this repo has no description

poc: repo index request

Akshay f61b8874 5cec4e53

Changed files
+113 -14
appview
knotserver
+45
appview/state/middleware.go
··· 1 1 package state 2 2 3 3 import ( 4 + "context" 4 5 "log" 5 6 "net/http" 6 7 "strings" 7 8 "time" 8 9 9 10 comatproto "github.com/bluesky-social/indigo/api/atproto" 11 + "github.com/bluesky-social/indigo/atproto/identity" 10 12 "github.com/bluesky-social/indigo/xrpc" 11 13 "github.com/go-chi/chi/v5" 12 14 "github.com/sotangled/tangled/appview" ··· 110 112 next.ServeHTTP(w, req) 111 113 }) 112 114 } 115 + 116 + func ResolveIdent(next http.Handler) http.Handler { 117 + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 118 + didOrHandle := chi.URLParam(req, "user") 119 + 120 + log.Println(didOrHandle) 121 + id, err := auth.ResolveIdent(req.Context(), didOrHandle) 122 + if err != nil { 123 + // invalid did or handle 124 + log.Println("failed to resolve did/handle") 125 + w.WriteHeader(http.StatusNotFound) 126 + return 127 + } 128 + 129 + ctx := context.WithValue(req.Context(), "resolvedId", *id) 130 + next.ServeHTTP(w, req.WithContext(ctx)) 131 + }) 132 + } 133 + 134 + func ResolveRepoDomain(s *State) Middleware { 135 + return func(next http.Handler) http.Handler { 136 + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 137 + repoName := chi.URLParam(req, "repo") 138 + id, ok := req.Context().Value("resolvedId").(identity.Identity) 139 + if !ok { 140 + log.Println("malformed middleware") 141 + w.WriteHeader(http.StatusInternalServerError) 142 + return 143 + } 144 + 145 + repo, err := s.db.GetRepo(id.DID.String(), repoName) 146 + if err != nil { 147 + // invalid did or handle 148 + log.Println("failed to resolve repo") 149 + w.WriteHeader(http.StatusNotFound) 150 + return 151 + } 152 + 153 + ctx := context.WithValue(req.Context(), "domain", repo.Knot) 154 + next.ServeHTTP(w, req.WithContext(ctx)) 155 + }) 156 + } 157 + }
+41
appview/state/repo.go
··· 1 + package state 2 + 3 + import ( 4 + "fmt" 5 + "io" 6 + "log" 7 + "net/http" 8 + 9 + "github.com/bluesky-social/indigo/atproto/identity" 10 + "github.com/go-chi/chi/v5" 11 + ) 12 + 13 + func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) { 14 + ctx := r.Context() 15 + repoName := chi.URLParam(r, "repo") 16 + 17 + domain, ok := ctx.Value("domain").(string) 18 + if !ok { 19 + log.Println("malformed middleware") 20 + w.WriteHeader(http.StatusInternalServerError) 21 + return 22 + } 23 + 24 + id, ok := ctx.Value("resolvedId").(identity.Identity) 25 + if !ok { 26 + log.Println("malformed middleware") 27 + w.WriteHeader(http.StatusInternalServerError) 28 + return 29 + } 30 + 31 + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s", domain, id.DID.String(), repoName)) 32 + if err != nil { 33 + log.Println("failed to reach knotserver", err) 34 + return 35 + } 36 + 37 + txt, err := io.ReadAll(resp.Body) 38 + log.Println(resp.Status, string(txt)) 39 + 40 + return 41 + }
+18 -6
appview/state/signer.go
··· 59 59 return http.NewRequest(method, s.Url.JoinPath(endpoint).String(), bytes.NewReader(body)) 60 60 } 61 61 62 - func (s *SignedClient) Init(did string, keys []string) (*http.Response, error) { 62 + func (s *SignedClient) Init(did string) (*http.Response, error) { 63 63 const ( 64 64 Method = "POST" 65 65 Endpoint = "/init" 66 66 ) 67 67 68 68 body, _ := json.Marshal(map[string]interface{}{ 69 - "did": did, 70 - "keys": keys, 69 + "did": did, 71 70 }) 72 71 73 72 req, err := s.newRequest(Method, Endpoint, body) ··· 97 96 return s.client.Do(req) 98 97 } 99 98 100 - func (s *SignedClient) AddMember(did string, keys []string) (*http.Response, error) { 99 + func (s *SignedClient) AddMember(did string) (*http.Response, error) { 101 100 const ( 102 101 Method = "PUT" 103 102 Endpoint = "/member/add" 104 103 ) 105 104 106 105 body, _ := json.Marshal(map[string]interface{}{ 107 - "did": did, 108 - "keys": keys, 106 + "did": did, 109 107 }) 110 108 111 109 req, err := s.newRequest(Method, Endpoint, body) ··· 115 113 116 114 return s.client.Do(req) 117 115 } 116 + 117 + func (s *SignedClient) RepoIndex(did, repo string) (*http.Response, error) { 118 + const ( 119 + Method = "GET" 120 + ) 121 + endpoint := fmt.Sprint("/%s/%s", did, repo) 122 + 123 + req, err := s.newRequest(Method, endpoint, nil) 124 + if err != nil { 125 + return nil, err 126 + } 127 + 128 + return s.client.Do(req) 129 + }
+9 -4
appview/state/state.go
··· 201 201 case http.MethodPut: 202 202 did := s.auth.GetDid(r) 203 203 key := r.FormValue("key") 204 + key = strings.TrimSpace(key) 204 205 name := r.FormValue("name") 205 206 client, _ := s.auth.AuthorizedClient(r) 206 207 ··· 261 262 log.Println("failed to create client to ", domain) 262 263 } 263 264 264 - resp, err := client.Init(user.Did, []string{}) 265 + resp, err := client.Init(user.Did) 265 266 if err != nil { 266 267 w.Write([]byte("no dice")) 267 268 log.Println("domain was unreachable after 5 seconds") ··· 455 456 return 456 457 } 457 458 458 - ksResp, err := ksClient.AddMember(memberIdent.DID.String(), []string{}) 459 + ksResp, err := ksClient.AddMember(memberIdent.DID.String()) 459 460 if err != nil { 460 - log.Printf("failet to make request to %s: %s", domain, err) 461 + log.Printf("failed to make request to %s: %s", domain, err) 461 462 } 462 463 463 464 if ksResp.StatusCode != http.StatusNoContent { ··· 596 597 // strip @ from user 597 598 r.Use(StripLeadingAt) 598 599 599 - r.Route("/{user}", func(r chi.Router) { 600 + r.With(ResolveIdent).Route("/{user}", func(r chi.Router) { 600 601 r.Get("/", s.ProfilePage) 602 + r.With(ResolveRepoDomain(s)).Route("/{repo}", func(r chi.Router) { 603 + r.Get("/", s.RepoIndex) 604 + // r.Get("/info/refs", s.InfoRefs) 605 + }) 601 606 }) 602 607 603 608 return r
-4
knotserver/jetstream.go
··· 182 182 return nil 183 183 } 184 184 185 - if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(ct, "text/plain") { 186 - return fmt.Errorf("unexpected content type: %s", ct) 187 - } 188 - 189 185 plaintext, err := io.ReadAll(resp.Body) 190 186 if err != nil { 191 187 l.Error("error reading response body", "error", err)