An atproto PDS written in Go
103
fork

Configure Feed

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

refactor the 2FA code into it's own field on model and generate a new email type

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

authored by willdot.net and committed by

Tangled 8ac78c0f 1d8b8d2e

+50 -14
+2
models/models.go
··· 30 30 Preferences []byte 31 31 Deactivated bool 32 32 EmailAuthFactor bool 33 + AuthCode *string 34 + AuthCodeExpiresAt *time.Time 33 35 } 34 36 35 37 func (r *Repo) SignFor(ctx context.Context, did string, msg []byte) ([]byte, error) {
+29 -14
server/handle_server_create_session.go
··· 1 1 package server 2 2 3 3 import ( 4 + "context" 4 5 "errors" 5 6 "fmt" 6 7 "strings" ··· 88 89 89 90 // if repo requires auth factor token and one hasn't been provided, return error prompting for one 90 91 if repo.EmailAuthFactor && (req.AuthFactorToken == nil || *req.AuthFactorToken == "") { 91 - code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) 92 - eat := time.Now().Add(10 * time.Minute).UTC() 93 - 94 - if err := s.db.Exec(ctx, "UPDATE repos SET email_update_code = ?, email_update_code_expires_at = ? WHERE did = ?", nil, code, eat, repo.Repo.Did).Error; err != nil { 95 - s.logger.Error("error updating repo", "error", err) 96 - return helpers.ServerError(e, nil) 97 - } 98 - 99 - if err := s.sendEmailUpdate(repo.Email, repo.Handle, code); err != nil { 100 - s.logger.Error("error sending email", "error", err) 92 + err = s.createAndSendAuthCode(ctx, repo) 93 + if err != nil { 94 + s.logger.Error("sending auth code", "error", err) 101 95 return helpers.ServerError(e, nil) 102 96 } 103 97 ··· 106 100 107 101 // if auth factor is required, now check that the one provided is valid 108 102 if repo.EmailAuthFactor { 109 - if repo.EmailUpdateCode == nil || repo.EmailUpdateCodeExpiresAt == nil { 110 - return helpers.InvalidTokenError(e) 103 + if repo.AuthCode == nil || repo.AuthCodeExpiresAt == nil { 104 + err = s.createAndSendAuthCode(ctx, repo) 105 + if err != nil { 106 + s.logger.Error("sending auth code", "error", err) 107 + return helpers.ServerError(e, nil) 108 + } 109 + 110 + return helpers.InputError(e, to.StringPtr("AuthFactorTokenRequired")) 111 111 } 112 112 113 - if *repo.EmailUpdateCode != *req.AuthFactorToken { 113 + if *repo.AuthCode != *req.AuthFactorToken { 114 114 return helpers.InvalidTokenError(e) 115 115 } 116 116 117 - if time.Now().UTC().After(*repo.EmailUpdateCodeExpiresAt) { 117 + if time.Now().UTC().After(*repo.AuthCodeExpiresAt) { 118 118 return helpers.ExpiredTokenError(e) 119 119 } 120 120 } ··· 144 144 Status: repo.Status(), 145 145 }) 146 146 } 147 + 148 + func (s *Server) createAndSendAuthCode(ctx context.Context, repo models.RepoActor) error { 149 + code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5)) 150 + eat := time.Now().Add(10 * time.Minute).UTC() 151 + 152 + if err := s.db.Exec(ctx, "UPDATE repos SET auth_code = ?, auth_code_expires_at = ? WHERE did = ?", nil, code, eat, repo.Repo.Did).Error; err != nil { 153 + return fmt.Errorf("updating repo: %w", err) 154 + } 155 + 156 + if err := s.sendAuthCode(repo.Email, repo.Handle, code); err != nil { 157 + return fmt.Errorf("sending email: %w", err) 158 + } 159 + 160 + return nil 161 + }
+19
server/mail.go
··· 96 96 97 97 return nil 98 98 } 99 + 100 + func (s *Server) sendAuthCode(email, handle, code string) error { 101 + if s.mail == nil { 102 + return nil 103 + } 104 + 105 + s.mailLk.Lock() 106 + defer s.mailLk.Unlock() 107 + 108 + s.mail.To(email) 109 + s.mail.Subject("2FA code for " + s.config.Hostname) 110 + s.mail.Plain().Set(fmt.Sprintf("Hello %s. Your 2FA code is %s. This code will expire in ten minutes.", handle, code)) 111 + 112 + if err := s.mail.Send(); err != nil { 113 + return err 114 + } 115 + 116 + return nil 117 + }