@@ -4,12 +4,12 @@ import (
44 "bytes"
55 "context"
66 "encoding/json"
7- "fmt"
87 "image/png"
98 "time"
109
1110 "github.com/google/uuid"
1211 "github.com/pquerna/otp/totp"
12+ log "github.com/sirupsen/logrus"
1313
1414 "github.com/authorizerdev/authorizer/server/authenticators/providers"
1515 "github.com/authorizerdev/authorizer/server/constants"
@@ -22,30 +22,26 @@ import (
2222// Generate generates a Time-Based One-Time Password (TOTP) for a user and returns the base64-encoded QR code for frontend display.
2323func (p * provider ) Generate (ctx context.Context , id string ) (* providers.AuthenticatorConfig , error ) {
2424 var buf bytes.Buffer
25-
2625 //get user details
2726 user , err := db .Provider .GetUserByID (ctx , id )
2827 if err != nil {
29- return nil , fmt . Errorf ( "error while getting user details" )
28+ return nil , err
3029 }
31-
3230 // generate totp, Authenticators hash is valid for 30 seconds
3331 key , err := totp .Generate (totp.GenerateOpts {
3432 Issuer : "authorizer" ,
3533 AccountName : refs .StringValue (user .Email ),
3634 })
3735 if err != nil {
38- return nil , fmt . Errorf ( "error while genrating totp" )
36+ return nil , err
3937 }
40-
4138 //generating image for key and encoding to base64 for displaying in frontend
4239 img , err := key .Image (200 , 200 )
4340 if err != nil {
44- return nil , fmt . Errorf ( "error while creating qr image for totp" )
41+ return nil , err
4542 }
4643 png .Encode (& buf , img )
4744 encodedText := crypto .EncryptB64 (buf .String ())
48-
4945 secret := key .Secret ()
5046 recoveryCodes := []string {}
5147 for i := 0 ; i < 10 ; i ++ {
@@ -59,24 +55,40 @@ func (p *provider) Generate(ctx context.Context, id string) (*providers.Authenti
5955 // Converting recoveryCodesMap to string
6056 jsonData , err := json .Marshal (recoverCodesMap )
6157 if err != nil {
62- return nil , fmt . Errorf ( "error while converting recoveryCodes to string" )
58+ return nil , err
6359 }
6460 recoveryCodesString := string (jsonData )
65-
6661 totpModel := & models.Authenticator {
6762 Secret : secret ,
6863 RecoveryCodes : refs .NewStringRef (recoveryCodesString ),
6964 UserID : user .ID ,
7065 Method : constants .EnvKeyTOTPAuthenticator ,
7166 }
72- _ , err = db .Provider .AddAuthenticator (ctx , totpModel )
67+ authenticator , err : = db .Provider .GetAuthenticatorDetailsByUserId (ctx , user . ID , constants . EnvKeyTOTPAuthenticator )
7368 if err != nil {
74- return nil , fmt .Errorf ("error while inserting into totp table" )
69+ log .Debug ("Failed to get authenticator details by user id, creating new record: " , err )
70+ // continue
71+ }
72+ if authenticator == nil {
73+ // if authenticator is nil then create new authenticator
74+ _ , err = db .Provider .AddAuthenticator (ctx , totpModel )
75+ if err != nil {
76+ return nil , err
77+ }
78+ } else {
79+ authenticator .Secret = secret
80+ authenticator .RecoveryCodes = refs .NewStringRef (recoveryCodesString )
81+ // if authenticator is not nil then update authenticator
82+ _ , err = db .Provider .UpdateAuthenticator (ctx , authenticator )
83+ if err != nil {
84+ return nil , err
85+ }
7586 }
7687 return & providers.AuthenticatorConfig {
77- ScannerImage : encodedText ,
78- Secret : secret ,
79- RecoveryCodes : recoveryCodes ,
88+ ScannerImage : encodedText ,
89+ Secret : secret ,
90+ RecoveryCodes : recoveryCodes ,
91+ RecoveryCodeMap : recoverCodesMap ,
8092 }, nil
8193}
8294
@@ -85,22 +97,18 @@ func (p *provider) Validate(ctx context.Context, passcode string, userID string)
8597 // get totp details
8698 totpModel , err := db .Provider .GetAuthenticatorDetailsByUserId (ctx , userID , constants .EnvKeyTOTPAuthenticator )
8799 if err != nil {
88- return false , fmt . Errorf ( "error while getting totp details from authenticators" )
100+ return false , err
89101 }
90-
102+ // validate totp
91103 status := totp .Validate (passcode , totpModel .Secret )
92104 // checks if user not signed in for totp and totp code is correct then VerifiedAt will be stored in db
93- if totpModel .VerifiedAt == nil {
94- if status {
95- timeNow := time .Now ().Unix ()
96- totpModel .VerifiedAt = & timeNow
97- _ , err = db .Provider .UpdateAuthenticator (ctx , totpModel )
98- if err != nil {
99- return false , fmt .Errorf ("error while updaing authenticator table for totp" )
100- }
101- return status , nil
105+ if totpModel .VerifiedAt == nil && status {
106+ timeNow := time .Now ().Unix ()
107+ totpModel .VerifiedAt = & timeNow
108+ _ , err = db .Provider .UpdateAuthenticator (ctx , totpModel )
109+ if err != nil {
110+ return false , err
102111 }
103- return status , nil
104112 }
105113 return status , nil
106114}
0 commit comments