A vibe coded tangled fork which supports pijul.
at 1237bf9f58e4ba5d13d5437f2f82a2078572e229 86 lines 2.5 kB view raw
1package xrpc 2 3import ( 4 "context" 5 "fmt" 6 "io" 7 "net/http" 8 "slices" 9 10 "github.com/bluesky-social/indigo/atproto/atclient" 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 "github.com/go-git/go-git/v5/plumbing/object" 13 "tangled.org/core/knotserver/git" 14) 15 16func (x *Xrpc) GetBlob(w http.ResponseWriter, r *http.Request) { 17 var ( 18 repoQuery = r.URL.Query().Get("repo") 19 ref = r.URL.Query().Get("ref") // ref can be empty (git.Open handles this) 20 path = r.URL.Query().Get("path") 21 ) 22 23 repo, err := syntax.ParseATURI(repoQuery) 24 if err != nil || repo.RecordKey() == "" { 25 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) 26 return 27 } 28 29 l := x.logger.With("repo", repo, "ref", ref, "path", path) 30 31 if path == "" { 32 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: "missing path parameter"}) 33 return 34 } 35 36 file, err := x.getFile(r.Context(), repo, ref, path) 37 if err != nil { 38 // TODO: better error return 39 l.Error("failed to get blob", "err", err) 40 writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to get blob"}) 41 return 42 } 43 44 reader, err := file.Reader() 45 if err != nil { 46 l.Error("failed to read blob", "err", err) 47 writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to read the blob"}) 48 return 49 } 50 defer reader.Close() 51 52 w.Header().Set("Content-Type", "application/octet-stream") 53 if _, err := io.Copy(w, reader); err != nil { 54 l.Error("failed to serve the blob", "err", err) 55 } 56} 57 58func (x *Xrpc) getFile(ctx context.Context, repo syntax.ATURI, ref, path string) (*object.File, error) { 59 repoPath, err := x.makeRepoPath(ctx, repo) 60 if err != nil { 61 return nil, fmt.Errorf("resolving repo at-uri: %w", err) 62 } 63 64 gr, err := git.Open(repoPath, ref) 65 if err != nil { 66 return nil, fmt.Errorf("opening git repo: %w", err) 67 } 68 69 return gr.File(path) 70} 71 72var textualMimeTypes = []string{ 73 "application/json", 74 "application/xml", 75 "application/yaml", 76 "application/x-yaml", 77 "application/toml", 78 "application/javascript", 79 "application/ecmascript", 80} 81 82// isTextualMimeType returns true if the MIME type represents textual content 83// that should be served as text/plain for security reasons 84func isTextualMimeType(mimeType string) bool { 85 return slices.Contains(textualMimeTypes, mimeType) 86}