This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

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