forked from tangled.org/core
this repo has no description
1package serververify 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 8 indigoxrpc "github.com/bluesky-social/indigo/xrpc" 9 "tangled.sh/tangled.sh/core/api/tangled" 10 "tangled.sh/tangled.sh/core/appview/db" 11 "tangled.sh/tangled.sh/core/appview/xrpcclient" 12 "tangled.sh/tangled.sh/core/rbac" 13) 14 15var ( 16 FetchError = errors.New("failed to fetch owner") 17) 18 19// fetchOwner fetches the owner DID from a server's /owner endpoint 20func fetchOwner(ctx context.Context, domain string, dev bool) (string, error) { 21 scheme := "https" 22 if dev { 23 scheme = "http" 24 } 25 26 host := fmt.Sprintf("%s://%s", scheme, domain) 27 xrpcc := &indigoxrpc.Client{ 28 Host: host, 29 } 30 31 res, err := tangled.Owner(ctx, xrpcc) 32 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 33 return "", xrpcerr 34 } 35 36 return res.Owner, nil 37} 38 39type OwnerMismatch struct { 40 expected string 41 observed string 42} 43 44func (e *OwnerMismatch) Error() string { 45 return fmt.Sprintf("owner mismatch: %q != %q", e.expected, e.observed) 46} 47 48// RunVerification verifies that the server at the given domain has the expected owner 49func RunVerification(ctx context.Context, domain, expectedOwner string, dev bool) error { 50 observedOwner, err := fetchOwner(ctx, domain, dev) 51 if err != nil { 52 return err 53 } 54 55 if observedOwner != expectedOwner { 56 return &OwnerMismatch{ 57 expected: expectedOwner, 58 observed: observedOwner, 59 } 60 } 61 62 return nil 63} 64 65// MarkSpindleVerified marks a spindle as verified in the DB and adds the user as its owner 66func MarkSpindleVerified(d *db.DB, e *rbac.Enforcer, instance, owner string) (int64, error) { 67 tx, err := d.Begin() 68 if err != nil { 69 return 0, fmt.Errorf("failed to create txn: %w", err) 70 } 71 defer func() { 72 tx.Rollback() 73 e.E.LoadPolicy() 74 }() 75 76 // mark this spindle as verified in the db 77 rowId, err := db.VerifySpindle( 78 tx, 79 db.FilterEq("owner", owner), 80 db.FilterEq("instance", instance), 81 ) 82 if err != nil { 83 return 0, fmt.Errorf("failed to write to DB: %w", err) 84 } 85 86 err = e.AddSpindleOwner(instance, owner) 87 if err != nil { 88 return 0, fmt.Errorf("failed to update ACL: %w", err) 89 } 90 91 err = tx.Commit() 92 if err != nil { 93 return 0, fmt.Errorf("failed to commit txn: %w", err) 94 } 95 96 err = e.E.SavePolicy() 97 if err != nil { 98 return 0, fmt.Errorf("failed to update ACL: %w", err) 99 } 100 101 return rowId, nil 102} 103 104// MarkKnotVerified marks a knot as verified and sets up ownership/permissions 105func MarkKnotVerified(d *db.DB, e *rbac.Enforcer, domain, owner string) error { 106 tx, err := d.BeginTx(context.Background(), nil) 107 if err != nil { 108 return fmt.Errorf("failed to start tx: %w", err) 109 } 110 defer func() { 111 tx.Rollback() 112 e.E.LoadPolicy() 113 }() 114 115 // mark as registered 116 err = db.MarkRegistered( 117 tx, 118 db.FilterEq("did", owner), 119 db.FilterEq("domain", domain), 120 ) 121 if err != nil { 122 return fmt.Errorf("failed to register domain: %w", err) 123 } 124 125 // add basic acls for this domain 126 err = e.AddKnot(domain) 127 if err != nil { 128 return fmt.Errorf("failed to add knot to enforcer: %w", err) 129 } 130 131 // add this did as owner of this domain 132 err = e.AddKnotOwner(domain, owner) 133 if err != nil { 134 return fmt.Errorf("failed to add knot owner to enforcer: %w", err) 135 } 136 137 err = tx.Commit() 138 if err != nil { 139 return fmt.Errorf("failed to commit changes: %w", err) 140 } 141 142 err = e.E.SavePolicy() 143 if err != nil { 144 return fmt.Errorf("failed to update ACLs: %w", err) 145 } 146 147 return nil 148}