forked from tangled.org/core
this repo has no description

knotserver: reject 'git-receive-pack' service in info/refs

* Checks service name query parameter in info/refs handler; rejects any
service request that doesn't match 'git-upload-pack'.

* Produces 'text/plain' error responses so the git client will display
them.

* Adds a specific reject message for 'git-receive-pack'. This will
produce a less cryptic error in the terminal when trying to push over
http.

authored by tjh.dev and committed by Tangled ca454e92 f884856c

Changed files
+45 -8
knotserver
+45 -8
knotserver/git.go
··· 2 2 3 3 import ( 4 4 "compress/gzip" 5 + "fmt" 5 6 "io" 6 7 "net/http" 7 8 "path/filepath" ··· 14 15 func (d *Handle) InfoRefs(w http.ResponseWriter, r *http.Request) { 15 16 did := chi.URLParam(r, "did") 16 17 name := chi.URLParam(r, "name") 17 - repo, _ := securejoin.SecureJoin(d.c.Repo.ScanPath, filepath.Join(did, name)) 18 + repoName, err := securejoin.SecureJoin(did, name) 19 + if err != nil { 20 + gitError(w, "repository not found", http.StatusNotFound) 21 + d.l.Error("git: failed to secure join repo path", "handler", "InfoRefs", "error", err) 22 + return 23 + } 18 24 19 - w.Header().Set("content-type", "application/x-git-upload-pack-advertisement") 20 - w.WriteHeader(http.StatusOK) 25 + repoPath, err := securejoin.SecureJoin(d.c.Repo.ScanPath, repoName) 26 + if err != nil { 27 + gitError(w, "repository not found", http.StatusNotFound) 28 + d.l.Error("git: failed to secure join repo path", "handler", "InfoRefs", "error", err) 29 + return 30 + } 21 31 22 32 cmd := service.ServiceCommand{ 23 - Dir: repo, 33 + Dir: repoPath, 24 34 Stdout: w, 25 35 } 26 36 27 - if err := cmd.InfoRefs(); err != nil { 28 - writeError(w, err.Error(), 500) 29 - d.l.Error("git: failed to execute git-upload-pack (info/refs)", "handler", "InfoRefs", "error", err) 30 - return 37 + serviceName := r.URL.Query().Get("service") 38 + switch serviceName { 39 + case "git-upload-pack": 40 + w.Header().Set("content-type", "application/x-git-upload-pack-advertisement") 41 + w.WriteHeader(http.StatusOK) 42 + 43 + if err := cmd.InfoRefs(); err != nil { 44 + gitError(w, err.Error(), http.StatusInternalServerError) 45 + d.l.Error("git: process failed", "handler", "InfoRefs", "service", serviceName, "error", err) 46 + return 47 + } 48 + case "git-receive-pack": 49 + d.RejectPush(w, r, name) 50 + default: 51 + gitError(w, fmt.Sprintf("service unsupported: '%s'", serviceName), http.StatusForbidden) 31 52 } 32 53 } 33 54 ··· 71 92 return 72 93 } 73 94 } 95 + 96 + func (d *Handle) RejectPush(w http.ResponseWriter, r *http.Request, unqualifiedRepoName string) { 97 + // A text/plain response will cause git to print each line of the body 98 + // prefixed with "remote: ". 99 + w.Header().Set("content-type", "text/plain; charset=UTF-8") 100 + w.WriteHeader(http.StatusForbidden) 101 + 102 + fmt.Fprintf(w, "Welcome to Tangled.sh!\n\nPushes are currently only supported over SSH.") 103 + fmt.Fprintf(w, "\n\n") 104 + } 105 + 106 + func gitError(w http.ResponseWriter, msg string, status int) { 107 + w.Header().Set("content-type", "text/plain; charset=UTF-8") 108 + w.WriteHeader(status) 109 + fmt.Fprintf(w, "%s\n", msg) 110 + }