Monorepo for Tangled

appview,xrpc: rewrite RepoUploadBlob to accept content types

uploading a blob without the content type results in a 403
ScopeMissingError, but indigo does not let us specify one! rewriting the
API to allow specifying the blob mime type is a temporary fix until
upstream allows this.

Signed-off-by: oppiliappan <me@oppi.li>

authored by

oppiliappan and committed by tangled.org c2049613 c983de83

+38 -14
+8 -5
appview/pulls/pulls.go
··· 39 "tangled.org/core/rbac" 40 "tangled.org/core/tid" 41 "tangled.org/core/types" 42 43 comatproto "github.com/bluesky-social/indigo/api/atproto" 44 "github.com/bluesky-social/indigo/atproto/syntax" ··· 47 "github.com/go-chi/chi/v5" 48 "github.com/google/uuid" 49 ) 50 51 type Pulls struct { 52 oauth *oauth.OAuth ··· 1227 return 1228 } 1229 1230 - blob, err := comatproto.RepoUploadBlob(r.Context(), client, gz(patch)) 1231 if err != nil { 1232 log.Println("failed to upload patch", err) 1233 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") ··· 1321 // apply all record creations at once 1322 var writes []*comatproto.RepoApplyWrites_Input_Writes_Elem 1323 for _, p := range stack { 1324 - blob, err := comatproto.RepoUploadBlob(r.Context(), client, gz(p.LatestPatch())) 1325 if err != nil { 1326 log.Println("failed to upload patch blob", err) 1327 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") ··· 1871 return 1872 } 1873 1874 - blob, err := comatproto.RepoUploadBlob(r.Context(), client, gz(patch)) 1875 if err != nil { 1876 log.Println("failed to upload patch blob", err) 1877 s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.") ··· 2014 return 2015 } 2016 2017 - blob, err := comatproto.RepoUploadBlob(r.Context(), client, gz(patch)) 2018 if err != nil { 2019 log.Println("failed to upload patch blob", err) 2020 s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.") ··· 2056 return 2057 } 2058 2059 - blob, err := comatproto.RepoUploadBlob(r.Context(), client, gz(patch)) 2060 if err != nil { 2061 log.Println("failed to upload patch blob", err) 2062 s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")
··· 39 "tangled.org/core/rbac" 40 "tangled.org/core/tid" 41 "tangled.org/core/types" 42 + "tangled.org/core/xrpc" 43 44 comatproto "github.com/bluesky-social/indigo/api/atproto" 45 "github.com/bluesky-social/indigo/atproto/syntax" ··· 48 "github.com/go-chi/chi/v5" 49 "github.com/google/uuid" 50 ) 51 + 52 + const ApplicationGzip = "application/gzip" 53 54 type Pulls struct { 55 oauth *oauth.OAuth ··· 1230 return 1231 } 1232 1233 + blob, err := xrpc.RepoUploadBlob(r.Context(), client, gz(patch), ApplicationGzip) 1234 if err != nil { 1235 log.Println("failed to upload patch", err) 1236 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") ··· 1324 // apply all record creations at once 1325 var writes []*comatproto.RepoApplyWrites_Input_Writes_Elem 1326 for _, p := range stack { 1327 + blob, err := xrpc.RepoUploadBlob(r.Context(), client, gz(p.LatestPatch()), ApplicationGzip) 1328 if err != nil { 1329 log.Println("failed to upload patch blob", err) 1330 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") ··· 1874 return 1875 } 1876 1877 + blob, err := xrpc.RepoUploadBlob(r.Context(), client, gz(patch), ApplicationGzip) 1878 if err != nil { 1879 log.Println("failed to upload patch blob", err) 1880 s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.") ··· 2017 return 2018 } 2019 2020 + blob, err := xrpc.RepoUploadBlob(r.Context(), client, gz(patch), ApplicationGzip) 2021 if err != nil { 2022 log.Println("failed to upload patch blob", err) 2023 s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.") ··· 2059 return 2060 } 2061 2062 + blob, err := xrpc.RepoUploadBlob(r.Context(), client, gz(patch), ApplicationGzip) 2063 if err != nil { 2064 log.Println("failed to upload patch blob", err) 2065 s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")
+5 -4
appview/repo/artifact.go
··· 18 "tangled.org/core/orm" 19 "tangled.org/core/tid" 20 "tangled.org/core/types" 21 22 comatproto "github.com/bluesky-social/indigo/api/atproto" 23 lexutil "github.com/bluesky-social/indigo/lex/util" ··· 46 return 47 } 48 49 - file, handler, err := r.FormFile("artifact") 50 if err != nil { 51 log.Println("failed to upload artifact", err) 52 rp.pages.Notice(w, "upload", "failed to upload artifact") ··· 61 return 62 } 63 64 - uploadBlobResp, err := comatproto.RepoUploadBlob(r.Context(), client, file) 65 if err != nil { 66 log.Println("failed to upload blob", err) 67 rp.pages.Notice(w, "upload", "Failed to upload blob to your PDS. Try again later.") ··· 81 Val: &tangled.RepoArtifact{ 82 Artifact: uploadBlobResp.Blob, 83 CreatedAt: createdAt.Format(time.RFC3339), 84 - Name: handler.Filename, 85 Repo: f.RepoAt().String(), 86 Tag: tag.Tag.Hash[:], 87 }, ··· 110 Tag: tag.Tag.Hash, 111 CreatedAt: createdAt, 112 BlobCid: cid.Cid(uploadBlobResp.Blob.Ref), 113 - Name: handler.Filename, 114 Size: uint64(uploadBlobResp.Blob.Size), 115 MimeType: uploadBlobResp.Blob.MimeType, 116 }
··· 18 "tangled.org/core/orm" 19 "tangled.org/core/tid" 20 "tangled.org/core/types" 21 + "tangled.org/core/xrpc" 22 23 comatproto "github.com/bluesky-social/indigo/api/atproto" 24 lexutil "github.com/bluesky-social/indigo/lex/util" ··· 47 return 48 } 49 50 + file, header, err := r.FormFile("artifact") 51 if err != nil { 52 log.Println("failed to upload artifact", err) 53 rp.pages.Notice(w, "upload", "failed to upload artifact") ··· 62 return 63 } 64 65 + uploadBlobResp, err := xrpc.RepoUploadBlob(r.Context(), client, file, header.Header.Get("Content-Type")) 66 if err != nil { 67 log.Println("failed to upload blob", err) 68 rp.pages.Notice(w, "upload", "Failed to upload blob to your PDS. Try again later.") ··· 82 Val: &tangled.RepoArtifact{ 83 Artifact: uploadBlobResp.Blob, 84 CreatedAt: createdAt.Format(time.RFC3339), 85 + Name: header.Filename, 86 Repo: f.RepoAt().String(), 87 Tag: tag.Tag.Hash[:], 88 }, ··· 111 Tag: tag.Tag.Hash, 112 CreatedAt: createdAt, 113 BlobCid: cid.Cid(uploadBlobResp.Blob.Ref), 114 + Name: header.Filename, 115 Size: uint64(uploadBlobResp.Blob.Size), 116 MimeType: uploadBlobResp.Blob.MimeType, 117 }
+6 -5
appview/state/profile.go
··· 20 "tangled.org/core/appview/models" 21 "tangled.org/core/appview/pages" 22 "tangled.org/core/orm" 23 ) 24 25 func (s *State) Profile(w http.ResponseWriter, r *http.Request) { ··· 741 return 742 } 743 744 - file, handler, err := r.FormFile("avatar") 745 if err != nil { 746 l.Error("failed to read avatar file", "err", err) 747 s.pages.Notice(w, "avatar-error", "Failed to read avatar file") ··· 749 } 750 defer file.Close() 751 752 - if handler.Size > 1000000 { 753 - l.Warn("avatar file too large", "size", handler.Size) 754 s.pages.Notice(w, "avatar-error", "Avatar file too large (max 1MB)") 755 return 756 } 757 758 - contentType := handler.Header.Get("Content-Type") 759 if contentType != "image/png" && contentType != "image/jpeg" { 760 l.Warn("invalid image type", "contentType", contentType) 761 s.pages.Notice(w, "avatar-error", "Invalid image type (only PNG and JPEG allowed)") ··· 769 return 770 } 771 772 - uploadBlobResp, err := comatproto.RepoUploadBlob(r.Context(), client, file) 773 if err != nil { 774 l.Error("failed to upload avatar blob", "err", err) 775 s.pages.Notice(w, "avatar-error", "Failed to upload avatar to your PDS")
··· 20 "tangled.org/core/appview/models" 21 "tangled.org/core/appview/pages" 22 "tangled.org/core/orm" 23 + "tangled.org/core/xrpc" 24 ) 25 26 func (s *State) Profile(w http.ResponseWriter, r *http.Request) { ··· 742 return 743 } 744 745 + file, header, err := r.FormFile("avatar") 746 if err != nil { 747 l.Error("failed to read avatar file", "err", err) 748 s.pages.Notice(w, "avatar-error", "Failed to read avatar file") ··· 750 } 751 defer file.Close() 752 753 + if header.Size > 1000000 { 754 + l.Warn("avatar file too large", "size", header.Size) 755 s.pages.Notice(w, "avatar-error", "Avatar file too large (max 1MB)") 756 return 757 } 758 759 + contentType := header.Header.Get("Content-Type") 760 if contentType != "image/png" && contentType != "image/jpeg" { 761 l.Warn("invalid image type", "contentType", contentType) 762 s.pages.Notice(w, "avatar-error", "Invalid image type (only PNG and JPEG allowed)") ··· 770 return 771 } 772 773 + uploadBlobResp, err := xrpc.RepoUploadBlob(r.Context(), client, file, header.Header.Get("Content-Type")) 774 if err != nil { 775 l.Error("failed to upload avatar blob", "err", err) 776 s.pages.Notice(w, "avatar-error", "Failed to upload avatar to your PDS")
+19
xrpc/blob.go
···
··· 1 + package xrpc 2 + 3 + import ( 4 + "context" 5 + "io" 6 + 7 + comatproto "github.com/bluesky-social/indigo/api/atproto" 8 + "github.com/bluesky-social/indigo/lex/util" 9 + ) 10 + 11 + // RepoUploadBlob calls the XRPC method "com.atproto.repo.uploadBlob". 12 + func RepoUploadBlob(ctx context.Context, c util.LexClient, input io.Reader, contentType string) (*comatproto.RepoUploadBlob_Output, error) { 13 + var out comatproto.RepoUploadBlob_Output 14 + if err := c.LexDo(ctx, util.Procedure, contentType, "com.atproto.repo.uploadBlob", nil, input, &out); err != nil { 15 + return nil, err 16 + } 17 + 18 + return &out, nil 19 + }