forked from hailey.at/cocoon
An atproto PDS written in Go

implement 2fa on creating a session

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

Changed files
+35
server
+35
server/handle_server_create_session.go
··· 2 2 3 3 import ( 4 4 "errors" 5 + "fmt" 5 6 "strings" 7 + "time" 6 8 7 9 "github.com/Azure/go-autorest/autorest/to" 8 10 "github.com/bluesky-social/indigo/atproto/syntax" ··· 82 84 83 85 logger.Error("erorr looking up repo", "endpoint", "com.atproto.server.createSession", "error", err) 84 86 return helpers.ServerError(e, nil) 87 + } 88 + 89 + // if repo requires auth factor token and one hasn't been provided, return error prompting for one 90 + 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) 101 + return helpers.ServerError(e, nil) 102 + } 103 + 104 + return helpers.InputError(e, to.StringPtr("AuthFactorTokenRequired")) 105 + } 106 + 107 + // if auth factor is required, now check that the one provided is valid 108 + if repo.EmailAuthFactor { 109 + if repo.EmailUpdateCode == nil || repo.EmailUpdateCodeExpiresAt == nil { 110 + return helpers.InvalidTokenError(e) 111 + } 112 + 113 + if *repo.EmailUpdateCode != *req.AuthFactorToken { 114 + return helpers.InvalidTokenError(e) 115 + } 116 + 117 + if time.Now().UTC().After(*repo.EmailUpdateCodeExpiresAt) { 118 + return helpers.ExpiredTokenError(e) 119 + } 85 120 } 86 121 87 122 if err := bcrypt.CompareHashAndPassword([]byte(repo.Password), []byte(req.Password)); err != nil {