all repos — elgit @ fed19ae329323cca0f7b49624486966fbce8096b

fork of legit: web frontend for git, written in go

use gitweb/gitolite directory layout (including subdirs)

Alan Pearce
commit

fed19ae329323cca0f7b49624486966fbce8096b

parent

9c336ff148d48d09a4f4866798511cdcce50202a

1 file changed, 54 insertions(+), 119 deletions(-)

changed files
M routes/routes.goroutes/routes.go
@@ -5,15 +5,13 @@ "compress/gzip"
"fmt" "log" "net/http" - "os" + "path" "path/filepath" - "sort" "strconv" "strings" - "time" securejoin "github.com/cyphar/filepath-securejoin" - "github.com/dustin/go-humanize" + "github.com/dimfeld/httptreemux/v5" "github.com/microcosm-cc/bluemonday" "github.com/russross/blackfriday/v2" "go.alanpearce.eu/elgit/config"
@@ -22,95 +20,33 @@ "go.alanpearce.eu/elgit/templates"
) type deps struct { - c *config.Config + c *config.Config + projects []string } -func (d *deps) Index(w http.ResponseWriter, r *http.Request) { - dirs, err := os.ReadDir(d.c.Repo.ScanPath) - if err != nil { - d.Write500(w) - log.Printf("reading scan path: %s", err) - return - } - - type info struct { - DisplayName, Name, Desc, Idle string - d time.Time - } - - infos := []info{} - - for _, dir := range dirs { - name := dir.Name() - if !dir.IsDir() || d.isIgnored(name) || d.isUnlisted(name) { - continue - } - - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - gr, err := git.Open(path, "") - if err != nil { - log.Println(err) - continue - } - - c, err := gr.LastCommit() - if err != nil { - d.Write500(w) - log.Println(err) - return - } - - infos = append(infos, info{ - DisplayName: getDisplayName(name), - Name: name, - Desc: getDescription(path), - Idle: humanize.Time(c.Author.When), - d: c.Author.When, - }) - } - - sort.Slice(infos, func(i, j int) bool { - return infos[j].d.Before(infos[i].d) - }) - - // Convert to the format expected by the templates package - repoInfos := make([]templates.RepoInfo, len(infos)) - for i, info := range infos { - repoInfos[i] = templates.RepoInfo{ - DisplayName: info.DisplayName, - Name: info.Name, - Desc: info.Desc, - Idle: info.Idle, - LastCommit: info.d, - } - } +func (d *deps) Index(w http.ResponseWriter, r *http.Request, params map[string]string) { + repos := d.getAllRepos() pageData := templates.PageData{ Meta: d.c.Meta, } - if err := templates.Index(pageData, repoInfos).Render(w); err != nil { + if err := templates.Index(pageData, repos).Render(w); err != nil { log.Println(err) return } } -func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { +func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request, params map[string]string) { + name := path.Join(params["category"], params["name"]) + + if d.isNotAllowed(name) { d.Write404(w) return } - name = filepath.Clean(name) - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) + path, err := d.GetCleanPath(name) if err != nil { - log.Printf("securejoin error: %v", err) + log.Printf("getcleanpath error: %v", err) d.Write404(w) return }
@@ -179,19 +115,18 @@ log.Println(err)
} } -func (d *deps) RepoTree(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { +func (d *deps) RepoTree(w http.ResponseWriter, r *http.Request, params map[string]string) { + name := path.Join(params["category"], params["name"]) + if d.isNotAllowed(name) { d.Write404(w) return } - treePath := r.PathValue("rest") - ref := r.PathValue("ref") + treePath := strings.TrimSuffix(params["rest"], "/") + ref := params["ref"] - name = filepath.Clean(name) - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) + path, err := d.GetCleanPath(name) if err != nil { - log.Printf("securejoin error: %v", err) + log.Printf("getcleanpath error: %v", err) d.Write404(w) return }
@@ -219,24 +154,24 @@
d.listFiles(files, data, w) } -func (d *deps) FileContent(w http.ResponseWriter, r *http.Request) { +func (d *deps) FileContent(w http.ResponseWriter, r *http.Request, params map[string]string) { var raw bool if rawParam, err := strconv.ParseBool(r.URL.Query().Get("raw")); err == nil { raw = rawParam } - name := r.PathValue("name") - if d.isIgnored(name) { + name := path.Join(params["category"], params["name"]) + if d.isNotAllowed(name) { d.Write404(w) return } - treePath := r.PathValue("rest") - ref := r.PathValue("ref") + treePath := params["rest"] + ref := params["ref"] - name = filepath.Clean(name) - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) + name = httptreemux.Clean(name) + path, err := d.GetCleanPath(name) if err != nil { - log.Printf("securejoin error: %v", err) + log.Printf("getcleanpath error: %v", err) d.Write404(w) return }
@@ -270,14 +205,14 @@ }
} } -func (d *deps) Archive(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { +func (d *deps) Archive(w http.ResponseWriter, r *http.Request, params map[string]string) { + name := path.Join(params["category"], params["name"]) + if d.isNotAllowed(name) { d.Write404(w) return } - file := r.PathValue("file") + file := params["file"] // TODO: extend this to add more files compression (e.g.: xz) if !strings.HasSuffix(file, ".tar.gz") {
@@ -293,9 +228,9 @@ filename := fmt.Sprintf("%s-%s.tar.gz", name, ref)
setContentDisposition(w, filename) setGZipMIME(w) - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) + path, err := d.GetCleanPath(name) if err != nil { - log.Printf("securejoin error: %v", err) + log.Printf("getcleanpath error: %v", err) d.Write404(w) return }
@@ -327,17 +262,17 @@ return
} } -func (d *deps) Log(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { +func (d *deps) Log(w http.ResponseWriter, r *http.Request, params map[string]string) { + name := path.Join(params["category"], params["name"]) + if d.isNotAllowed(name) { d.Write404(w) return } - ref := r.PathValue("ref") + ref := params["ref"] - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) + path, err := d.GetCleanPath(name) if err != nil { - log.Printf("securejoin error: %v", err) + log.Printf("getcleanpath error: %v", err) d.Write404(w) return }
@@ -370,17 +305,17 @@ return
} } -func (d *deps) Diff(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { +func (d *deps) Diff(w http.ResponseWriter, r *http.Request, params map[string]string) { + name := path.Join(params["category"], params["name"]) + if d.isNotAllowed(name) { d.Write404(w) return } - ref := r.PathValue("ref") + ref := params["ref"] - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) + path, err := d.GetCleanPath(name) if err != nil { - log.Printf("securejoin error: %v", err) + log.Printf("getcleanpath error: %v", err) d.Write404(w) return }
@@ -413,16 +348,16 @@ return
} } -func (d *deps) Refs(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { +func (d *deps) Refs(w http.ResponseWriter, r *http.Request, params map[string]string) { + name := path.Join(params["category"], params["name"]) + if d.isNotAllowed(name) { d.Write404(w) return } - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) + path, err := d.GetCleanPath(name) if err != nil { - log.Printf("securejoin error: %v", err) + log.Printf("getcleanpath error: %v", err) d.Write404(w) return }
@@ -459,9 +394,9 @@ return
} } -func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) { - f := r.PathValue("file") - f = filepath.Clean(f) +func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request, params map[string]string) { + f := params["file"] + f = httptreemux.Clean(f) f, err := securejoin.SecureJoin(d.c.Dirs.Static, f) if err != nil { d.Write404(w)