From cf966f1481be37ec91aae5c18fc4beb6fc6e0736 Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 5 Feb 2025 18:27:04 +0000 Subject: [PATCH] poc: repo index request --- appview/state/middleware.go | 45 +++++++++++++++++++++++++++++++++++++ appview/state/repo.go | 41 +++++++++++++++++++++++++++++++++ appview/state/signer.go | 24 +++++++++++++++----- appview/state/state.go | 13 +++++++---- knotserver/jetstream.go | 4 ---- 5 files changed, 113 insertions(+), 14 deletions(-) create mode 100644 appview/state/repo.go diff --git a/appview/state/middleware.go b/appview/state/middleware.go index b0e71315..ad275a41 100644 --- a/appview/state/middleware.go +++ b/appview/state/middleware.go @@ -1,12 +1,14 @@ package state import ( + "context" "log" "net/http" "strings" "time" comatproto "github.com/bluesky-social/indigo/api/atproto" + "github.com/bluesky-social/indigo/atproto/identity" "github.com/bluesky-social/indigo/xrpc" "github.com/go-chi/chi/v5" "github.com/sotangled/tangled/appview" @@ -110,3 +112,46 @@ func StripLeadingAt(next http.Handler) http.Handler { next.ServeHTTP(w, req) }) } + +func ResolveIdent(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + didOrHandle := chi.URLParam(req, "user") + + log.Println(didOrHandle) + id, err := auth.ResolveIdent(req.Context(), didOrHandle) + if err != nil { + // invalid did or handle + log.Println("failed to resolve did/handle") + w.WriteHeader(http.StatusNotFound) + return + } + + ctx := context.WithValue(req.Context(), "resolvedId", *id) + next.ServeHTTP(w, req.WithContext(ctx)) + }) +} + +func ResolveRepoDomain(s *State) Middleware { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + repoName := chi.URLParam(req, "repo") + id, ok := req.Context().Value("resolvedId").(identity.Identity) + if !ok { + log.Println("malformed middleware") + w.WriteHeader(http.StatusInternalServerError) + return + } + + repo, err := s.db.GetRepo(id.DID.String(), repoName) + if err != nil { + // invalid did or handle + log.Println("failed to resolve repo") + w.WriteHeader(http.StatusNotFound) + return + } + + ctx := context.WithValue(req.Context(), "domain", repo.Knot) + next.ServeHTTP(w, req.WithContext(ctx)) + }) + } +} diff --git a/appview/state/repo.go b/appview/state/repo.go new file mode 100644 index 00000000..3ad7de6b --- /dev/null +++ b/appview/state/repo.go @@ -0,0 +1,41 @@ +package state + +import ( + "fmt" + "io" + "log" + "net/http" + + "github.com/bluesky-social/indigo/atproto/identity" + "github.com/go-chi/chi/v5" +) + +func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + repoName := chi.URLParam(r, "repo") + + domain, ok := ctx.Value("domain").(string) + if !ok { + log.Println("malformed middleware") + w.WriteHeader(http.StatusInternalServerError) + return + } + + id, ok := ctx.Value("resolvedId").(identity.Identity) + if !ok { + log.Println("malformed middleware") + w.WriteHeader(http.StatusInternalServerError) + return + } + + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s", domain, id.DID.String(), repoName)) + if err != nil { + log.Println("failed to reach knotserver", err) + return + } + + txt, err := io.ReadAll(resp.Body) + log.Println(resp.Status, string(txt)) + + return +} diff --git a/appview/state/signer.go b/appview/state/signer.go index dc629fc3..ed106c41 100644 --- a/appview/state/signer.go +++ b/appview/state/signer.go @@ -59,15 +59,14 @@ func (s *SignedClient) newRequest(method, endpoint string, body []byte) (*http.R return http.NewRequest(method, s.Url.JoinPath(endpoint).String(), bytes.NewReader(body)) } -func (s *SignedClient) Init(did string, keys []string) (*http.Response, error) { +func (s *SignedClient) Init(did string) (*http.Response, error) { const ( Method = "POST" Endpoint = "/init" ) body, _ := json.Marshal(map[string]interface{}{ - "did": did, - "keys": keys, + "did": did, }) req, err := s.newRequest(Method, Endpoint, body) @@ -97,15 +96,14 @@ func (s *SignedClient) NewRepo(did, repoName string) (*http.Response, error) { return s.client.Do(req) } -func (s *SignedClient) AddMember(did string, keys []string) (*http.Response, error) { +func (s *SignedClient) AddMember(did string) (*http.Response, error) { const ( Method = "PUT" Endpoint = "/member/add" ) body, _ := json.Marshal(map[string]interface{}{ - "did": did, - "keys": keys, + "did": did, }) req, err := s.newRequest(Method, Endpoint, body) @@ -115,3 +113,17 @@ func (s *SignedClient) AddMember(did string, keys []string) (*http.Response, err return s.client.Do(req) } + +func (s *SignedClient) RepoIndex(did, repo string) (*http.Response, error) { + const ( + Method = "GET" + ) + endpoint := fmt.Sprint("/%s/%s", did, repo) + + req, err := s.newRequest(Method, endpoint, nil) + if err != nil { + return nil, err + } + + return s.client.Do(req) +} diff --git a/appview/state/state.go b/appview/state/state.go index 40f3487a..21b3f1cf 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -201,6 +201,7 @@ func (s *State) SettingsKeys(w http.ResponseWriter, r *http.Request) { case http.MethodPut: did := s.auth.GetDid(r) key := r.FormValue("key") + key = strings.TrimSpace(key) name := r.FormValue("name") client, _ := s.auth.AuthorizedClient(r) @@ -261,7 +262,7 @@ func (s *State) InitKnotServer(w http.ResponseWriter, r *http.Request) { log.Println("failed to create client to ", domain) } - resp, err := client.Init(user.Did, []string{}) + resp, err := client.Init(user.Did) if err != nil { w.Write([]byte("no dice")) log.Println("domain was unreachable after 5 seconds") @@ -455,9 +456,9 @@ func (s *State) AddMember(w http.ResponseWriter, r *http.Request) { return } - ksResp, err := ksClient.AddMember(memberIdent.DID.String(), []string{}) + ksResp, err := ksClient.AddMember(memberIdent.DID.String()) if err != nil { - log.Printf("failet to make request to %s: %s", domain, err) + log.Printf("failed to make request to %s: %s", domain, err) } if ksResp.StatusCode != http.StatusNoContent { @@ -596,8 +597,12 @@ func (s *State) UserRouter() http.Handler { // strip @ from user r.Use(StripLeadingAt) - r.Route("/{user}", func(r chi.Router) { + r.With(ResolveIdent).Route("/{user}", func(r chi.Router) { r.Get("/", s.ProfilePage) + r.With(ResolveRepoDomain(s)).Route("/{repo}", func(r chi.Router) { + r.Get("/", s.RepoIndex) + // r.Get("/info/refs", s.InfoRefs) + }) }) return r diff --git a/knotserver/jetstream.go b/knotserver/jetstream.go index 4cd2f5ca..112b3695 100644 --- a/knotserver/jetstream.go +++ b/knotserver/jetstream.go @@ -182,10 +182,6 @@ func (h *Handle) fetchAndAddKeys(ctx context.Context, did string) error { return nil } - if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(ct, "text/plain") { - return fmt.Errorf("unexpected content type: %s", ct) - } - plaintext, err := io.ReadAll(resp.Body) if err != nil { l.Error("error reading response body", "error", err) -- 2.51.2