A vibe coded tangled fork which supports pijul.
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}