this repo has no description
1package knotserver 2 3import ( 4 "compress/gzip" 5 "fmt" 6 "io" 7 "net/http" 8 "path/filepath" 9 "strings" 10 11 securejoin "github.com/cyphar/filepath-securejoin" 12 "github.com/go-chi/chi/v5" 13 "tangled.sh/tangled.sh/core/knotserver/git/service" 14) 15 16func (d *Handle) InfoRefs(w http.ResponseWriter, r *http.Request) { 17 did := chi.URLParam(r, "did") 18 name := chi.URLParam(r, "name") 19 repoName, err := securejoin.SecureJoin(did, name) 20 if err != nil { 21 gitError(w, "repository not found", http.StatusNotFound) 22 d.l.Error("git: failed to secure join repo path", "handler", "InfoRefs", "error", err) 23 return 24 } 25 26 repoPath, err := securejoin.SecureJoin(d.c.Repo.ScanPath, repoName) 27 if err != nil { 28 gitError(w, "repository not found", http.StatusNotFound) 29 d.l.Error("git: failed to secure join repo path", "handler", "InfoRefs", "error", err) 30 return 31 } 32 33 cmd := service.ServiceCommand{ 34 GitProtocol: r.Header.Get("Git-Protocol"), 35 Dir: repoPath, 36 Stdout: w, 37 } 38 39 serviceName := r.URL.Query().Get("service") 40 switch serviceName { 41 case "git-upload-pack": 42 w.Header().Set("content-type", "application/x-git-upload-pack-advertisement") 43 w.WriteHeader(http.StatusOK) 44 45 if err := cmd.InfoRefs(); err != nil { 46 gitError(w, err.Error(), http.StatusInternalServerError) 47 d.l.Error("git: process failed", "handler", "InfoRefs", "service", serviceName, "error", err) 48 return 49 } 50 case "git-receive-pack": 51 d.RejectPush(w, r, name) 52 default: 53 gitError(w, fmt.Sprintf("service unsupported: '%s'", serviceName), http.StatusForbidden) 54 } 55} 56 57func (d *Handle) UploadPack(w http.ResponseWriter, r *http.Request) { 58 did := chi.URLParam(r, "did") 59 name := chi.URLParam(r, "name") 60 repo, err := securejoin.SecureJoin(d.c.Repo.ScanPath, filepath.Join(did, name)) 61 if err != nil { 62 writeError(w, err.Error(), 500) 63 d.l.Error("git: failed to secure join repo path", "handler", "UploadPack", "error", err) 64 return 65 } 66 67 var bodyReader io.ReadCloser = r.Body 68 if r.Header.Get("Content-Encoding") == "gzip" { 69 gzipReader, err := gzip.NewReader(r.Body) 70 if err != nil { 71 writeError(w, err.Error(), 500) 72 d.l.Error("git: failed to create gzip reader", "handler", "UploadPack", "error", err) 73 return 74 } 75 defer gzipReader.Close() 76 bodyReader = gzipReader 77 } 78 79 w.Header().Set("Content-Type", "application/x-git-upload-pack-result") 80 w.Header().Set("Connection", "Keep-Alive") 81 82 d.l.Info("git: executing git-upload-pack", "handler", "UploadPack", "repo", repo) 83 84 cmd := service.ServiceCommand{ 85 GitProtocol: r.Header.Get("Git-Protocol"), 86 Dir: repo, 87 Stdout: w, 88 Stdin: bodyReader, 89 } 90 91 w.WriteHeader(http.StatusOK) 92 93 if err := cmd.UploadPack(); err != nil { 94 d.l.Error("git: failed to execute git-upload-pack", "handler", "UploadPack", "error", err) 95 return 96 } 97} 98 99func (d *Handle) ReceivePack(w http.ResponseWriter, r *http.Request) { 100 did := chi.URLParam(r, "did") 101 name := chi.URLParam(r, "name") 102 _, err := securejoin.SecureJoin(d.c.Repo.ScanPath, filepath.Join(did, name)) 103 if err != nil { 104 gitError(w, err.Error(), http.StatusForbidden) 105 d.l.Error("git: failed to secure join repo path", "handler", "ReceivePack", "error", err) 106 return 107 } 108 109 d.RejectPush(w, r, name) 110} 111 112func (d *Handle) RejectPush(w http.ResponseWriter, r *http.Request, unqualifiedRepoName string) { 113 // A text/plain response will cause git to print each line of the body 114 // prefixed with "remote: ". 115 w.Header().Set("content-type", "text/plain; charset=UTF-8") 116 w.WriteHeader(http.StatusForbidden) 117 118 fmt.Fprintf(w, "Pushes are only supported over SSH.") 119 120 // If the appview gave us the repository owner's handle we can attempt to 121 // construct the correct ssh url. 122 ownerHandle := r.Header.Get("x-tangled-repo-owner-handle") 123 if ownerHandle != "" && !strings.ContainsAny(ownerHandle, ":") { 124 hostname := d.c.Server.Hostname 125 if strings.Contains(hostname, ":") { 126 hostname = strings.Split(hostname, ":")[0] 127 } 128 129 fmt.Fprintf(w, " Try:\ngit remote set-url --push origin git@%s:%s/%s\n\n... and push again.", hostname, ownerHandle, unqualifiedRepoName) 130 } 131 fmt.Fprintf(w, "\n\n") 132} 133 134func gitError(w http.ResponseWriter, msg string, status int) { 135 w.Header().Set("content-type", "text/plain; charset=UTF-8") 136 w.WriteHeader(status) 137 fmt.Fprintf(w, "%s\n", msg) 138}