diff --git a/LICENSE b/LICENSE index de46a64..8e596cc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2025 me@haileyok.com +Copyright (c) 2026 Patrick Dewey Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/models/models.go b/models/models.go index 6cf6520..aa01613 100644 --- a/models/models.go +++ b/models/models.go @@ -7,37 +7,16 @@ import ( "github.com/bluesky-social/indigo/atproto/atcrypto" ) -type TwoFactorType string - -var ( - TwoFactorTypeNone = TwoFactorType("none") - TwoFactorTypeEmail = TwoFactorType("email") -) - type Repo struct { - Did string `gorm:"primaryKey"` - CreatedAt time.Time - Email string `gorm:"uniqueIndex"` - EmailConfirmedAt *time.Time - EmailVerificationCode *string - EmailVerificationCodeExpiresAt *time.Time - EmailUpdateCode *string - EmailUpdateCodeExpiresAt *time.Time - PasswordResetCode *string - PasswordResetCodeExpiresAt *time.Time - PlcOperationCode *string - PlcOperationCodeExpiresAt *time.Time - AccountDeleteCode *string - AccountDeleteCodeExpiresAt *time.Time - Password string - SigningKey []byte - Rev string - Root []byte - Preferences []byte - Deactivated bool - TwoFactorCode *string - TwoFactorCodeExpiresAt *time.Time - TwoFactorType TwoFactorType `gorm:"default:none"` + Did string `gorm:"primaryKey"` + CreatedAt time.Time + Email string `gorm:"uniqueIndex"` + Password string + SigningKey []byte + Rev string + Root []byte + Preferences []byte + Deactivated bool } func (r *Repo) SignFor(ctx context.Context, did string, msg []byte) ([]byte, error) { @@ -76,12 +55,6 @@ type RepoActor struct { Actor } -type InviteCode struct { - Code string `gorm:"primaryKey"` - Did string `gorm:"index"` - RemainingUseCount int -} - type Token struct { Token string `gorm:"primaryKey"` Did string `gorm:"index"` diff --git a/oauth/dpop/nonce.go b/oauth/dpop/nonce.go index 29605c3..627d032 100644 --- a/oauth/dpop/nonce.go +++ b/oauth/dpop/nonce.go @@ -41,7 +41,9 @@ func NewNonce(args NonceArgs) *Nonce { if args.Secret == nil { args.Secret = helpers.RandomBytes(constants.NonceSecretByteLength) - args.OnSecretCreated(args.Secret) + if args.OnSecretCreated != nil { + args.OnSecretCreated(args.Secret) + } } n := &Nonce{ diff --git a/recording_blockstore/recording_blockstore.go b/recording_blockstore/recording_blockstore.go deleted file mode 100644 index 954a965..0000000 --- a/recording_blockstore/recording_blockstore.go +++ /dev/null @@ -1,85 +0,0 @@ -package recording_blockstore - -import ( - "context" - "fmt" - - blockformat "github.com/ipfs/go-block-format" - "github.com/ipfs/go-cid" - blockstore "github.com/ipfs/go-ipfs-blockstore" -) - -type RecordingBlockstore struct { - base blockstore.Blockstore - - inserts map[cid.Cid]blockformat.Block - reads map[cid.Cid]blockformat.Block -} - -func New(base blockstore.Blockstore) *RecordingBlockstore { - return &RecordingBlockstore{ - base: base, - inserts: make(map[cid.Cid]blockformat.Block), - reads: make(map[cid.Cid]blockformat.Block), - } -} - -func (bs *RecordingBlockstore) Has(ctx context.Context, c cid.Cid) (bool, error) { - return bs.base.Has(ctx, c) -} - -func (bs *RecordingBlockstore) Get(ctx context.Context, c cid.Cid) (blockformat.Block, error) { - b, err := bs.base.Get(ctx, c) - if err != nil { - return nil, err - } - bs.reads[c] = b - return b, nil -} - -func (bs *RecordingBlockstore) GetSize(ctx context.Context, c cid.Cid) (int, error) { - return bs.base.GetSize(ctx, c) -} - -func (bs *RecordingBlockstore) DeleteBlock(ctx context.Context, c cid.Cid) error { - return bs.base.DeleteBlock(ctx, c) -} - -func (bs *RecordingBlockstore) Put(ctx context.Context, block blockformat.Block) error { - if err := bs.base.Put(ctx, block); err != nil { - return err - } - bs.inserts[block.Cid()] = block - return nil -} - -func (bs *RecordingBlockstore) PutMany(ctx context.Context, blocks []blockformat.Block) error { - if err := bs.base.PutMany(ctx, blocks); err != nil { - return err - } - - for _, b := range blocks { - bs.inserts[b.Cid()] = b - } - - return nil -} - -func (bs *RecordingBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { - return nil, fmt.Errorf("iteration not allowed on recording blockstore") -} - -func (bs *RecordingBlockstore) HashOnRead(enabled bool) { -} - -func (bs *RecordingBlockstore) GetWriteLog() map[cid.Cid]blockformat.Block { - return bs.inserts -} - -func (bs *RecordingBlockstore) GetReadLog() []blockformat.Block { - var blocks []blockformat.Block - for _, b := range bs.reads { - blocks = append(blocks, b) - } - return blocks -} diff --git a/server/handle_identity_request_plc_operation.go b/server/handle_identity_request_plc_operation.go index 7cd04d9..4d83e24 100644 --- a/server/handle_identity_request_plc_operation.go +++ b/server/handle_identity_request_plc_operation.go @@ -1,32 +1,9 @@ package server -import ( - "fmt" - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) +import "github.com/labstack/echo/v4" +// handleIdentityRequestPlcOperationSignature is a stub since chrysalis doesn't +// support email-based PLC operation tokens. func (s *Server) handleIdentityRequestPlcOperationSignature(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleIdentityRequestPlcOperationSignature") - - urepo := e.Get("repo").(*models.RepoActor) - - code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) - eat := time.Now().Add(10 * time.Minute).UTC() - - if err := s.db.Exec(ctx, "UPDATE repos SET plc_operation_code = ?, plc_operation_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil { - logger.Error("error updating user", "error", err) - return helpers.ServerError(e, nil) - } - - if err := s.sendPlcTokenReset(urepo.Email, urepo.Handle, code); err != nil { - logger.Error("error sending mail", "error", err) - return helpers.ServerError(e, nil) - } - return e.NoContent(200) -} +} \ No newline at end of file diff --git a/server/handle_identity_sign_plc_operation.go b/server/handle_identity_sign_plc_operation.go index 4eda042..2e98a26 100644 --- a/server/handle_identity_sign_plc_operation.go +++ b/server/handle_identity_sign_plc_operation.go @@ -3,7 +3,6 @@ package server import ( "context" "strings" - "time" "github.com/bluesky-social/indigo/atproto/atcrypto" "tangled.org/pdewey.com/chrysalis/identity" @@ -14,10 +13,9 @@ import ( ) type ComAtprotoSignPlcOperationRequest struct { - Token string `json:"token"` - VerificationMethods *map[string]string `json:"verificationMethods"` - RotationKeys *[]string `json:"rotationKeys"` - AlsoKnownAs *[]string `json:"alsoKnownAs"` + VerificationMethods *map[string]string `json:"verificationMethods"` + RotationKeys *[]string `json:"rotationKeys"` + AlsoKnownAs *[]string `json:"alsoKnownAs"` Services *map[string]identity.OperationService `json:"services"` } @@ -40,18 +38,6 @@ func (s *Server) handleSignPlcOperation(e echo.Context) error { return helpers.InputError(e, nil) } - if repo.PlcOperationCode == nil || repo.PlcOperationCodeExpiresAt == nil { - return helpers.InputError(e, new("InvalidToken")) - } - - if *repo.PlcOperationCode != req.Token { - return helpers.InvalidTokenError(e) - } - - if time.Now().UTC().After(*repo.PlcOperationCodeExpiresAt) { - return helpers.ExpiredTokenError(e) - } - ctx := context.WithValue(e.Request().Context(), "skip-cache", true) log, err := identity.FetchDidAuditLog(ctx, s.http, s.plcURL, repo.Repo.Did) if err != nil { @@ -93,12 +79,7 @@ func (s *Server) handleSignPlcOperation(e echo.Context) error { return helpers.ServerError(e, nil) } - if err := s.db.Exec(ctx, "UPDATE repos SET plc_operation_code = NULL, plc_operation_code_expires_at = NULL WHERE did = ?", nil, repo.Repo.Did).Error; err != nil { - logger.Error("error updating repo", "error", err) - return helpers.ServerError(e, nil) - } - return e.JSON(200, ComAtprotoSignPlcOperationResponse{ Operation: op, }) -} +} \ No newline at end of file diff --git a/server/handle_import_repo.go b/server/handle_import_repo.go deleted file mode 100644 index e126039..0000000 --- a/server/handle_import_repo.go +++ /dev/null @@ -1,117 +0,0 @@ -package server - -import ( - "bytes" - "context" - "io" - "slices" - "strings" - - "github.com/bluesky-social/indigo/atproto/syntax" - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - blocks "github.com/ipfs/go-block-format" - "github.com/ipfs/go-cid" - "github.com/ipld/go-car" - "github.com/labstack/echo/v4" -) - -func (s *Server) handleRepoImportRepo(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleImportRepo") - - urepo := e.Get("repo").(*models.RepoActor) - - b, err := io.ReadAll(e.Request().Body) - if err != nil { - logger.Error("could not read bytes in import request", "error", err) - return helpers.ServerError(e, nil) - } - - bs := s.getBlockstore(urepo.Repo.Did) - - cs, err := car.NewCarReader(bytes.NewReader(b)) - if err != nil { - logger.Error("could not read car in import request", "error", err) - return helpers.ServerError(e, nil) - } - - orderedBlocks := []blocks.Block{} - currBlock, err := cs.Next() - if err != nil { - logger.Error("could not get first block from car", "error", err) - return helpers.ServerError(e, nil) - } - currBlockCt := 1 - - for currBlock != nil { - logger.Info("someone is importing their repo", "block", currBlockCt) - orderedBlocks = append(orderedBlocks, currBlock) - next, _ := cs.Next() - currBlock = next - currBlockCt++ - } - - slices.Reverse(orderedBlocks) - - if err := bs.PutMany(context.TODO(), orderedBlocks); err != nil { - logger.Error("could not insert blocks", "error", err) - return helpers.ServerError(e, nil) - } - - r, err := openRepo(context.TODO(), bs, cs.Header.Roots[0], urepo.Repo.Did) - if err != nil { - logger.Error("could not open repo", "error", err) - return helpers.ServerError(e, nil) - } - - tx := s.db.Begin(ctx) - - clock := syntax.NewTIDClock(0) - - if err := r.MST.Walk(func(key []byte, cid cid.Cid) error { - pts := strings.Split(string(key), "/") - nsid := pts[0] - rkey := pts[1] - cidStr := cid.String() - b, err := bs.Get(context.TODO(), cid) - if err != nil { - logger.Error("record bytes don't exist in blockstore", "error", err) - return helpers.ServerError(e, nil) - } - - rec := models.Record{ - Did: urepo.Repo.Did, - CreatedAt: clock.Next().String(), - Nsid: nsid, - Rkey: rkey, - Cid: cidStr, - Value: b.RawData(), - } - - if err := tx.Save(rec).Error; err != nil { - return err - } - - return nil - }); err != nil { - tx.Rollback() - logger.Error("record bytes don't exist in blockstore", "error", err) - return helpers.ServerError(e, nil) - } - - tx.Commit() - - root, rev, err := commitRepo(context.TODO(), bs, r, urepo.Repo.SigningKey) - if err != nil { - logger.Error("error committing", "error", err) - return helpers.ServerError(e, nil) - } - - if err := s.UpdateRepo(context.TODO(), urepo.Repo.Did, root, rev); err != nil { - logger.Error("error updating repo after commit", "error", err) - return helpers.ServerError(e, nil) - } - - return nil -} diff --git a/server/handle_robots.go b/server/handle_robots.go deleted file mode 100644 index 9ee73ea..0000000 --- a/server/handle_robots.go +++ /dev/null @@ -1,7 +0,0 @@ -package server - -import "github.com/labstack/echo/v4" - -func (s *Server) handleRobots(e echo.Context) error { - return e.String(200, "# Beep boop beep boop\n\n# Crawl me 🥺\nUser-agent: *\nAllow: /") -} diff --git a/server/handle_server_confirm_email.go b/server/handle_server_confirm_email.go deleted file mode 100644 index bff5551..0000000 --- a/server/handle_server_confirm_email.go +++ /dev/null @@ -1,52 +0,0 @@ -package server - -import ( - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -type ComAtprotoServerConfirmEmailRequest struct { - Email string `json:"email" validate:"required"` - Token string `json:"token" validate:"required"` -} - -func (s *Server) handleServerConfirmEmail(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerConfirmEmail") - - urepo := e.Get("repo").(*models.RepoActor) - - var req ComAtprotoServerConfirmEmailRequest - if err := e.Bind(&req); err != nil { - logger.Error("error binding", "error", err) - return helpers.ServerError(e, nil) - } - - if err := e.Validate(req); err != nil { - return helpers.InputError(e, nil) - } - - if urepo.EmailVerificationCode == nil || urepo.EmailVerificationCodeExpiresAt == nil { - return helpers.ExpiredTokenError(e) - } - - if *urepo.EmailVerificationCode != req.Token { - return helpers.InputError(e, new("InvalidToken")) - } - - if time.Now().UTC().After(*urepo.EmailVerificationCodeExpiresAt) { - return helpers.ExpiredTokenError(e) - } - - now := time.Now().UTC() - - if err := s.db.Exec(ctx, "UPDATE repos SET email_verification_code = NULL, email_verification_code_expires_at = NULL, email_confirmed_at = ? WHERE did = ?", nil, now, urepo.Repo.Did).Error; err != nil { - logger.Error("error updating user", "error", err) - return helpers.ServerError(e, nil) - } - - return e.NoContent(200) -} diff --git a/server/handle_server_create_account.go b/server/handle_server_create_account.go index 8c0532e..f8f331c 100644 --- a/server/handle_server_create_account.go +++ b/server/handle_server_create_account.go @@ -3,7 +3,6 @@ package server import ( "context" "errors" - "fmt" "strings" "time" @@ -107,25 +106,6 @@ func (s *Server) handleCreateAccount(e echo.Context) error { return helpers.InputError(e, new("HandleNotAvailable")) } - var ic models.InviteCode - if s.config.RequireInvite { - if strings.TrimSpace(request.InviteCode) == "" { - return helpers.InputError(e, new("InvalidInviteCode")) - } - - if err := s.db.Raw(ctx, "SELECT * FROM invite_codes WHERE code = ?", nil, request.InviteCode).Scan(&ic).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return helpers.InputError(e, new("InvalidInviteCode")) - } - logger.Error("error getting invite code from db", "error", err) - return helpers.ServerError(e, nil) - } - - if ic.RemainingUseCount < 1 { - return helpers.InputError(e, new("InvalidInviteCode")) - } - } - // see if the email is already taken existingRepo, err := s.getRepoByEmail(ctx, request.Email) if err != nil && err != gorm.ErrRecordNotFound { @@ -189,12 +169,11 @@ func (s *Server) handleCreateAccount(e echo.Context) error { } urepo := models.Repo{ - Did: signupDid, - CreatedAt: time.Now(), - Email: request.Email, - EmailVerificationCode: new(fmt.Sprintf("%s-%s", helpers.RandomVarchar(6), helpers.RandomVarchar(6))), - Password: string(hashed), - SigningKey: k.Bytes(), + Did: signupDid, + CreatedAt: time.Now(), + Email: request.Email, + Password: string(hashed), + SigningKey: k.Bytes(), } if actor == nil { @@ -251,28 +230,12 @@ func (s *Server) handleCreateAccount(e echo.Context) error { }) } - if s.config.RequireInvite { - if err := s.db.Raw(ctx, "UPDATE invite_codes SET remaining_use_count = remaining_use_count - 1 WHERE code = ?", nil, request.InviteCode).Scan(&ic).Error; err != nil { - logger.Error("error decrementing use count", "error", err) - return helpers.ServerError(e, nil) - } - } - sess, err := s.createSession(ctx, &urepo) if err != nil { logger.Error("error creating new session", "error", err) return helpers.ServerError(e, nil) } - go func() { - if err := s.sendEmailVerification(urepo.Email, actor.Handle, *urepo.EmailVerificationCode); err != nil { - logger.Error("error sending email verification email", "error", err) - } - if err := s.sendWelcomeMail(urepo.Email, actor.Handle); err != nil { - logger.Error("error sending welcome email", "error", err) - } - }() - return e.JSON(200, ComAtprotoServerCreateAccountResponse{ AccessJwt: sess.AccessToken, RefreshJwt: sess.RefreshToken, diff --git a/server/handle_server_create_invite_code.go b/server/handle_server_create_invite_code.go deleted file mode 100644 index 1b5177c..0000000 --- a/server/handle_server_create_invite_code.go +++ /dev/null @@ -1,55 +0,0 @@ -package server - -import ( - "github.com/google/uuid" - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -type ComAtprotoServerCreateInviteCodeRequest struct { - UseCount int `json:"useCount" validate:"required"` - ForAccount *string `json:"forAccount,omitempty"` -} - -type ComAtprotoServerCreateInviteCodeResponse struct { - Code string `json:"code"` -} - -func (s *Server) handleCreateInviteCode(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerCreateInviteCode") - - var req ComAtprotoServerCreateInviteCodeRequest - if err := e.Bind(&req); err != nil { - logger.Error("error binding", "error", err) - return helpers.ServerError(e, nil) - } - - if err := e.Validate(req); err != nil { - logger.Error("error validating", "error", err) - return helpers.InputError(e, nil) - } - - ic := uuid.NewString() - - var acc string - if req.ForAccount == nil { - acc = "admin" - } else { - acc = *req.ForAccount - } - - if err := s.db.Create(ctx, &models.InviteCode{ - Code: ic, - Did: acc, - RemainingUseCount: req.UseCount, - }, nil).Error; err != nil { - logger.Error("error creating invite code", "error", err) - return helpers.ServerError(e, nil) - } - - return e.JSON(200, ComAtprotoServerCreateInviteCodeResponse{ - Code: ic, - }) -} diff --git a/server/handle_server_create_invite_codes.go b/server/handle_server_create_invite_codes.go deleted file mode 100644 index 1f3085e..0000000 --- a/server/handle_server_create_invite_codes.go +++ /dev/null @@ -1,72 +0,0 @@ -package server - -import ( -"github.com/google/uuid" - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -type ComAtprotoServerCreateInviteCodesRequest struct { - CodeCount *int `json:"codeCount,omitempty"` - UseCount int `json:"useCount" validate:"required"` - ForAccounts *[]string `json:"forAccounts,omitempty"` -} - -type ComAtprotoServerCreateInviteCodesResponse []ComAtprotoServerCreateInviteCodesItem - -type ComAtprotoServerCreateInviteCodesItem struct { - Account string `json:"account"` - Codes []string `json:"codes"` -} - -func (s *Server) handleCreateInviteCodes(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerCreateInviteCodes") - - var req ComAtprotoServerCreateInviteCodesRequest - if err := e.Bind(&req); err != nil { - logger.Error("error binding", "error", err) - return helpers.ServerError(e, nil) - } - - if err := e.Validate(req); err != nil { - logger.Error("error validating", "error", err) - return helpers.InputError(e, nil) - } - - if req.CodeCount == nil { - req.CodeCount = new(1) - } - - if req.ForAccounts == nil { - req.ForAccounts = new([]string{"admin"}) - } - - codes := make([]ComAtprotoServerCreateInviteCodesItem, 0, len(*req.ForAccounts)) - - for _, did := range *req.ForAccounts { - ics := make([]string, 0, *req.CodeCount) - - for range *req.CodeCount { - ic := uuid.NewString() - ics = append(ics, ic) - - if err := s.db.Create(ctx, &models.InviteCode{ - Code: ic, - Did: did, - RemainingUseCount: req.UseCount, - }, nil).Error; err != nil { - logger.Error("error creating invite code", "error", err) - return helpers.ServerError(e, nil) - } - } - - codes = append(codes, ComAtprotoServerCreateInviteCodesItem{ - Account: did, - Codes: ics, - }) - } - - return e.JSON(200, codes) -} diff --git a/server/handle_server_create_session.go b/server/handle_server_create_session.go index 854a2af..5be898e 100644 --- a/server/handle_server_create_session.go +++ b/server/handle_server_create_session.go @@ -1,11 +1,8 @@ package server import ( - "context" "errors" - "fmt" "strings" - "time" "github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/pdewey.com/chrysalis/internal/helpers" @@ -16,21 +13,18 @@ import ( ) type ComAtprotoServerCreateSessionRequest struct { - Identifier string `json:"identifier" validate:"required"` - Password string `json:"password" validate:"required"` - AuthFactorToken *string `json:"authFactorToken,omitempty"` + Identifier string `json:"identifier" validate:"required"` + Password string `json:"password" validate:"required"` } type ComAtprotoServerCreateSessionResponse struct { - AccessJwt string `json:"accessJwt"` - RefreshJwt string `json:"refreshJwt"` - Handle string `json:"handle"` - Did string `json:"did"` - Email string `json:"email"` - EmailConfirmed bool `json:"emailConfirmed"` - EmailAuthFactor bool `json:"emailAuthFactor"` - Active bool `json:"active"` - Status *string `json:"status,omitempty"` + AccessJwt string `json:"accessJwt"` + RefreshJwt string `json:"refreshJwt"` + Handle string `json:"handle"` + Did string `json:"did"` + Email string `json:"email"` + Active bool `json:"active"` + Status *string `json:"status,omitempty"` } func (s *Server) handleCreateSession(e echo.Context) error { @@ -93,38 +87,6 @@ func (s *Server) handleCreateSession(e echo.Context) error { return helpers.InputError(e, new("InvalidRequest")) } - // if repo requires 2FA token and one hasn't been provided, return error prompting for one - if repo.TwoFactorType != models.TwoFactorTypeNone && (req.AuthFactorToken == nil || *req.AuthFactorToken == "") { - err = s.createAndSendTwoFactorCode(ctx, repo) - if err != nil { - logger.Error("sending 2FA code", "error", err) - return helpers.ServerError(e, nil) - } - - return helpers.InputError(e, new("AuthFactorTokenRequired")) - } - - // if 2FA is required, now check that the one provided is valid - if repo.TwoFactorType != models.TwoFactorTypeNone { - if repo.TwoFactorCode == nil || repo.TwoFactorCodeExpiresAt == nil { - err = s.createAndSendTwoFactorCode(ctx, repo) - if err != nil { - logger.Error("sending 2FA code", "error", err) - return helpers.ServerError(e, nil) - } - - return helpers.InputError(e, new("AuthFactorTokenRequired")) - } - - if *repo.TwoFactorCode != *req.AuthFactorToken { - return helpers.InvalidTokenError(e) - } - - if time.Now().UTC().After(*repo.TwoFactorCodeExpiresAt) { - return helpers.ExpiredTokenError(e) - } - } - sess, err := s.createSession(ctx, &repo.Repo) if err != nil { logger.Error("error creating session", "error", err) @@ -132,32 +94,12 @@ func (s *Server) handleCreateSession(e echo.Context) error { } return e.JSON(200, ComAtprotoServerCreateSessionResponse{ - AccessJwt: sess.AccessToken, - RefreshJwt: sess.RefreshToken, - Handle: repo.Handle, - Did: repo.Repo.Did, - Email: repo.Email, - EmailConfirmed: repo.EmailConfirmedAt != nil, - EmailAuthFactor: repo.TwoFactorType != models.TwoFactorTypeNone, - Active: repo.Active(), - Status: repo.Status(), + AccessJwt: sess.AccessToken, + RefreshJwt: sess.RefreshToken, + Handle: repo.Handle, + Did: repo.Repo.Did, + Email: repo.Email, + Active: repo.Active(), + Status: repo.Status(), }) -} - -func (s *Server) createAndSendTwoFactorCode(ctx context.Context, repo models.RepoActor) error { - // TODO: when implementing a new type of 2FA there should be some logic in here to send the - // right type of code - - code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) - eat := time.Now().Add(10 * time.Minute).UTC() - - if err := s.db.Exec(ctx, "UPDATE repos SET two_factor_code = ?, two_factor_code_expires_at = ? WHERE did = ?", nil, code, eat, repo.Repo.Did).Error; err != nil { - return fmt.Errorf("updating repo: %w", err) - } - - if err := s.sendTwoFactorCode(repo.Email, repo.Handle, code); err != nil { - return fmt.Errorf("sending email: %w", err) - } - - return nil -} +} \ No newline at end of file diff --git a/server/handle_server_delete_account.go b/server/handle_server_delete_account.go index cead738..4a18276 100644 --- a/server/handle_server_delete_account.go +++ b/server/handle_server_delete_account.go @@ -15,7 +15,6 @@ import ( type ComAtprotoServerDeleteAccountRequest struct { Did string `json:"did" validate:"required"` Password string `json:"password" validate:"required"` - Token string `json:"token" validate:"required"` } func (s *Server) handleServerDeleteAccount(e echo.Context) error { @@ -44,30 +43,6 @@ func (s *Server) handleServerDeleteAccount(e echo.Context) error { return echo.NewHTTPError(401, "Invalid did or password") } - if urepo.Repo.AccountDeleteCode == nil || urepo.Repo.AccountDeleteCodeExpiresAt == nil { - logger.Error("no deletion token found for account") - return echo.NewHTTPError(400, map[string]any{ - "error": "InvalidToken", - "message": "Token is invalid", - }) - } - - if *urepo.Repo.AccountDeleteCode != req.Token { - logger.Error("deletion token mismatch") - return echo.NewHTTPError(400, map[string]any{ - "error": "InvalidToken", - "message": "Token is invalid", - }) - } - - if time.Now().UTC().After(*urepo.Repo.AccountDeleteCodeExpiresAt) { - logger.Error("deletion token expired") - return echo.NewHTTPError(400, map[string]any{ - "error": "ExpiredToken", - "message": "Token is expired", - }) - } - tx := s.db.Begin(ctx) if tx.Error != nil { logger.Error("error starting transaction", "error", tx.Error) @@ -113,11 +88,6 @@ func (s *Server) handleServerDeleteAccount(e echo.Context) error { return helpers.ServerError(e, nil) } - if err := tx.Exec("DELETE FROM invite_codes WHERE did = ?", req.Did).Error; err != nil { - logger.Error("error deleting invite codes", "error", err) - return helpers.ServerError(e, nil) - } - if err := tx.Exec("DELETE FROM actors WHERE did = ?", req.Did).Error; err != nil { logger.Error("error deleting actor", "error", err) return helpers.ServerError(e, nil) @@ -146,4 +116,4 @@ func (s *Server) handleServerDeleteAccount(e echo.Context) error { }) return e.NoContent(200) -} +} \ No newline at end of file diff --git a/server/handle_server_describe_server.go b/server/handle_server_describe_server.go index c7a224a..a14fb28 100644 --- a/server/handle_server_describe_server.go +++ b/server/handle_server_describe_server.go @@ -22,7 +22,7 @@ type ComAtprotoServerDescribeServerResponse struct { func (s *Server) handleDescribeServer(e echo.Context) error { return e.JSON(200, ComAtprotoServerDescribeServerResponse{ - InviteCodeRequired: s.config.RequireInvite, + InviteCodeRequired: false, PhoneVerificationRequired: false, AvailableUserDomains: []string{"." + s.config.Hostname}, // TODO: more Links: ComAtprotoServerDescribeServerResponseLinks{ diff --git a/server/handle_server_get_session.go b/server/handle_server_get_session.go index cbf5c6a..8b8b5c3 100644 --- a/server/handle_server_get_session.go +++ b/server/handle_server_get_session.go @@ -6,25 +6,21 @@ import ( ) type ComAtprotoServerGetSessionResponse struct { - Handle string `json:"handle"` - Did string `json:"did"` - Email string `json:"email"` - EmailConfirmed bool `json:"emailConfirmed"` - EmailAuthFactor bool `json:"emailAuthFactor"` - Active bool `json:"active"` - Status *string `json:"status,omitempty"` + Handle string `json:"handle"` + Did string `json:"did"` + Email string `json:"email"` + Active bool `json:"active"` + Status *string `json:"status,omitempty"` } func (s *Server) handleGetSession(e echo.Context) error { repo := e.Get("repo").(*models.RepoActor) return e.JSON(200, ComAtprotoServerGetSessionResponse{ - Handle: repo.Handle, - Did: repo.Repo.Did, - Email: repo.Email, - EmailConfirmed: repo.EmailConfirmedAt != nil, - EmailAuthFactor: repo.TwoFactorType != models.TwoFactorTypeNone, - Active: repo.Active(), - Status: repo.Status(), + Handle: repo.Handle, + Did: repo.Repo.Did, + Email: repo.Email, + Active: repo.Active(), + Status: repo.Status(), }) -} +} \ No newline at end of file diff --git a/server/handle_server_request_account_delete.go b/server/handle_server_request_account_delete.go deleted file mode 100644 index 617628e..0000000 --- a/server/handle_server_request_account_delete.go +++ /dev/null @@ -1,27 +0,0 @@ -package server - -import ( - "fmt" - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -func (s *Server) handleServerRequestAccountDelete(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerRequestAccountDelete") - - urepo := e.Get("repo").(*models.RepoActor) - - token := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) - expiresAt := time.Now().UTC().Add(15 * time.Minute) - - if err := s.db.Exec(ctx, "UPDATE repos SET account_delete_code = ?, account_delete_code_expires_at = ? WHERE did = ?", nil, token, expiresAt, urepo.Repo.Did).Error; err != nil { - logger.Error("error setting deletion token", "error", err) - return helpers.ServerError(e, nil) - } - - return e.NoContent(200) -} diff --git a/server/handle_server_request_email_confirmation.go b/server/handle_server_request_email_confirmation.go deleted file mode 100644 index 75f819a..0000000 --- a/server/handle_server_request_email_confirmation.go +++ /dev/null @@ -1,36 +0,0 @@ -package server - -import ( - "fmt" - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -func (s *Server) handleServerRequestEmailConfirmation(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerRequestEmailConfirm") - - urepo := e.Get("repo").(*models.RepoActor) - - if urepo.EmailConfirmedAt != nil { - return helpers.InputError(e, new("InvalidRequest")) - } - - code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) - eat := time.Now().Add(10 * time.Minute).UTC() - - if err := s.db.Exec(ctx, "UPDATE repos SET email_verification_code = ?, email_verification_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil { - logger.Error("error updating user", "error", err) - return helpers.ServerError(e, nil) - } - - if err := s.sendEmailVerification(urepo.Email, urepo.Handle, code); err != nil { - logger.Error("error sending mail", "error", err) - return helpers.ServerError(e, nil) - } - - return e.NoContent(200) -} diff --git a/server/handle_server_request_email_update.go b/server/handle_server_request_email_update.go deleted file mode 100644 index d5dd404..0000000 --- a/server/handle_server_request_email_update.go +++ /dev/null @@ -1,40 +0,0 @@ -package server - -import ( - "fmt" - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -type ComAtprotoRequestEmailUpdateResponse struct { - TokenRequired bool `json:"tokenRequired"` -} - -func (s *Server) handleServerRequestEmailUpdate(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerRequestEmailUpdate") - - urepo := e.Get("repo").(*models.RepoActor) - - if urepo.EmailConfirmedAt != nil { - code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) - eat := time.Now().Add(10 * time.Minute).UTC() - - if err := s.db.Exec(ctx, "UPDATE repos SET email_update_code = ?, email_update_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil { - logger.Error("error updating repo", "error", err) - return helpers.ServerError(e, nil) - } - - if err := s.sendEmailUpdate(urepo.Email, urepo.Handle, code); err != nil { - logger.Error("error sending email", "error", err) - return helpers.ServerError(e, nil) - } - } - - return e.JSON(200, ComAtprotoRequestEmailUpdateResponse{ - TokenRequired: urepo.EmailConfirmedAt != nil, - }) -} diff --git a/server/handle_server_request_password_reset.go b/server/handle_server_request_password_reset.go deleted file mode 100644 index 9212c68..0000000 --- a/server/handle_server_request_password_reset.go +++ /dev/null @@ -1,53 +0,0 @@ -package server - -import ( - "fmt" - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -type ComAtprotoServerRequestPasswordResetRequest struct { - Email string `json:"email" validate:"required"` -} - -func (s *Server) handleServerRequestPasswordReset(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerRequestPasswordReset") - - urepo, ok := e.Get("repo").(*models.RepoActor) - if !ok { - var req ComAtprotoServerRequestPasswordResetRequest - if err := e.Bind(&req); err != nil { - return err - } - - if err := e.Validate(req); err != nil { - return err - } - - murepo, err := s.getRepoActorByEmail(ctx, req.Email) - if err != nil { - return err - } - - urepo = murepo - } - - code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) - eat := time.Now().Add(10 * time.Minute).UTC() - - if err := s.db.Exec(ctx, "UPDATE repos SET password_reset_code = ?, password_reset_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil { - logger.Error("error updating repo", "error", err) - return helpers.ServerError(e, nil) - } - - if err := s.sendPasswordReset(urepo.Email, urepo.Handle, code); err != nil { - logger.Error("error sending email", "error", err) - return helpers.ServerError(e, nil) - } - - return e.NoContent(200) -} diff --git a/server/handle_server_reset_password.go b/server/handle_server_reset_password.go deleted file mode 100644 index fc2ea28..0000000 --- a/server/handle_server_reset_password.go +++ /dev/null @@ -1,57 +0,0 @@ -package server - -import ( - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" - "golang.org/x/crypto/bcrypt" -) - -type ComAtprotoServerResetPasswordRequest struct { - Token string `json:"token" validate:"required"` - Password string `json:"password" validate:"required"` -} - -func (s *Server) handleServerResetPassword(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerResetPassword") - - urepo := e.Get("repo").(*models.RepoActor) - - var req ComAtprotoServerResetPasswordRequest - if err := e.Bind(&req); err != nil { - logger.Error("error binding", "error", err) - return helpers.ServerError(e, nil) - } - - if err := e.Validate(req); err != nil { - return helpers.InputError(e, nil) - } - - if urepo.PasswordResetCode == nil || urepo.PasswordResetCodeExpiresAt == nil { - return helpers.InputError(e, new("InvalidToken")) - } - - if *urepo.PasswordResetCode != req.Token { - return helpers.InvalidTokenError(e) - } - - if time.Now().UTC().After(*urepo.PasswordResetCodeExpiresAt) { - return helpers.ExpiredTokenError(e) - } - - hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10) - if err != nil { - logger.Error("error creating hash", "error", err) - return helpers.ServerError(e, nil) - } - - if err := s.db.Exec(ctx, "UPDATE repos SET password_reset_code = NULL, password_reset_code_expires_at = NULL, password = ? WHERE did = ?", nil, hash, urepo.Repo.Did).Error; err != nil { - logger.Error("error updating repo", "error", err) - return helpers.ServerError(e, nil) - } - - return e.NoContent(200) -} diff --git a/server/handle_server_update_email.go b/server/handle_server_update_email.go deleted file mode 100644 index 52bfe0e..0000000 --- a/server/handle_server_update_email.go +++ /dev/null @@ -1,73 +0,0 @@ -package server - -import ( - "time" - - "tangled.org/pdewey.com/chrysalis/internal/helpers" - "tangled.org/pdewey.com/chrysalis/models" - "github.com/labstack/echo/v4" -) - -type ComAtprotoServerUpdateEmailRequest struct { - Email string `json:"email" validate:"required"` - EmailAuthFactor bool `json:"emailAuthFactor"` - Token string `json:"token"` -} - -func (s *Server) handleServerUpdateEmail(e echo.Context) error { - ctx := e.Request().Context() - logger := s.logger.With("name", "handleServerUpdateEmail") - - urepo := e.Get("repo").(*models.RepoActor) - - var req ComAtprotoServerUpdateEmailRequest - if err := e.Bind(&req); err != nil { - logger.Error("error binding", "error", err) - return helpers.ServerError(e, nil) - } - - if err := e.Validate(req); err != nil { - return helpers.InputError(e, nil) - } - - // To disable email auth factor a token is required. - // To enable email auth factor a token is not required. - // If updating an email address, a token will be sent anyway - if urepo.TwoFactorType != models.TwoFactorTypeNone && req.EmailAuthFactor == false && req.Token == "" { - return helpers.InvalidTokenError(e) - } - - if req.Token != "" { - if urepo.EmailUpdateCode == nil || urepo.EmailUpdateCodeExpiresAt == nil { - return helpers.InvalidTokenError(e) - } - - if *urepo.EmailUpdateCode != req.Token { - return helpers.InvalidTokenError(e) - } - - if time.Now().UTC().After(*urepo.EmailUpdateCodeExpiresAt) { - return helpers.ExpiredTokenError(e) - } - } - - twoFactorType := models.TwoFactorTypeNone - if req.EmailAuthFactor { - twoFactorType = models.TwoFactorTypeEmail - } - - query := "UPDATE repos SET email_update_code = NULL, email_update_code_expires_at = NULL, two_factor_type = ?, email = ?" - - if urepo.Email != req.Email { - query += ",email_confirmed_at = NULL" - } - - query += " WHERE did = ?" - - if err := s.db.Exec(ctx, query, nil, twoFactorType, req.Email, urepo.Repo.Did).Error; err != nil { - logger.Error("error updating repo", "error", err) - return helpers.ServerError(e, nil) - } - - return e.NoContent(200) -} diff --git a/server/handle_sync_subscribe_repos.go b/server/handle_sync_subscribe_repos.go index b6d758b..1dfc9f5 100644 --- a/server/handle_sync_subscribe_repos.go +++ b/server/handle_sync_subscribe_repos.go @@ -3,7 +3,6 @@ package server import ( "context" "strconv" - "time" "github.com/bluesky-social/indigo/events" "github.com/bluesky-social/indigo/lex/util" @@ -123,15 +122,5 @@ func (s *Server) handleSyncSubscribeRepos(e echo.Context) error { }() } - // we should tell the relay to request a new crawl at this point if we got disconnected - // use a new context since the old one might be cancelled at this point - go func() { - retryCtx, retryCancel := context.WithTimeout(context.Background(), 10*time.Second) - defer retryCancel() - if err := s.requestCrawl(retryCtx); err != nil { - logger.Error("error requesting crawls", "err", err) - } - }() - return nil } diff --git a/server/mail.go b/server/mail.go deleted file mode 100644 index 8218e46..0000000 --- a/server/mail.go +++ /dev/null @@ -1,10 +0,0 @@ -package server - -// Mail stubs — chrysalis is a test-only PDS, no SMTP support. - -func (s *Server) sendWelcomeMail(email, handle string) error { return nil } -func (s *Server) sendPasswordReset(email, handle, code string) error { return nil } -func (s *Server) sendPlcTokenReset(email, handle, code string) error { return nil } -func (s *Server) sendEmailUpdate(email, handle, code string) error { return nil } -func (s *Server) sendEmailVerification(email, handle, code string) error { return nil } -func (s *Server) sendTwoFactorCode(email, handle, code string) error { return nil } diff --git a/server/repo.go b/server/repo.go index 1587e77..98fc848 100644 --- a/server/repo.go +++ b/server/repo.go @@ -20,7 +20,6 @@ import ( lexutil "github.com/bluesky-social/indigo/lex/util" "tangled.org/pdewey.com/chrysalis/internal/db" "tangled.org/pdewey.com/chrysalis/models" - "tangled.org/pdewey.com/chrysalis/recording_blockstore" blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" blockstore "github.com/ipfs/go-ipfs-blockstore" @@ -239,7 +238,7 @@ func (rm *RepoMan) applyWrites(ctx context.Context, urepo models.Repo, writes [] } dbs := rm.s.getBlockstore(urepo.Did) - bs := recording_blockstore.New(dbs) + bs := dbs var results []ApplyWriteResult var ops []*atp.Operation @@ -461,13 +460,6 @@ func (rm *RepoMan) applyWrites(ctx context.Context, urepo models.Repo, writes [] } } - // write the writelog to the buffer - for _, blk := range bs.GetWriteLog() { - if _, err := carstore.LdWrite(buf, blk.Cid().Bytes(), blk.RawData()); err != nil { - return nil, err - } - } - // blob blob blob blob blob :3 var blobs []lexutil.LexLink for _, entry := range entries { diff --git a/server/server.go b/server/server.go index 4b27d9b..dc99114 100644 --- a/server/server.go +++ b/server/server.go @@ -8,14 +8,13 @@ import ( "log/slog" "net/http" "os" - "sync" + "time" - "github.com/bluesky-social/indigo/api/atproto" + "github.com/bluesky-social/indigo/atproto/syntax" "github.com/bluesky-social/indigo/events" "github.com/bluesky-social/indigo/util" - "github.com/bluesky-social/indigo/xrpc" "github.com/go-playground/validator" "github.com/ipfs/go-cid" "github.com/labstack/echo/v4" @@ -49,9 +48,6 @@ type Server struct { evtman *events.EventManager passport *identity.Passport - lastRequestCrawl time.Time - requestCrawlMu sync.Mutex - dbName string } @@ -66,9 +62,7 @@ type Args struct { RotationKeyPath string JwkPath string ContactEmail string - Relays []string AdminPassword string - RequireInvite bool BlockstoreVariant BlockstoreVariant @@ -89,9 +83,7 @@ type config struct { Did string Hostname string ContactEmail string - Relays []string AdminPassword string - RequireInvite bool BlockstoreVariant BlockstoreVariant } @@ -290,14 +282,6 @@ func New(args *Args) (*Server, error) { Timeout: 10 * time.Second, } - var nonceSecret []byte - maybeSecret, err := os.ReadFile("nonce.secret") - if err != nil && !os.IsNotExist(err) { - logger.Error("error attempting to read nonce secret", "error", err) - } else { - nonceSecret = maybeSecret - } - evtPersister, err := NewDbPersister(gdb, 72*time.Hour) if err != nil { return nil, fmt.Errorf("failed to create event persister: %w", err) @@ -316,9 +300,7 @@ func New(args *Args) (*Server, error) { Did: args.Did, Hostname: args.Hostname, ContactEmail: args.ContactEmail, - Relays: args.Relays, AdminPassword: args.AdminPassword, - RequireInvite: args.RequireInvite, BlockstoreVariant: args.BlockstoreVariant, }, evtman: events.NewEventManager(evtPersister), @@ -334,15 +316,10 @@ func New(args *Args) (*Server, error) { Logger: args.Logger.With("component", "oauth-client-manager"), }, DpopManagerArgs: dpop.ManagerArgs{ - NonceSecret: nonceSecret, + NonceSecret: nil, // nonces are in-memory only for test PDS NonceRotationInterval: constants.NonceMaxRotationInterval / 3, - OnNonceSecretCreated: func(newNonce []byte) { - if err := os.WriteFile("nonce.secret", newNonce, 0644); err != nil { - logger.Error("error writing new nonce secret", "error", err) - } - }, - Logger: args.Logger.With("component", "dpop-manager"), - Hostname: args.Hostname, + Logger: args.Logger.With("component", "dpop-manager"), + Hostname: args.Hostname, }, }), } @@ -358,7 +335,6 @@ func (s *Server) addRoutes() { s.echo.GET("/.well-known/atproto-did", s.handleAtprotoDid) s.echo.GET("/.well-known/oauth-protected-resource", s.handleOauthProtectedResource) s.echo.GET("/.well-known/oauth-authorization-server", s.handleOauthAuthorizationServer) - s.echo.GET("/robots.txt", s.handleRobots) // public s.echo.GET("/xrpc/com.atproto.identity.resolveHandle", s.handleResolveHandle) @@ -399,17 +375,10 @@ func (s *Server) addRoutes() { s.echo.POST("/xrpc/com.atproto.identity.requestPlcOperationSignature", s.handleIdentityRequestPlcOperationSignature, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/com.atproto.identity.signPlcOperation", s.handleSignPlcOperation, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/com.atproto.identity.submitPlcOperation", s.handleSubmitPlcOperation, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - s.echo.POST("/xrpc/com.atproto.server.confirmEmail", s.handleServerConfirmEmail, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - s.echo.POST("/xrpc/com.atproto.server.requestEmailConfirmation", s.handleServerRequestEmailConfirmation, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - s.echo.POST("/xrpc/com.atproto.server.requestPasswordReset", s.handleServerRequestPasswordReset) - s.echo.POST("/xrpc/com.atproto.server.requestEmailUpdate", s.handleServerRequestEmailUpdate, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - s.echo.POST("/xrpc/com.atproto.server.resetPassword", s.handleServerResetPassword, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - s.echo.POST("/xrpc/com.atproto.server.updateEmail", s.handleServerUpdateEmail, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.GET("/xrpc/com.atproto.server.getServiceAuth", s.handleServerGetServiceAuth, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.GET("/xrpc/com.atproto.server.checkAccountStatus", s.handleServerCheckAccountStatus, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/com.atproto.server.deactivateAccount", s.handleServerDeactivateAccount, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/com.atproto.server.activateAccount", s.handleServerActivateAccount, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - s.echo.POST("/xrpc/com.atproto.server.requestAccountDelete", s.handleServerRequestAccountDelete, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/com.atproto.server.deleteAccount", s.handleServerDeleteAccount) // repo @@ -419,16 +388,11 @@ func (s *Server) addRoutes() { s.echo.POST("/xrpc/com.atproto.repo.deleteRecord", s.handleDeleteRecord, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/com.atproto.repo.applyWrites", s.handleApplyWrites, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/com.atproto.repo.uploadBlob", s.handleRepoUploadBlob, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - s.echo.POST("/xrpc/com.atproto.repo.importRepo", s.handleRepoImportRepo, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - // bsky compat s.echo.GET("/xrpc/app.bsky.actor.getPreferences", s.handleActorGetPreferences, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.POST("/xrpc/app.bsky.actor.putPreferences", s.handleActorPutPreferences, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) s.echo.GET("/xrpc/app.bsky.ageassurance.getState", s.handleAgeAssurance, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware) - // admin routes - s.echo.POST("/xrpc/com.atproto.server.createInviteCode", s.handleCreateInviteCode, s.handleAdminMiddleware) - s.echo.POST("/xrpc/com.atproto.server.createInviteCodes", s.handleCreateInviteCodes, s.handleAdminMiddleware) } func (s *Server) Serve(ctx context.Context) error { @@ -441,7 +405,6 @@ func (s *Server) Serve(ctx context.Context) error { s.db.AutoMigrate( &models.Actor{}, &models.Repo{}, - &models.InviteCode{}, &models.Token{}, &models.RefreshToken{}, &models.Block{}, @@ -463,9 +426,7 @@ func (s *Server) Serve(ctx context.Context) error { }() go func() { - if err := s.requestCrawl(ctx); err != nil { - logger.Error("error requesting crawls", "err", err) - } + <-ctx.Done() }() select { @@ -486,35 +447,6 @@ func (s *Server) Serve(ctx context.Context) error { return nil } -func (s *Server) requestCrawl(ctx context.Context) error { - logger := s.logger.With("component", "request-crawl") - s.requestCrawlMu.Lock() - defer s.requestCrawlMu.Unlock() - - logger.Info("requesting crawl with configured relays") - - if time.Since(s.lastRequestCrawl) <= 1*time.Minute { - return fmt.Errorf("a crawl request has already been made within the last minute") - } - - for _, relay := range s.config.Relays { - logger := logger.With("relay", relay) - logger.Info("requesting crawl from relay") - cli := xrpc.Client{Host: relay} - if err := atproto.SyncRequestCrawl(ctx, &cli, &atproto.SyncRequestCrawl_Input{ - Hostname: s.config.Hostname, - }); err != nil { - logger.Error("error requesting crawl", "err", err) - } else { - logger.Info("crawl requested successfully") - } - } - - s.lastRequestCrawl = time.Now() - - return nil -} - func (s *Server) UpdateRepo(ctx context.Context, did string, root cid.Cid, rev string) error { if err := s.db.Exec(ctx, "UPDATE repos SET root = ?, rev = ? WHERE did = ?", nil, root.Bytes(), rev, did).Error; err != nil { return err diff --git a/testpds/testpds.go b/testpds/testpds.go index 22bcdc3..a4775e7 100644 --- a/testpds/testpds.go +++ b/testpds/testpds.go @@ -81,14 +81,6 @@ type Options struct { // (default) picks a free one. FakePLCPort int - // RequireInvite controls whether the server requires invite codes for - // account creation. Defaults to false. - RequireInvite bool - - // Relays is the list of relay URLs to notify on new commits. Defaults to - // empty (no relay notifications). - Relays []string - // AdminPassword overrides the admin password. Defaults to "test-admin". AdminPassword string @@ -196,8 +188,6 @@ func Start(ctx context.Context, opts *Options) (*TestPDS, error) { HTTPClient: &http.Client{Timeout: httpClientTimeout}, ContactEmail: "test@test.com", AdminPassword: opts.AdminPassword, - RequireInvite: opts.RequireInvite, - Relays: opts.Relays, }) if err != nil { _ = plcSrv.Close() diff --git a/testpds/testpds_test.go b/testpds/testpds_test.go index c5331b0..b5c98a2 100644 --- a/testpds/testpds_test.go +++ b/testpds/testpds_test.go @@ -32,7 +32,6 @@ func TestStart(t *testing.T) { func TestStartWithOptions(t *testing.T) { pds := testpds.StartT(t, &testpds.Options{ AdminPassword: "custom-password", - RequireInvite: true, }) resp, err := http.Get(pds.URL + "/xrpc/_health")