An atproto PDS written in Go

implement enabling / disabling email auth factor (not currently checked on auth checks though)

Signed-off-by: Will Andrews <did:plc:dadhhalkfcq3gucaq25hjqon>

+29 -11
+3 -2
models/models.go
··· 29 29 Root []byte 30 30 Preferences []byte 31 31 Deactivated bool 32 + EmailAuthFactor bool 32 33 } 33 34 34 35 func (r *Repo) SignFor(ctx context.Context, did string, msg []byte) ([]byte, error) { ··· 121 122 } 122 123 123 124 type ReservedKey struct { 124 - KeyDid string `gorm:"primaryKey"` 125 - Did *string `gorm:"index"` 125 + KeyDid string `gorm:"primaryKey"` 126 + Did *string `gorm:"index"` 126 127 PrivateKey []byte 127 128 CreatedAt time.Time `gorm:"index"` 128 129 }
+1 -1
server/handle_server_create_session.go
··· 103 103 Did: repo.Repo.Did, 104 104 Email: repo.Email, 105 105 EmailConfirmed: repo.EmailConfirmedAt != nil, 106 - EmailAuthFactor: false, 106 + EmailAuthFactor: repo.EmailAuthFactor, 107 107 Active: repo.Active(), 108 108 Status: repo.Status(), 109 109 })
+1 -1
server/handle_server_get_session.go
··· 23 23 Did: repo.Repo.Did, 24 24 Email: repo.Email, 25 25 EmailConfirmed: repo.EmailConfirmedAt != nil, 26 - EmailAuthFactor: false, // TODO: todo todo 26 + EmailAuthFactor: repo.EmailAuthFactor, 27 27 Active: repo.Active(), 28 28 Status: repo.Status(), 29 29 })
+24 -7
server/handle_server_update_email.go
··· 11 11 type ComAtprotoServerUpdateEmailRequest struct { 12 12 Email string `json:"email" validate:"required"` 13 13 EmailAuthFactor bool `json:"emailAuthFactor"` 14 - Token string `json:"token" validate:"required"` 14 + Token string `json:"token"` 15 15 } 16 16 17 17 func (s *Server) handleServerUpdateEmail(e echo.Context) error { ··· 29 29 return helpers.InputError(e, nil) 30 30 } 31 31 32 - if urepo.EmailUpdateCode == nil || urepo.EmailUpdateCodeExpiresAt == nil { 32 + // To disable email auth factor a token is required. 33 + // To enable email auth factor a token is not required. 34 + // If updating an email address, a token will be sent anyway 35 + if urepo.EmailAuthFactor && req.EmailAuthFactor == false && req.Token == "" { 33 36 return helpers.InvalidTokenError(e) 34 37 } 35 38 36 - if *urepo.EmailUpdateCode != req.Token { 37 - return helpers.InvalidTokenError(e) 39 + if req.Token != "" { 40 + if urepo.EmailUpdateCode == nil || urepo.EmailUpdateCodeExpiresAt == nil { 41 + return helpers.InvalidTokenError(e) 42 + } 43 + 44 + if *urepo.EmailUpdateCode != req.Token { 45 + return helpers.InvalidTokenError(e) 46 + } 47 + 48 + if time.Now().UTC().After(*urepo.EmailUpdateCodeExpiresAt) { 49 + return helpers.ExpiredTokenError(e) 50 + } 38 51 } 39 52 40 - if time.Now().UTC().After(*urepo.EmailUpdateCodeExpiresAt) { 41 - return helpers.ExpiredTokenError(e) 53 + query := "UPDATE repos SET email_update_code = NULL, email_update_code_expires_at = NULL, email_auth_factor = ?, email = ?" 54 + 55 + if urepo.Email != req.Email { 56 + query += ",email_confirmed_at = NULL" 42 57 } 43 58 44 - if err := s.db.Exec(ctx, "UPDATE repos SET email_update_code = NULL, email_update_code_expires_at = NULL, email_confirmed_at = NULL, email = ? WHERE did = ?", nil, req.Email, urepo.Repo.Did).Error; err != nil { 59 + query += " WHERE did = ?" 60 + 61 + if err := s.db.Exec(ctx, query, nil, req.EmailAuthFactor, req.Email, urepo.Repo.Did).Error; err != nil { 45 62 s.logger.Error("error updating repo", "error", err) 46 63 return helpers.ServerError(e, nil) 47 64 }