forked from tangled.org/core
this repo has no description

appview: remove all mentions of SignedClient

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

oppi.li 9b88f828 161b5275

verified
Changed files
+127 -651
appview
config
oauth
handler
repo
knotclient
knotserver
nix
modules
+1 -1
appview/config/config.go
···
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"`
}
+98 -82
appview/oauth/handler/handler.go
···
"log"
"net/http"
"net/url"
+
"slices"
"strings"
"time"
···
"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"
)
···
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"),
···
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
+
}
+
+
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("successfully added %s to default spindle", did)
+
}
+
+
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
+
}
-
if appPassword == "" {
-
log.Println("no app password configured, skipping spindle member addition")
+
log.Printf("adding %s to default knot", did)
+
session, err := o.createAppPasswordSession()
+
if err != nil {
+
log.Printf("failed to create session: %s", err)
return
}
-
log.Printf("adding %s to default spindle", did)
+
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 {
-
log.Printf("failed to resolve tangled.sh DID %s: %v", tangledDid, err)
-
return
+
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{
···
}
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
-
}
-
-
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
+
return fmt.Errorf("failed to add user to default Knot: HTTP %d", resp.StatusCode)
}
-
if resp.StatusCode != http.StatusNoContent {
-
log.Println("failed to add user to knot1.tangled.sh: ", resp.StatusCode)
-
return
-
}
+
return nil
}
-157
appview/repo/index.go
···
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 {
···
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
-
// }
+21 -90
appview/repo/repo.go
···
fail("Failed to write record to PDS.", err)
return
}
-
l = l.With("at-uri", resp.Uri)
+
+
aturi := resp.Uri
+
l = l.With("at-uri", aturi)
l.Info("wrote record to PDS")
-
l.Info("adding to knot")
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
+
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
}
-
ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
-
if err != nil {
-
fail("Failed to add to knot.", err)
-
return
-
}
+
rollback := func() {
+
err1 := tx.Rollback()
+
err2 := rp.enforcer.E.LoadPolicy()
+
err3 := rollbackRecord(context.Background(), aturi, client)
-
ksResp, err := ksClient.AddCollaborator(f.OwnerDid(), f.Name, collaboratorIdent.DID.String())
-
if err != nil {
-
fail("Knot was unreachable.", err)
-
return
-
}
+
// ignore txn complete errors, this is okay
+
if errors.Is(err1, sql.ErrTxDone) {
+
err1 = nil
+
}
-
if ksResp.StatusCode != http.StatusNoContent {
-
fail(fmt.Sprintf("Knot returned unexpected status code: %d.", ksResp.StatusCode), nil)
-
return
-
}
-
-
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 {
···
fail("Failed to update collaborator permissions.", err)
return
}
+
+
// clear aturi to when everything is successful
+
aturi = ""
rp.pages.HxRefresh(w)
}
···
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) {
-299
knotclient/signer.go
···
-
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)
-
}
-10
knotserver/http_util.go
···
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)
-
}
+7 -3
knotserver/ingester.go
···
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 {
···
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
}
-2
knotserver/internal.go
···
}
w.WriteHeader(http.StatusNoContent)
-
return
}
func (h *InternalHandle) InternalKeys(w http.ResponseWriter, r *http.Request) {
···
data = append(data, j)
}
writeJSON(w, data)
-
return
}
type PushOptions struct {
-7
nix/modules/knot.nix
···
description = "DID of owner (required)";
};
-
secretFile = mkOption {
-
type = lib.types.path;
-
example = "KNOT_SERVER_SECRET=<hash>";
-
description = "File containing secret key provided by appview (required)";
-
};
-
dbPath = mkOption {
type = types.path;
default = "${cfg.stateDir}/knotserver.db";
···
"KNOT_SERVER_HOSTNAME=${cfg.server.hostname}"
"KNOT_SERVER_OWNER=${cfg.server.owner}"
];
-
EnvironmentFile = cfg.server.secretFile;
ExecStart = "${cfg.package}/bin/knot server";
Restart = "always";
};