Monorepo for Tangled tangled.org

appview: relax auth requirement on artifact download

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

oppi.li b1aab088 084f70e8

verified
Changed files
+42 -17
appview
+40 -14
appview/repo/artifact.go
··· 4 4 "context" 5 5 "encoding/json" 6 6 "fmt" 7 + "io" 7 8 "log" 8 9 "net/http" 9 10 "net/url" ··· 133 134 }) 134 135 } 135 136 136 - // TODO: proper statuses here on early exit 137 137 func (rp *Repo) DownloadArtifact(w http.ResponseWriter, r *http.Request) { 138 - tagParam := chi.URLParam(r, "tag") 139 - filename := chi.URLParam(r, "file") 140 138 f, err := rp.repoResolver.Resolve(r) 141 139 if err != nil { 142 140 log.Println("failed to get repo and knot", err) 141 + http.Error(w, "failed to resolve repo", http.StatusInternalServerError) 143 142 return 144 143 } 144 + 145 + tagParam := chi.URLParam(r, "tag") 146 + filename := chi.URLParam(r, "file") 145 147 146 148 tag, err := rp.resolveTag(r.Context(), f, tagParam) 147 149 if err != nil { ··· 150 152 return 151 153 } 152 154 153 - client, err := rp.oauth.AuthorizedClient(r) 154 - if err != nil { 155 - log.Println("failed to get authorized client", err) 156 - return 157 - } 158 - 159 155 artifacts, err := db.GetArtifact( 160 156 rp.db, 161 157 db.FilterEq("repo_at", f.RepoAt()), ··· 164 160 ) 165 161 if err != nil { 166 162 log.Println("failed to get artifacts", err) 163 + http.Error(w, "failed to get artifact", http.StatusInternalServerError) 167 164 return 168 165 } 166 + 169 167 if len(artifacts) != 1 { 170 - log.Printf("too many or too little artifacts found") 168 + log.Printf("too many or too few artifacts found") 169 + http.Error(w, "artifact not found", http.StatusNotFound) 171 170 return 172 171 } 173 172 174 173 artifact := artifacts[0] 175 174 176 - getBlobResp, err := client.SyncGetBlob(r.Context(), artifact.BlobCid.String(), artifact.Did) 175 + ownerPds := f.OwnerId.PDSEndpoint() 176 + url, _ := url.Parse(fmt.Sprintf("%s/xrpc/com.atproto.sync.getBlob", ownerPds)) 177 + q := url.Query() 178 + q.Set("cid", artifact.BlobCid.String()) 179 + q.Set("did", artifact.Did) 180 + url.RawQuery = q.Encode() 181 + 182 + req, err := http.NewRequest(http.MethodGet, url.String(), nil) 183 + if err != nil { 184 + log.Println("failed to create request", err) 185 + http.Error(w, "failed to create request", http.StatusInternalServerError) 186 + return 187 + } 188 + req.Header.Set("Content-Type", "application/json") 189 + 190 + resp, err := http.DefaultClient.Do(req) 177 191 if err != nil { 178 - log.Println("failed to get blob from pds", err) 192 + log.Println("failed to make request", err) 193 + http.Error(w, "failed to make request to PDS", http.StatusInternalServerError) 179 194 return 180 195 } 196 + defer resp.Body.Close() 181 197 182 - w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", filename)) 183 - w.Write(getBlobResp) 198 + // copy status code and relevant headers from upstream response 199 + w.WriteHeader(resp.StatusCode) 200 + for key, values := range resp.Header { 201 + for _, v := range values { 202 + w.Header().Add(key, v) 203 + } 204 + } 205 + 206 + // stream the body directly to the client 207 + if _, err := io.Copy(w, resp.Body); err != nil { 208 + log.Println("error streaming response to client:", err) 209 + } 184 210 } 185 211 186 212 // TODO: proper statuses here on early exit
+2 -3
appview/repo/router.go
··· 21 21 r.Route("/tags", func(r chi.Router) { 22 22 r.Get("/", rp.RepoTags) 23 23 r.Route("/{tag}", func(r chi.Router) { 24 - r.Use(middleware.AuthMiddleware(rp.oauth)) 25 - // require auth to download for now 26 24 r.Get("/download/{file}", rp.DownloadArtifact) 27 25 28 26 // require repo:push to upload or delete artifacts ··· 30 28 // additionally: only the uploader can truly delete an artifact 31 29 // (record+blob will live on their pds) 32 30 r.Group(func(r chi.Router) { 33 - r.With(mw.RepoPermissionMiddleware("repo:push")) 31 + r.Use(middleware.AuthMiddleware(rp.oauth)) 32 + r.Use(mw.RepoPermissionMiddleware("repo:push")) 34 33 r.Post("/upload", rp.AttachArtifact) 35 34 r.Delete("/{file}", rp.DeleteArtifact) 36 35 })