porting all github actions from bluesky-social/indigo to tangled CI
at ci 15 kB view raw
1package pds 2 3import ( 4 "bytes" 5 "context" 6 "database/sql" 7 "fmt" 8 "io" 9 10 comatprototypes "github.com/bluesky-social/indigo/api/atproto" 11 lexutil "github.com/bluesky-social/indigo/lex/util" 12 "github.com/bluesky-social/indigo/models" 13 "github.com/ipfs/go-cid" 14 "github.com/lestrrat-go/jwx/v2/jwt" 15) 16 17func (s *Server) handleComAtprotoServerCreateAccount(ctx context.Context, body *comatprototypes.ServerCreateAccount_Input) (*comatprototypes.ServerCreateAccount_Output, error) { 18 if body.Email == nil { 19 return nil, fmt.Errorf("email is required") 20 } 21 22 if body.Password == nil { 23 return nil, fmt.Errorf("password is required") 24 } 25 26 if err := validateEmail(*body.Email); err != nil { 27 return nil, err 28 } 29 30 if err := s.validateHandle(body.Handle); err != nil { 31 return nil, err 32 } 33 34 _, err := s.lookupUserByHandle(ctx, body.Handle) 35 switch err { 36 default: 37 return nil, err 38 case nil: 39 return nil, fmt.Errorf("handle already registered") 40 case ErrNoSuchUser: 41 // handle is available, lets go 42 } 43 44 var recoveryKey string 45 if body.RecoveryKey != nil { 46 recoveryKey = *body.RecoveryKey 47 } 48 49 u := User{ 50 Handle: body.Handle, 51 Password: *body.Password, 52 RecoveryKey: recoveryKey, 53 Email: *body.Email, 54 } 55 if err := s.db.Create(&u).Error; err != nil { 56 return nil, err 57 } 58 59 if recoveryKey == "" { 60 recoveryKey = s.signingKey.Public().DID() 61 } 62 63 d, err := s.plc.CreateDID(ctx, s.signingKey, recoveryKey, body.Handle, s.serviceUrl) 64 if err != nil { 65 return nil, fmt.Errorf("create did: %w", err) 66 } 67 68 u.Did = d 69 if err := s.db.Save(&u).Error; err != nil { 70 return nil, err 71 } 72 73 ai := &models.ActorInfo{ 74 Uid: u.ID, 75 Did: d, 76 Handle: sql.NullString{String: body.Handle, Valid: true}, 77 } 78 if err := s.db.Create(ai).Error; err != nil { 79 return nil, err 80 } 81 82 if err := s.repoman.InitNewActor(ctx, u.ID, u.Handle, u.Did, "", "", ""); err != nil { 83 return nil, err 84 } 85 86 tok, err := s.createAuthTokenForUser(ctx, body.Handle, d) 87 if err != nil { 88 return nil, err 89 } 90 91 return &comatprototypes.ServerCreateAccount_Output{ 92 Handle: body.Handle, 93 Did: d, 94 AccessJwt: tok.AccessJwt, 95 RefreshJwt: tok.RefreshJwt, 96 }, nil 97} 98 99func (s *Server) handleComAtprotoServerCreateInviteCode(ctx context.Context, body *comatprototypes.ServerCreateInviteCode_Input) (*comatprototypes.ServerCreateInviteCode_Output, error) { 100 u, err := s.getUser(ctx) 101 if err != nil { 102 return nil, err 103 } 104 105 _ = u 106 107 return nil, fmt.Errorf("invite codes not currently supported") 108} 109 110func (s *Server) handleComAtprotoServerRequestAccountDelete(ctx context.Context) error { 111 panic("not yet implemented") 112} 113 114func (s *Server) handleComAtprotoServerDeleteAccount(ctx context.Context, body *comatprototypes.ServerDeleteAccount_Input) error { 115 panic("not yet implemented") 116} 117 118func (s *Server) handleComAtprotoServerRequestPasswordReset(ctx context.Context, body *comatprototypes.ServerRequestPasswordReset_Input) error { 119 panic("not yet implemented") 120} 121 122func (s *Server) handleComAtprotoServerResetPassword(ctx context.Context, body *comatprototypes.ServerResetPassword_Input) error { 123 panic("not yet implemented") 124} 125 126func (s *Server) handleComAtprotoRepoUploadBlob(ctx context.Context, r io.Reader, contentType string) (*comatprototypes.RepoUploadBlob_Output, error) { 127 panic("not yet implemented") 128} 129 130func (s *Server) handleComAtprotoIdentityResolveHandle(ctx context.Context, handle string) (*comatprototypes.IdentityResolveHandle_Output, error) { 131 if handle == "" { 132 return &comatprototypes.IdentityResolveHandle_Output{Did: s.signingKey.Public().DID()}, nil 133 } 134 u, err := s.lookupUserByHandle(ctx, handle) 135 if err != nil { 136 return nil, err 137 } 138 139 return &comatprototypes.IdentityResolveHandle_Output{Did: u.Did}, nil 140} 141 142func (s *Server) handleComAtprotoRepoApplyWrites(ctx context.Context, body *comatprototypes.RepoApplyWrites_Input) error { 143 u, err := s.getUser(ctx) 144 if err != nil { 145 return err 146 } 147 148 if u.Did != body.Repo { 149 return fmt.Errorf("writes for non-user actors not supported (DID mismatch)") 150 } 151 152 return s.repoman.BatchWrite(ctx, u.ID, body.Writes) 153} 154 155func (s *Server) handleComAtprotoRepoCreateRecord(ctx context.Context, input *comatprototypes.RepoCreateRecord_Input) (*comatprototypes.RepoCreateRecord_Output, error) { 156 u, err := s.getUser(ctx) 157 if err != nil { 158 return nil, fmt.Errorf("get user: %w", err) 159 } 160 161 rpath, recid, err := s.repoman.CreateRecord(ctx, u.ID, input.Collection, input.Record.Val) 162 if err != nil { 163 return nil, fmt.Errorf("record create: %w", err) 164 } 165 166 return &comatprototypes.RepoCreateRecord_Output{ 167 Uri: "at://" + u.Did + "/" + rpath, 168 Cid: recid.String(), 169 }, nil 170} 171 172func (s *Server) handleComAtprotoRepoDeleteRecord(ctx context.Context, input *comatprototypes.RepoDeleteRecord_Input) error { 173 u, err := s.getUser(ctx) 174 if err != nil { 175 return err 176 } 177 178 if u.Did != input.Repo { 179 return fmt.Errorf("specified DID did not match authed user") 180 } 181 182 return s.repoman.DeleteRecord(ctx, u.ID, input.Collection, input.Rkey) 183} 184 185func (s *Server) handleComAtprotoRepoGetRecord(ctx context.Context, c string, collection string, repo string, rkey string) (*comatprototypes.RepoGetRecord_Output, error) { 186 targetUser, err := s.lookupUser(ctx, repo) 187 if err != nil { 188 return nil, err 189 } 190 191 var maybeCid cid.Cid 192 if c != "" { 193 cc, err := cid.Decode(c) 194 if err != nil { 195 return nil, err 196 } 197 maybeCid = cc 198 } 199 200 reccid, rec, err := s.repoman.GetRecord(ctx, targetUser.ID, collection, rkey, maybeCid) 201 if err != nil { 202 return nil, fmt.Errorf("repoman GetRecord: %w", err) 203 } 204 205 ccstr := reccid.String() 206 return &comatprototypes.RepoGetRecord_Output{ 207 Cid: &ccstr, 208 Uri: "at://" + targetUser.Did + "/" + collection + "/" + rkey, 209 Value: &lexutil.LexiconTypeDecoder{Val: rec}, 210 }, nil 211} 212 213func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context, collection string, cursor string, limit int, repo string, reverse *bool, rkeyEnd string, rkeyStart string) (*comatprototypes.RepoListRecords_Output, error) { 214 panic("not yet implemented") 215} 216 217func (s *Server) handleComAtprotoRepoPutRecord(ctx context.Context, input *comatprototypes.RepoPutRecord_Input) (*comatprototypes.RepoPutRecord_Output, error) { 218 panic("not yet implemented") 219} 220 221func (s *Server) handleComAtprotoServerDescribeServer(ctx context.Context) (*comatprototypes.ServerDescribeServer_Output, error) { 222 invcode := false 223 return &comatprototypes.ServerDescribeServer_Output{ 224 InviteCodeRequired: &invcode, 225 AvailableUserDomains: []string{ 226 s.handleSuffix, 227 }, 228 Links: &comatprototypes.ServerDescribeServer_Links{}, 229 }, nil 230} 231 232var ErrInvalidUsernameOrPassword = fmt.Errorf("invalid username or password") 233 234func (s *Server) handleComAtprotoServerCreateSession(ctx context.Context, body *comatprototypes.ServerCreateSession_Input) (*comatprototypes.ServerCreateSession_Output, error) { 235 u, err := s.lookupUserByHandle(ctx, body.Identifier) 236 if err != nil { 237 return nil, err 238 } 239 240 if body.Password != u.Password { 241 return nil, ErrInvalidUsernameOrPassword 242 } 243 244 tok, err := s.createAuthTokenForUser(ctx, body.Identifier, u.Did) 245 if err != nil { 246 return nil, err 247 } 248 249 return &comatprototypes.ServerCreateSession_Output{ 250 Handle: body.Identifier, 251 Did: u.Did, 252 AccessJwt: tok.AccessJwt, 253 RefreshJwt: tok.RefreshJwt, 254 }, nil 255} 256 257func (s *Server) handleComAtprotoServerDeleteSession(ctx context.Context) error { 258 panic("not yet implemented") 259} 260 261func (s *Server) handleComAtprotoServerGetSession(ctx context.Context) (*comatprototypes.ServerGetSession_Output, error) { 262 u, err := s.getUser(ctx) 263 if err != nil { 264 return nil, err 265 } 266 267 return &comatprototypes.ServerGetSession_Output{ 268 Handle: u.Handle, 269 Did: u.Did, 270 }, nil 271} 272 273func (s *Server) handleComAtprotoServerRefreshSession(ctx context.Context) (*comatprototypes.ServerRefreshSession_Output, error) { 274 u, err := s.getUser(ctx) 275 if err != nil { 276 return nil, err 277 } 278 279 scope, ok := ctx.Value("authScope").(string) 280 if !ok { 281 return nil, fmt.Errorf("scope not present in refresh token") 282 } 283 284 if scope != "com.atproto.refresh" { 285 return nil, fmt.Errorf("auth token did not have refresh scope") 286 } 287 288 tok, ok := ctx.Value("token").(*jwt.Token) 289 if !ok { 290 return nil, fmt.Errorf("internal auth error: token not set post auth check") 291 } 292 293 if err := s.invalidateToken(ctx, u, tok); err != nil { 294 return nil, err 295 } 296 297 outTok, err := s.createAuthTokenForUser(ctx, u.Handle, u.Did) 298 if err != nil { 299 return nil, err 300 } 301 302 return &comatprototypes.ServerRefreshSession_Output{ 303 Handle: u.Handle, 304 Did: u.Did, 305 AccessJwt: outTok.AccessJwt, 306 RefreshJwt: outTok.RefreshJwt, 307 }, nil 308 309} 310 311func (s *Server) handleComAtprotoSyncUpdateRepo(ctx context.Context, r io.Reader) error { 312 panic("not yet implemented") 313} 314 315func (s *Server) handleComAtprotoSyncGetCheckout(ctx context.Context, did string) (io.Reader, error) { 316 panic("not yet implemented") 317} 318 319func (s *Server) handleComAtprotoSyncGetHead(ctx context.Context, did string) (*comatprototypes.SyncGetHead_Output, error) { 320 user, err := s.lookupUserByDid(ctx, did) 321 if err != nil { 322 return nil, err 323 } 324 325 root, err := s.repoman.GetRepoRoot(ctx, user.ID) 326 if err != nil { 327 return nil, err 328 } 329 330 return &comatprototypes.SyncGetHead_Output{ 331 Root: root.String(), 332 }, nil 333} 334 335func (s *Server) handleComAtprotoSyncGetRecord(ctx context.Context, collection string, commit string, did string, rkey string) (io.Reader, error) { 336 panic("not yet implemented") 337} 338 339func (s *Server) handleComAtprotoSyncGetRepo(ctx context.Context, did string, since string) (io.Reader, error) { 340 targetUser, err := s.lookupUser(ctx, did) 341 if err != nil { 342 return nil, err 343 } 344 345 buf := new(bytes.Buffer) 346 if err := s.repoman.ReadRepo(ctx, targetUser.ID, since, buf); err != nil { 347 return nil, err 348 } 349 350 return buf, nil 351} 352 353func (s *Server) handleComAtprotoSyncGetBlocks(ctx context.Context, cids []string, did string) (io.Reader, error) { 354 panic("nyi") 355} 356 357func (s *Server) handleComAtprotoSyncNotifyOfUpdate(ctx context.Context, body *comatprototypes.SyncNotifyOfUpdate_Input) error { 358 panic("nyi") 359} 360 361func (s *Server) handleComAtprotoSyncRequestCrawl(ctx context.Context, body *comatprototypes.SyncRequestCrawl_Input) error { 362 panic("nyi") 363} 364 365func (s *Server) handleComAtprotoSyncGetBlob(ctx context.Context, cid string, did string) (io.Reader, error) { 366 panic("nyi") 367} 368 369func (s *Server) handleComAtprotoSyncListBlobs(ctx context.Context, cursor string, did string, limit int, since string) (*comatprototypes.SyncListBlobs_Output, error) { 370 panic("nyi") 371} 372 373func (s *Server) handleComAtprotoIdentityUpdateHandle(ctx context.Context, body *comatprototypes.IdentityUpdateHandle_Input) error { 374 if err := s.validateHandle(body.Handle); err != nil { 375 return err 376 } 377 378 u, err := s.getUser(ctx) 379 if err != nil { 380 return err 381 } 382 383 return s.UpdateUserHandle(ctx, u, body.Handle) 384} 385 386func (s *Server) handleComAtprotoModerationCreateReport(ctx context.Context, body *comatprototypes.ModerationCreateReport_Input) (*comatprototypes.ModerationCreateReport_Output, error) { 387 panic("nyi") 388} 389 390func (s *Server) handleComAtprotoRepoDescribeRepo(ctx context.Context, repo string) (*comatprototypes.RepoDescribeRepo_Output, error) { 391 panic("nyi") 392} 393 394func (s *Server) handleComAtprotoAdminDisableInviteCodes(ctx context.Context, body *comatprototypes.AdminDisableInviteCodes_Input) error { 395 panic("nyi") 396} 397 398func (s *Server) handleComAtprotoAdminGetInviteCodes(ctx context.Context, cursor string, limit int, sort string) (*comatprototypes.AdminGetInviteCodes_Output, error) { 399 panic("nyi") 400} 401 402func (s *Server) handleComAtprotoLabelQueryLabels(ctx context.Context, cursor string, limit int, sources []string, uriPatterns []string) (*comatprototypes.LabelQueryLabels_Output, error) { 403 panic("nyi") 404} 405 406func (s *Server) handleComAtprotoServerCreateInviteCodes(ctx context.Context, body *comatprototypes.ServerCreateInviteCodes_Input) (*comatprototypes.ServerCreateInviteCodes_Output, error) { 407 panic("nyi") 408} 409 410func (s *Server) handleComAtprotoServerGetAccountInviteCodes(ctx context.Context, createAvailable bool, includeUsed bool) (*comatprototypes.ServerGetAccountInviteCodes_Output, error) { 411 panic("nyi") 412} 413 414func (s *Server) handleComAtprotoSyncListRepos(ctx context.Context, cursor string, limit int) (*comatprototypes.SyncListRepos_Output, error) { 415 panic("nyi") 416} 417 418func (s *Server) handleComAtprotoAdminUpdateAccountEmail(ctx context.Context, body *comatprototypes.AdminUpdateAccountEmail_Input) error { 419 panic("nyi") 420} 421 422func (s *Server) handleComAtprotoAdminUpdateAccountHandle(ctx context.Context, body *comatprototypes.AdminUpdateAccountHandle_Input) error { 423 panic("nyi") 424} 425 426func (s *Server) handleComAtprotoServerCreateAppPassword(ctx context.Context, body *comatprototypes.ServerCreateAppPassword_Input) (*comatprototypes.ServerCreateAppPassword_AppPassword, error) { 427 panic("nyi") 428} 429 430func (s *Server) handleComAtprotoServerListAppPasswords(ctx context.Context) (*comatprototypes.ServerListAppPasswords_Output, error) { 431 panic("nyi") 432} 433 434func (s *Server) handleComAtprotoServerRevokeAppPassword(ctx context.Context, body *comatprototypes.ServerRevokeAppPassword_Input) error { 435 panic("nyi") 436} 437 438func (s *Server) handleComAtprotoAdminDisableAccountInvites(ctx context.Context, body *comatprototypes.AdminDisableAccountInvites_Input) error { 439 panic("nyi") 440} 441 442func (s *Server) handleComAtprotoAdminEnableAccountInvites(ctx context.Context, body *comatprototypes.AdminEnableAccountInvites_Input) error { 443 panic("nyi") 444} 445 446func (s *Server) handleComAtprotoAdminSendEmail(ctx context.Context, body *comatprototypes.AdminSendEmail_Input) (*comatprototypes.AdminSendEmail_Output, error) { 447 panic("nyi") 448} 449 450func (s *Server) handleComAtprotoSyncGetLatestCommit(ctx context.Context, did string) (*comatprototypes.SyncGetLatestCommit_Output, error) { 451 panic("nyi") 452} 453 454func (s *Server) handleComAtprotoAdminGetAccountInfo(ctx context.Context, did string) (*comatprototypes.AdminDefs_AccountView, error) { 455 panic("nyi") 456} 457func (s *Server) handleComAtprotoAdminGetSubjectStatus(ctx context.Context, blob string, did string, uri string) (*comatprototypes.AdminGetSubjectStatus_Output, error) { 458 panic("nyi") 459} 460 461func (s *Server) handleComAtprotoAdminUpdateSubjectStatus(ctx context.Context, body *comatprototypes.AdminUpdateSubjectStatus_Input) (*comatprototypes.AdminUpdateSubjectStatus_Output, error) { 462 panic("nyi") 463} 464func (s *Server) handleComAtprotoServerConfirmEmail(ctx context.Context, body *comatprototypes.ServerConfirmEmail_Input) error { 465 panic("nyi") 466} 467func (s *Server) handleComAtprotoServerRequestEmailConfirmation(ctx context.Context) error { 468 panic("nyi") 469} 470func (s *Server) handleComAtprotoServerRequestEmailUpdate(ctx context.Context) (*comatprototypes.ServerRequestEmailUpdate_Output, error) { 471 panic("nyi") 472} 473func (s *Server) handleComAtprotoServerReserveSigningKey(ctx context.Context, body *comatprototypes.ServerReserveSigningKey_Input) (*comatprototypes.ServerReserveSigningKey_Output, error) { 474 panic("nyi") 475} 476func (s *Server) handleComAtprotoServerUpdateEmail(ctx context.Context, body *comatprototypes.ServerUpdateEmail_Input) error { 477 panic("nyi") 478} 479func (s *Server) handleComAtprotoTempFetchLabels(ctx context.Context, limit int, since *int) (*comatprototypes.TempFetchLabels_Output, error) { 480 panic("nyi") 481}