From 9b88f828d2069244e654222b64ca315adc66f9c6 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Fri, 22 Aug 2025 11:04:43 +0100 Subject: [PATCH] appview: remove all mentions of SignedClient Signed-off-by: oppiliappan --- appview/config/config.go | 2 +- appview/oauth/handler/handler.go | 180 ++++++++++--------- appview/repo/index.go | 157 ---------------- appview/repo/repo.go | 111 +++--------- knotclient/signer.go | 299 ------------------------------- knotserver/http_util.go | 10 -- knotserver/ingester.go | 10 +- knotserver/internal.go | 2 - nix/modules/knot.nix | 7 - 9 files changed, 127 insertions(+), 651 deletions(-) delete mode 100644 knotclient/signer.go diff --git a/appview/config/config.go b/appview/config/config.go index 213e343e..8fd0a480 100644 --- a/appview/config/config.go +++ b/appview/config/config.go @@ -17,7 +17,7 @@ type CoreConfig struct { Dev bool `env:"DEV, default=false"` DisallowedNicknamesFile string `env:"DISALLOWED_NICKNAMES_FILE"` - // temporarily, to add users to default spindle + // temporarily, to add users to default knot and spindle AppPassword string `env:"APP_PASSWORD"` } diff --git a/appview/oauth/handler/handler.go b/appview/oauth/handler/handler.go index 1fd18bd3..65c458d6 100644 --- a/appview/oauth/handler/handler.go +++ b/appview/oauth/handler/handler.go @@ -8,6 +8,7 @@ import ( "log" "net/http" "net/url" + "slices" "strings" "time" @@ -25,7 +26,6 @@ import ( "tangled.sh/tangled.sh/core/appview/oauth/client" "tangled.sh/tangled.sh/core/appview/pages" "tangled.sh/tangled.sh/core/idresolver" - "tangled.sh/tangled.sh/core/knotclient" "tangled.sh/tangled.sh/core/rbac" "tangled.sh/tangled.sh/core/tid" ) @@ -353,13 +353,16 @@ func pubKeyFromJwk(jwks string) (jwk.Key, error) { return pubKey, nil } +var ( + tangledHandle = "tangled.sh" + tangledDid = "did:plc:wshs7t2adsemcrrd4snkeqli" + defaultSpindle = "spindle.tangled.sh" + defaultKnot = "knot1.tangled.sh" +) + func (o *OAuthHandler) addToDefaultSpindle(did string) { // use the tangled.sh app password to get an accessJwt // and create an sh.tangled.spindle.member record with that - - defaultSpindle := "spindle.tangled.sh" - appPassword := o.config.Core.AppPassword - spindleMembers, err := db.GetSpindleMembers( o.db, db.FilterEq("instance", "spindle.tangled.sh"), @@ -375,27 +378,85 @@ func (o *OAuthHandler) addToDefaultSpindle(did string) { return } - // TODO: hardcoded tangled handle and did for now - tangledHandle := "tangled.sh" - tangledDid := "did:plc:wshs7t2adsemcrrd4snkeqli" + log.Printf("adding %s to default spindle", did) + session, err := o.createAppPasswordSession() + if err != nil { + log.Printf("failed to create session: %s", err) + return + } - if appPassword == "" { - log.Println("no app password configured, skipping spindle member addition") + record := tangled.SpindleMember{ + LexiconTypeID: "sh.tangled.spindle.member", + Subject: did, + Instance: defaultSpindle, + CreatedAt: time.Now().Format(time.RFC3339), + } + + if err := session.putRecord(record); err != nil { + log.Printf("failed to add member to default knot: %s", err) return } - log.Printf("adding %s to default spindle", did) + log.Printf("successfully added %s to default spindle", did) +} - resolved, err := o.idResolver.ResolveIdent(context.Background(), tangledDid) +func (o *OAuthHandler) addToDefaultKnot(did string) { + // use the tangled.sh app password to get an accessJwt + // and create an sh.tangled.spindle.member record with that + + allKnots, err := o.enforcer.GetKnotsForUser(did) + if err != nil { + log.Printf("failed to get knot members for did %s: %v", did, err) + return + } + + if slices.Contains(allKnots, defaultKnot) { + log.Printf("did %s is already a member of the default knot", did) + return + } + + log.Printf("adding %s to default knot", did) + session, err := o.createAppPasswordSession() if err != nil { - log.Printf("failed to resolve tangled.sh DID %s: %v", tangledDid, err) + log.Printf("failed to create session: %s", err) + return + } + + record := tangled.KnotMember{ + LexiconTypeID: "sh.tangled.knot.member", + Subject: did, + Domain: defaultKnot, + CreatedAt: time.Now().Format(time.RFC3339), + } + + if err := session.putRecord(record); err != nil { + log.Printf("failed to add member to default knot: %s", err) return } + log.Printf("successfully added %s to default Knot", did) +} + +// create a session using apppasswords +type session struct { + AccessJwt string `json:"accessJwt"` + PdsEndpoint string +} + +func (o *OAuthHandler) createAppPasswordSession() (*session, error) { + appPassword := o.config.Core.AppPassword + if appPassword == "" { + return nil, fmt.Errorf("no app password configured, skipping member addition") + } + + resolved, err := o.idResolver.ResolveIdent(context.Background(), tangledDid) + if err != nil { + return nil, fmt.Errorf("failed to resolve tangled.sh DID %s: %v", tangledDid, err) + } + pdsEndpoint := resolved.PDSEndpoint() if pdsEndpoint == "" { - log.Printf("no PDS endpoint found for tangled.sh DID %s", tangledDid) - return + return nil, fmt.Errorf("no PDS endpoint found for tangled.sh DID %s", tangledDid) } sessionPayload := map[string]string{ @@ -404,119 +465,74 @@ func (o *OAuthHandler) addToDefaultSpindle(did string) { } sessionBytes, err := json.Marshal(sessionPayload) if err != nil { - log.Printf("failed to marshal session payload: %v", err) - return + return nil, fmt.Errorf("failed to marshal session payload: %v", err) } sessionURL := pdsEndpoint + "/xrpc/com.atproto.server.createSession" sessionReq, err := http.NewRequestWithContext(context.Background(), "POST", sessionURL, bytes.NewBuffer(sessionBytes)) if err != nil { - log.Printf("failed to create session request: %v", err) - return + return nil, fmt.Errorf("failed to create session request: %v", err) } sessionReq.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 30 * time.Second} sessionResp, err := client.Do(sessionReq) if err != nil { - log.Printf("failed to create session: %v", err) - return + return nil, fmt.Errorf("failed to create session: %v", err) } defer sessionResp.Body.Close() if sessionResp.StatusCode != http.StatusOK { - log.Printf("failed to create session: HTTP %d", sessionResp.StatusCode) - return + return nil, fmt.Errorf("failed to create session: HTTP %d", sessionResp.StatusCode) } - var session struct { - AccessJwt string `json:"accessJwt"` - } + var session session if err := json.NewDecoder(sessionResp.Body).Decode(&session); err != nil { - log.Printf("failed to decode session response: %v", err) - return + return nil, fmt.Errorf("failed to decode session response: %v", err) } - record := tangled.SpindleMember{ - LexiconTypeID: "sh.tangled.spindle.member", - Subject: did, - Instance: defaultSpindle, - CreatedAt: time.Now().Format(time.RFC3339), - } + session.PdsEndpoint = pdsEndpoint + + return &session, nil +} +func (s *session) putRecord(record any) error { recordBytes, err := json.Marshal(record) if err != nil { - log.Printf("failed to marshal spindle member record: %v", err) - return + return fmt.Errorf("failed to marshal knot member record: %w", err) } - payload := map[string]interface{}{ + payload := map[string]any{ "repo": tangledDid, - "collection": tangled.SpindleMemberNSID, + "collection": tangled.KnotMemberNSID, "rkey": tid.TID(), "record": json.RawMessage(recordBytes), } payloadBytes, err := json.Marshal(payload) if err != nil { - log.Printf("failed to marshal request payload: %v", err) - return + return fmt.Errorf("failed to marshal request payload: %w", err) } - url := pdsEndpoint + "/xrpc/com.atproto.repo.putRecord" + url := s.PdsEndpoint + "/xrpc/com.atproto.repo.putRecord" req, err := http.NewRequestWithContext(context.Background(), "POST", url, bytes.NewBuffer(payloadBytes)) if err != nil { - log.Printf("failed to create HTTP request: %v", err) - return + return fmt.Errorf("failed to create HTTP request: %w", err) } req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", "Bearer "+session.AccessJwt) + req.Header.Set("Authorization", "Bearer "+s.AccessJwt) + client := &http.Client{Timeout: 30 * time.Second} resp, err := client.Do(req) if err != nil { - log.Printf("failed to add user to default spindle: %v", err) - return + return fmt.Errorf("failed to add user to default Knot: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - log.Printf("failed to add user to default spindle: HTTP %d", resp.StatusCode) - return + return fmt.Errorf("failed to add user to default Knot: HTTP %d", resp.StatusCode) } - log.Printf("successfully added %s to default spindle", did) -} - -func (o *OAuthHandler) addToDefaultKnot(did string) { - defaultKnot := "knot1.tangled.sh" - - log.Printf("adding %s to default knot", did) - err := o.enforcer.AddKnotMember(defaultKnot, did) - if err != nil { - log.Println("failed to add user to knot1.tangled.sh: ", err) - return - } - err = o.enforcer.E.SavePolicy() - if err != nil { - log.Println("failed to add user to knot1.tangled.sh: ", err) - return - } - - secret, err := db.GetRegistrationKey(o.db, defaultKnot) - if err != nil { - log.Println("failed to get registration key for knot1.tangled.sh") - return - } - signedClient, err := knotclient.NewSignedClient(defaultKnot, secret, o.config.Core.Dev) - resp, err := signedClient.AddMember(did) - if err != nil { - log.Println("failed to add user to knot1.tangled.sh: ", err) - return - } - - if resp.StatusCode != http.StatusNoContent { - log.Println("failed to add user to knot1.tangled.sh: ", resp.StatusCode) - return - } + return nil } diff --git a/appview/repo/index.go b/appview/repo/index.go index 4ac668cb..7b7c91bf 100644 --- a/appview/repo/index.go +++ b/appview/repo/index.go @@ -101,27 +101,6 @@ func (rp *Repo) RepoIndex(w http.ResponseWriter, r *http.Request) { user := rp.oauth.GetUser(r) repoInfo := f.RepoInfo(user) - // secret, err := db.GetRegistrationKey(rp.db, f.Knot) - // if err != nil { - // log.Printf("failed to get registration key for %s: %s", f.Knot, err) - // rp.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") - // } - - // signedClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) - // if err != nil { - // log.Printf("failed to create signed client for %s: %s", f.Knot, err) - // return - // } - - // var forkInfo *types.ForkInfo - // if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) { - // forkInfo, err = getForkInfo(r, repoInfo, rp, f, result.Ref, user, signedClient) - // if err != nil { - // log.Printf("Failed to fetch fork information: %v", err) - // return - // } - // } - // TODO: a bit dirty languageInfo, err := rp.getLanguageInfo(f, us, result.Ref, ref == "") if err != nil { @@ -227,139 +206,3 @@ func (rp *Repo) getLanguageInfo( return languageStats, nil } - -// func getForkInfo( -// r *http.Request, -// repoInfo repoinfo.RepoInfo, -// rp *Repo, -// f *reporesolver.ResolvedRepo, -// currentRef string, -// user *oauth.User, -// signedClient *knotclient.SignedClient, -// ) (*types.ForkInfo, error) { -// if user == nil { -// return nil, nil -// } -// -// forkInfo := types.ForkInfo{ -// IsFork: repoInfo.Source != nil, -// Status: types.UpToDate, -// } -// -// if !forkInfo.IsFork { -// forkInfo.IsFork = false -// return &forkInfo, nil -// } -// -// us, err := knotclient.NewUnsignedClient(repoInfo.Source.Knot, rp.config.Core.Dev) -// if err != nil { -// log.Printf("failed to create unsigned client for %s", repoInfo.Source.Knot) -// return nil, err -// } -// -// result, err := us.Branches(repoInfo.Source.Did, repoInfo.Source.Name) -// if err != nil { -// log.Println("failed to reach knotserver", err) -// return nil, err -// } -// -// if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool { -// return branch.Name == currentRef -// }) { -// forkInfo.Status = types.MissingBranch -// return &forkInfo, nil -// } -// -// <<<<<<< Conflict 1 of 2 -// %%%%%%% Changes from base #1 to side #1 -// client, err := rp.oauth.ServiceClient( -// r, -// oauth.WithService(f.Knot), -// oauth.WithLxm(tangled.RepoHiddenRefNSID), -// oauth.WithDev(rp.config.Core.Dev), -// ) -// if err != nil { -// log.Printf("failed to connect to knot server: %v", err) -// %%%%%%% Changes from base #2 to side #2 -// - newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, currentRef, currentRef) -// + newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, f.Ref, f.Ref) -// if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent { -// log.Printf("failed to update tracking branch: %s", err) -// +++++++ Contents of side #3 -// client, err := rp.oauth.ServiceClient( -// r, -// oauth.WithService(f.Knot), -// oauth.WithLxm(tangled.RepoHiddenRefNSID), -// oauth.WithDev(rp.config.Core.Dev), -// ) -// if err != nil { -// log.Printf("failed to connect to knot server: %v", err) -// >>>>>>> Conflict 1 of 2 ends -// return nil, err -// } -// -// <<<<<<< Conflict 2 of 2 -// %%%%%%% Changes from base #1 to side #1 -// resp, err := tangled.RepoHiddenRef( -// r.Context(), -// client, -// &tangled.RepoHiddenRef_Input{ -// - ForkRef: f.Ref, -// - RemoteRef: f.Ref, -// + ForkRef: currentRef, -// + RemoteRef: currentRef, -// Repo: f.RepoAt().String(), -// }, -// ) -// if err != nil || !resp.Success { -// if err != nil { -// log.Printf("failed to update tracking branch: %s", err) -// } else { -// log.Printf("failed to update tracking branch: success=false") -// } -// return nil, fmt.Errorf("failed to update tracking branch") -// } -// -// - hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref) -// + hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef) -// -// %%%%%%% Changes from base #2 to side #2 -// - hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef) -// + hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref) -// -// +++++++ Contents of side #3 -// resp, err := tangled.RepoHiddenRef( -// r.Context(), -// client, -// &tangled.RepoHiddenRef_Input{ -// ForkRef: currentRef, -// RemoteRef: currentRef, -// Repo: f.RepoAt().String(), -// }, -// ) -// if err != nil || !resp.Success { -// if err != nil { -// log.Printf("failed to update tracking branch: %s", err) -// } else { -// log.Printf("failed to update tracking branch: success=false") -// } -// return nil, fmt.Errorf("failed to update tracking branch") -// } -// -// hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef) -// >>>>>>> Conflict 2 of 2 ends -// var status types.AncestorCheckResponse -// forkSyncableResp, err := signedClient.RepoForkAheadBehind(user.Did, string(f.RepoAt()), repoInfo.Name, currentRef, hiddenRef) -// if err != nil { -// log.Printf("failed to check if fork is ahead/behind: %s", err) -// return nil, err -// } -// -// if err := json.NewDecoder(forkSyncableResp.Body).Decode(&status); err != nil { -// log.Printf("failed to decode fork status: %s", err) -// return nil, err -// } -// -// forkInfo.Status = status.Status -// return &forkInfo, nil -// } diff --git a/appview/repo/repo.go b/appview/repo/repo.go index b710bd3a..94fcd1be 100644 --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -863,45 +863,33 @@ func (rp *Repo) AddCollaborator(w http.ResponseWriter, r *http.Request) { fail("Failed to write record to PDS.", err) return } - l = l.With("at-uri", resp.Uri) - l.Info("wrote record to PDS") - l.Info("adding to knot") - secret, err := db.GetRegistrationKey(rp.db, f.Knot) - if err != nil { - fail("Failed to add to knot.", err) - return - } + aturi := resp.Uri + l = l.With("at-uri", aturi) + l.Info("wrote record to PDS") - ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev) + tx, err := rp.db.BeginTx(r.Context(), nil) if err != nil { - fail("Failed to add to knot.", err) + fail("Failed to add collaborator.", err) return } - ksResp, err := ksClient.AddCollaborator(f.OwnerDid(), f.Name, collaboratorIdent.DID.String()) - if err != nil { - fail("Knot was unreachable.", err) - return - } + rollback := func() { + err1 := tx.Rollback() + err2 := rp.enforcer.E.LoadPolicy() + err3 := rollbackRecord(context.Background(), aturi, client) - if ksResp.StatusCode != http.StatusNoContent { - fail(fmt.Sprintf("Knot returned unexpected status code: %d.", ksResp.StatusCode), nil) - return - } + // ignore txn complete errors, this is okay + if errors.Is(err1, sql.ErrTxDone) { + err1 = nil + } - tx, err := rp.db.BeginTx(r.Context(), nil) - if err != nil { - fail("Failed to add collaborator.", err) - return - } - defer func() { - tx.Rollback() - err = rp.enforcer.E.LoadPolicy() - if err != nil { - fail("Failed to add collaborator.", err) + if errs := errors.Join(err1, err2, err3); errs != nil { + l.Error("failed to rollback changes", "errs", errs) + return } - }() + } + defer rollback() err = rp.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.DidSlashRepo()) if err != nil { @@ -933,6 +921,9 @@ func (rp *Repo) AddCollaborator(w http.ResponseWriter, r *http.Request) { return } + // clear aturi to when everything is successful + aturi = "" + rp.pages.HxRefresh(w) } @@ -1207,66 +1198,6 @@ func (rp *Repo) RepoSettings(w http.ResponseWriter, r *http.Request) { case "pipelines": rp.pipelineSettings(w, r) } - - // user := rp.oauth.GetUser(r) - // repoCollaborators, err := f.Collaborators(r.Context()) - // if err != nil { - // log.Println("failed to get collaborators", err) - // } - - // isCollaboratorInviteAllowed := false - // if user != nil { - // ok, err := rp.enforcer.IsCollaboratorInviteAllowed(user.Did, f.Knot, f.DidSlashRepo()) - // if err == nil && ok { - // isCollaboratorInviteAllowed = true - // } - // } - - // us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev) - // if err != nil { - // log.Println("failed to create unsigned client", err) - // return - // } - - // result, err := us.Branches(f.OwnerDid(), f.Name) - // if err != nil { - // log.Println("failed to reach knotserver", err) - // return - // } - - // // all spindles that this user is a member of - // spindles, err := rp.enforcer.GetSpindlesForUser(user.Did) - // if err != nil { - // log.Println("failed to fetch spindles", err) - // return - // } - - // var secrets []*tangled.RepoListSecrets_Secret - // if f.Spindle != "" { - // if spindleClient, err := rp.oauth.ServiceClient( - // r, - // oauth.WithService(f.Spindle), - // oauth.WithLxm(tangled.RepoListSecretsNSID), - // oauth.WithDev(rp.config.Core.Dev), - // ); err != nil { - // log.Println("failed to create spindle client", err) - // } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt().String()); err != nil { - // log.Println("failed to fetch secrets", err) - // } else { - // secrets = resp.Secrets - // } - // } - - // rp.pages.RepoSettings(w, pages.RepoSettingsParams{ - // LoggedInUser: user, - // RepoInfo: f.RepoInfo(user), - // Collaborators: repoCollaborators, - // IsCollaboratorInviteAllowed: isCollaboratorInviteAllowed, - // Branches: result.Branches, - // Spindles: spindles, - // CurrentSpindle: f.Spindle, - // Secrets: secrets, - // }) } func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) { diff --git a/knotclient/signer.go b/knotclient/signer.go deleted file mode 100644 index 2539bf5e..00000000 --- a/knotclient/signer.go +++ /dev/null @@ -1,299 +0,0 @@ -package knotclient - -import ( - "bytes" - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "net/http" - "net/url" - "time" - - "tangled.sh/tangled.sh/core/types" -) - -type SignerTransport struct { - Secret string -} - -func (s SignerTransport) RoundTrip(req *http.Request) (*http.Response, error) { - timestamp := time.Now().Format(time.RFC3339) - mac := hmac.New(sha256.New, []byte(s.Secret)) - message := req.Method + req.URL.Path + timestamp - mac.Write([]byte(message)) - signature := hex.EncodeToString(mac.Sum(nil)) - req.Header.Set("X-Signature", signature) - req.Header.Set("X-Timestamp", timestamp) - return http.DefaultTransport.RoundTrip(req) -} - -type SignedClient struct { - Secret string - Url *url.URL - client *http.Client -} - -func NewSignedClient(domain, secret string, dev bool) (*SignedClient, error) { - client := &http.Client{ - Timeout: 5 * time.Second, - Transport: SignerTransport{ - Secret: secret, - }, - } - - scheme := "https" - if dev { - scheme = "http" - } - url, err := url.Parse(fmt.Sprintf("%s://%s", scheme, domain)) - if err != nil { - return nil, err - } - - signedClient := &SignedClient{ - Secret: secret, - client: client, - Url: url, - } - - return signedClient, nil -} - -func (s *SignedClient) newRequest(method, endpoint string, body []byte) (*http.Request, error) { - return http.NewRequest(method, s.Url.JoinPath(endpoint).String(), bytes.NewReader(body)) -} - -func (s *SignedClient) Init(did string) (*http.Response, error) { - const ( - Method = "POST" - Endpoint = "/init" - ) - - body, _ := json.Marshal(map[string]any{ - "did": did, - }) - - req, err := s.newRequest(Method, Endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) NewRepo(did, repoName, defaultBranch string) (*http.Response, error) { - const ( - Method = "PUT" - Endpoint = "/repo/new" - ) - - body, _ := json.Marshal(map[string]any{ - "did": did, - "name": repoName, - "default_branch": defaultBranch, - }) - - req, err := s.newRequest(Method, Endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) RepoForkAheadBehind(ownerDid, source, name, branch, hiddenRef string) (*http.Response, error) { - const ( - Method = "GET" - ) - endpoint := fmt.Sprintf("/repo/fork/sync/%s", url.PathEscape(branch)) - - body, _ := json.Marshal(map[string]any{ - "did": ownerDid, - "source": source, - "name": name, - "hiddenref": hiddenRef, - }) - - req, err := s.newRequest(Method, endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) SyncRepoFork(ownerDid, source, name, branch string) (*http.Response, error) { - const ( - Method = "POST" - ) - endpoint := fmt.Sprintf("/repo/fork/sync/%s", url.PathEscape(branch)) - - body, _ := json.Marshal(map[string]any{ - "did": ownerDid, - "source": source, - "name": name, - }) - - req, err := s.newRequest(Method, endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) ForkRepo(ownerDid, source, name string) (*http.Response, error) { - const ( - Method = "POST" - Endpoint = "/repo/fork" - ) - - body, _ := json.Marshal(map[string]any{ - "did": ownerDid, - "source": source, - "name": name, - }) - - req, err := s.newRequest(Method, Endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) RemoveRepo(did, repoName string) (*http.Response, error) { - const ( - Method = "DELETE" - Endpoint = "/repo" - ) - - body, _ := json.Marshal(map[string]any{ - "did": did, - "name": repoName, - }) - - req, err := s.newRequest(Method, Endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) AddMember(did string) (*http.Response, error) { - const ( - Method = "PUT" - Endpoint = "/member/add" - ) - - body, _ := json.Marshal(map[string]any{ - "did": did, - }) - - req, err := s.newRequest(Method, Endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) SetDefaultBranch(ownerDid, repoName, branch string) (*http.Response, error) { - const ( - Method = "PUT" - ) - endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName) - - body, _ := json.Marshal(map[string]any{ - "branch": branch, - }) - - req, err := s.newRequest(Method, endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) AddCollaborator(ownerDid, repoName, memberDid string) (*http.Response, error) { - const ( - Method = "POST" - ) - endpoint := fmt.Sprintf("/%s/%s/collaborator/add", ownerDid, repoName) - - body, _ := json.Marshal(map[string]any{ - "did": memberDid, - }) - - req, err := s.newRequest(Method, endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) Merge( - patch []byte, - ownerDid, targetRepo, branch, commitMessage, commitBody, authorName, authorEmail string, -) (*http.Response, error) { - const ( - Method = "POST" - ) - endpoint := fmt.Sprintf("/%s/%s/merge", ownerDid, targetRepo) - - mr := types.MergeRequest{ - Branch: branch, - CommitMessage: commitMessage, - CommitBody: commitBody, - AuthorName: authorName, - AuthorEmail: authorEmail, - Patch: string(patch), - } - - body, _ := json.Marshal(mr) - - req, err := s.newRequest(Method, endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) MergeCheck(patch []byte, ownerDid, targetRepo, branch string) (*http.Response, error) { - const ( - Method = "POST" - ) - endpoint := fmt.Sprintf("/%s/%s/merge/check", ownerDid, targetRepo) - - body, _ := json.Marshal(map[string]any{ - "patch": string(patch), - "branch": branch, - }) - - req, err := s.newRequest(Method, endpoint, body) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} - -func (s *SignedClient) NewHiddenRef(ownerDid, targetRepo, forkBranch, remoteBranch string) (*http.Response, error) { - const ( - Method = "POST" - ) - endpoint := fmt.Sprintf("/%s/%s/hidden-ref/%s/%s", ownerDid, targetRepo, url.PathEscape(forkBranch), url.PathEscape(remoteBranch)) - - req, err := s.newRequest(Method, endpoint, nil) - if err != nil { - return nil, err - } - - return s.client.Do(req) -} diff --git a/knotserver/http_util.go b/knotserver/http_util.go index 8b8451ca..b0ee4d1e 100644 --- a/knotserver/http_util.go +++ b/knotserver/http_util.go @@ -20,13 +20,3 @@ func writeError(w http.ResponseWriter, msg string, status int) { func notFound(w http.ResponseWriter) { writeError(w, "not found", http.StatusNotFound) } - -func writeMsg(w http.ResponseWriter, msg string) { - writeJSON(w, map[string]string{"msg": msg}) -} - -func writeConflict(w http.ResponseWriter, data interface{}) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusConflict) - json.NewEncoder(w).Encode(data) -} diff --git a/knotserver/ingester.go b/knotserver/ingester.go index e4330e50..69225ad1 100644 --- a/knotserver/ingester.go +++ b/knotserver/ingester.go @@ -255,8 +255,12 @@ func (h *Handle) processCollaborator(ctx context.Context, event *models.Event) e didSlashRepo, _ := securejoin.SecureJoin(owner.DID.String(), repo.Name) // check perms for this user - if ok, err := h.e.IsCollaboratorInviteAllowed(did, rbac.ThisServer, didSlashRepo); !ok || err != nil { - return fmt.Errorf("insufficient permissions: %w", err) + ok, err := h.e.IsCollaboratorInviteAllowed(did, rbac.ThisServer, didSlashRepo) + if err != nil { + return fmt.Errorf("failed to check permissions: %w", err) + } + if !ok { + return fmt.Errorf("insufficient permissions: %s, %s, %s", did, "IsCollaboratorInviteAllowed", didSlashRepo) } if err := h.db.AddDid(subjectId.DID.String()); err != nil { @@ -298,7 +302,7 @@ func (h *Handle) fetchAndAddKeys(ctx context.Context, did string) error { return fmt.Errorf("error reading response body: %w", err) } - for _, key := range strings.Split(string(plaintext), "\n") { + for key := range strings.SplitSeq(string(plaintext), "\n") { if key == "" { continue } diff --git a/knotserver/internal.go b/knotserver/internal.go index e93644d9..b88584b8 100644 --- a/knotserver/internal.go +++ b/knotserver/internal.go @@ -47,7 +47,6 @@ func (h *InternalHandle) PushAllowed(w http.ResponseWriter, r *http.Request) { } w.WriteHeader(http.StatusNoContent) - return } func (h *InternalHandle) InternalKeys(w http.ResponseWriter, r *http.Request) { @@ -63,7 +62,6 @@ func (h *InternalHandle) InternalKeys(w http.ResponseWriter, r *http.Request) { data = append(data, j) } writeJSON(w, data) - return } type PushOptions struct { diff --git a/nix/modules/knot.nix b/nix/modules/knot.nix index ce8816f2..ff6463d1 100644 --- a/nix/modules/knot.nix +++ b/nix/modules/knot.nix @@ -99,12 +99,6 @@ in description = "DID of owner (required)"; }; - secretFile = mkOption { - type = lib.types.path; - example = "KNOT_SERVER_SECRET="; - description = "File containing secret key provided by appview (required)"; - }; - dbPath = mkOption { type = types.path; default = "${cfg.stateDir}/knotserver.db"; @@ -207,7 +201,6 @@ in "KNOT_SERVER_HOSTNAME=${cfg.server.hostname}" "KNOT_SERVER_OWNER=${cfg.server.owner}" ]; - EnvironmentFile = cfg.server.secretFile; ExecStart = "${cfg.package}/bin/knot server"; Restart = "always"; }; -- 2.51.2