Skip to content

Commit d04f795

Browse files
committed
Refactor code for otp
1 parent c20e9b8 commit d04f795

33 files changed

+277
-685
lines changed

server/constants/auth_methods.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const (
77
AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth"
88
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
99
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
10+
// AuthRecipeMethodMobileOTP is the mobile_otp auth method
11+
AuthRecipeMethodMobileOTP = "mobile_otp"
1012
// AuthRecipeMethodGoogle is the google auth method
1113
AuthRecipeMethodGoogle = "google"
1214
// AuthRecipeMethodGithub is the github auth method

server/db/models/sms_verification_requests.go

Lines changed: 0 additions & 12 deletions
This file was deleted.

server/db/providers/arangodb/otp.go

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package arangodb
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"time"
78

@@ -12,17 +13,31 @@ import (
1213

1314
// UpsertOTP to add or update otp
1415
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
15-
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
16+
// check if email or phone number is present
17+
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
18+
return nil, errors.New("email or phone_number is required")
19+
}
20+
uniqueField := models.FieldNameEmail
21+
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
22+
uniqueField = models.FieldNamePhoneNumber
23+
}
24+
var otp *models.OTP
25+
if uniqueField == models.FieldNameEmail {
26+
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
27+
} else {
28+
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
29+
}
1630
shouldCreate := false
1731
if otp == nil {
1832
id := uuid.NewString()
1933
otp = &models.OTP{
20-
ID: id,
21-
Key: id,
22-
Otp: otpParam.Otp,
23-
Email: otpParam.Email,
24-
ExpiresAt: otpParam.ExpiresAt,
25-
CreatedAt: time.Now().Unix(),
34+
ID: id,
35+
Key: id,
36+
Otp: otpParam.Otp,
37+
Email: otpParam.Email,
38+
PhoneNumber: otpParam.PhoneNumber,
39+
ExpiresAt: otpParam.ExpiresAt,
40+
CreatedAt: time.Now().Unix(),
2641
}
2742
shouldCreate = true
2843
} else {
@@ -67,7 +82,35 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
6782
for {
6883
if !cursor.HasMore() {
6984
if otp.Key == "" {
70-
return nil, fmt.Errorf("email template not found")
85+
return nil, fmt.Errorf("otp with given email not found")
86+
}
87+
break
88+
}
89+
_, err := cursor.ReadDocument(ctx, &otp)
90+
if err != nil {
91+
return nil, err
92+
}
93+
}
94+
95+
return &otp, nil
96+
}
97+
98+
// GetOTPByPhoneNumber to get otp for a given phone number
99+
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
100+
var otp models.OTP
101+
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.OTP)
102+
bindVars := map[string]interface{}{
103+
"phone_number": phoneNumber,
104+
}
105+
cursor, err := p.db.Query(ctx, query, bindVars)
106+
if err != nil {
107+
return nil, err
108+
}
109+
defer cursor.Close()
110+
for {
111+
if !cursor.HasMore() {
112+
if otp.Key == "" {
113+
return nil, fmt.Errorf("otp with given phone_number not found")
71114
}
72115
break
73116
}

server/db/providers/arangodb/provider.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -233,22 +233,7 @@ func NewProvider() (*provider, error) {
233233
Unique: true,
234234
Sparse: true,
235235
})
236-
237-
smsVerificationCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.SMSVerificationRequest)
238-
if err != nil {
239-
return nil, err
240-
}
241-
if !smsVerificationCollectionExists {
242-
_, err = arangodb.CreateCollection(ctx, models.Collections.SMSVerificationRequest, nil)
243-
if err != nil {
244-
return nil, err
245-
}
246-
}
247-
smsVerificationCollection, err := arangodb.Collection(ctx, models.Collections.SMSVerificationRequest)
248-
if err != nil {
249-
return nil, err
250-
}
251-
smsVerificationCollection.EnsureHashIndex(ctx, []string{"phone_number"}, &arangoDriver.EnsureHashIndexOptions{
236+
otpCollection.EnsureHashIndex(ctx, []string{"phone_number"}, &arangoDriver.EnsureHashIndexOptions{
252237
Unique: true,
253238
Sparse: true,
254239
})

server/db/providers/arangodb/sms_verification_requests.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

server/db/providers/cassandradb/otp.go

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cassandradb
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"time"
78

@@ -12,17 +13,31 @@ import (
1213

1314
// UpsertOTP to add or update otp
1415
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
15-
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
16+
// check if email or phone number is present
17+
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
18+
return nil, errors.New("email or phone_number is required")
19+
}
20+
uniqueField := models.FieldNameEmail
21+
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
22+
uniqueField = models.FieldNamePhoneNumber
23+
}
24+
var otp *models.OTP
25+
if uniqueField == models.FieldNameEmail {
26+
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
27+
} else {
28+
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
29+
}
1630
shouldCreate := false
1731
if otp == nil {
1832
shouldCreate = true
1933
otp = &models.OTP{
20-
ID: uuid.NewString(),
21-
Otp: otpParam.Otp,
22-
Email: otpParam.Email,
23-
ExpiresAt: otpParam.ExpiresAt,
24-
CreatedAt: time.Now().Unix(),
25-
UpdatedAt: time.Now().Unix(),
34+
ID: uuid.NewString(),
35+
Otp: otpParam.Otp,
36+
Email: otpParam.Email,
37+
PhoneNumber: otpParam.PhoneNumber,
38+
ExpiresAt: otpParam.ExpiresAt,
39+
CreatedAt: time.Now().Unix(),
40+
UpdatedAt: time.Now().Unix(),
2641
}
2742
} else {
2843
otp.Otp = otpParam.Otp
@@ -32,7 +47,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
3247
otp.UpdatedAt = time.Now().Unix()
3348
query := ""
3449
if shouldCreate {
35-
query = fmt.Sprintf(`INSERT INTO %s (id, email, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+models.Collections.OTP, otp.ID, otp.Email, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt)
50+
query = fmt.Sprintf(`INSERT INTO %s (id, email, phone_number, otp, expires_at, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)`, KeySpace+"."+models.Collections.OTP, otp.ID, otp.Email, otp.PhoneNumber, otp.Otp, otp.ExpiresAt, otp.CreatedAt, otp.UpdatedAt)
3651
} else {
3752
query = fmt.Sprintf(`UPDATE %s SET otp = '%s', expires_at = %d, updated_at = %d WHERE id = '%s'`, KeySpace+"."+models.Collections.OTP, otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID)
3853
}
@@ -48,8 +63,19 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
4863
// GetOTPByEmail to get otp for a given email address
4964
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
5065
var otp models.OTP
51-
query := fmt.Sprintf(`SELECT id, email, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, emailAddress)
52-
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
66+
query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, emailAddress)
67+
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
68+
if err != nil {
69+
return nil, err
70+
}
71+
return &otp, nil
72+
}
73+
74+
// GetOTPByPhoneNumber to get otp for a given phone number
75+
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
76+
var otp models.OTP
77+
query := fmt.Sprintf(`SELECT id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.OTP, phoneNumber)
78+
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
5379
if err != nil {
5480
return nil, err
5581
}

server/db/providers/cassandradb/provider.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,11 @@ func NewProvider() (*provider, error) {
254254
if err != nil {
255255
return nil, err
256256
}
257-
257+
otpIndexQueryPhoneNumber := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.OTP)
258+
err = session.Query(otpIndexQueryPhoneNumber).Exec()
259+
if err != nil {
260+
return nil, err
261+
}
258262
return &provider{
259263
db: session,
260264
}, err

server/db/providers/cassandradb/sms_verification_requests.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

server/db/providers/couchbase/otp.go

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package couchbase
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"time"
78

@@ -12,24 +13,36 @@ import (
1213

1314
// UpsertOTP to add or update otp
1415
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
15-
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
16-
16+
// check if email or phone number is present
17+
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
18+
return nil, errors.New("email or phone_number is required")
19+
}
20+
uniqueField := models.FieldNameEmail
21+
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
22+
uniqueField = models.FieldNamePhoneNumber
23+
}
24+
var otp *models.OTP
25+
if uniqueField == models.FieldNameEmail {
26+
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
27+
} else {
28+
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
29+
}
1730
shouldCreate := false
1831
if otp == nil {
1932
shouldCreate = true
2033
otp = &models.OTP{
21-
ID: uuid.NewString(),
22-
Otp: otpParam.Otp,
23-
Email: otpParam.Email,
24-
ExpiresAt: otpParam.ExpiresAt,
25-
CreatedAt: time.Now().Unix(),
26-
UpdatedAt: time.Now().Unix(),
34+
ID: uuid.NewString(),
35+
Otp: otpParam.Otp,
36+
Email: otpParam.Email,
37+
PhoneNumber: otpParam.PhoneNumber,
38+
ExpiresAt: otpParam.ExpiresAt,
39+
CreatedAt: time.Now().Unix(),
40+
UpdatedAt: time.Now().Unix(),
2741
}
2842
} else {
2943
otp.Otp = otpParam.Otp
3044
otp.ExpiresAt = otpParam.ExpiresAt
3145
}
32-
3346
otp.UpdatedAt = time.Now().Unix()
3447
if shouldCreate {
3548
insertOpt := gocb.InsertOptions{
@@ -54,7 +67,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
5467
// GetOTPByEmail to get otp for a given email address
5568
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
5669
otp := models.OTP{}
57-
query := fmt.Sprintf(`SELECT _id, email, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
70+
query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
5871
q, err := p.db.Query(query, &gocb.QueryOptions{
5972
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
6073
PositionalParameters: []interface{}{emailAddress},
@@ -63,11 +76,27 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
6376
return nil, err
6477
}
6578
err = q.One(&otp)
66-
6779
if err != nil {
6880
return nil, err
6981
}
82+
return &otp, nil
83+
}
7084

85+
// GetOTPByPhoneNumber to get otp for a given phone number
86+
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
87+
otp := models.OTP{}
88+
query := fmt.Sprintf(`SELECT _id, email, phone_number, otp, expires_at, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
89+
q, err := p.db.Query(query, &gocb.QueryOptions{
90+
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
91+
PositionalParameters: []interface{}{phoneNumber},
92+
})
93+
if err != nil {
94+
return nil, err
95+
}
96+
err = q.One(&otp)
97+
if err != nil {
98+
return nil, err
99+
}
71100
return &otp, nil
72101
}
73102

server/db/providers/couchbase/provider.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,5 +166,9 @@ func GetIndex(scopeName string) map[string][]string {
166166
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
167167
indices[models.Collections.OTP] = []string{otpIndex1}
168168

169+
// OTP index
170+
otpIndex2 := fmt.Sprintf("CREATE INDEX OTPPhoneNumberIndex ON %s.%s(phone_number)", scopeName, models.Collections.OTP)
171+
indices[models.Collections.OTP] = []string{otpIndex2}
172+
169173
return indices
170174
}

0 commit comments

Comments
 (0)