Refactor code for otp
This commit is contained in:
parent
c20e9b810a
commit
d04f79557a
|
@ -7,6 +7,8 @@ const (
|
||||||
AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth"
|
AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth"
|
||||||
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
||||||
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
||||||
|
// AuthRecipeMethodMobileOTP is the mobile_otp auth method
|
||||||
|
AuthRecipeMethodMobileOTP = "mobile_otp"
|
||||||
// AuthRecipeMethodGoogle is the google auth method
|
// AuthRecipeMethodGoogle is the google auth method
|
||||||
AuthRecipeMethodGoogle = "google"
|
AuthRecipeMethodGoogle = "google"
|
||||||
// AuthRecipeMethodGithub is the github auth method
|
// AuthRecipeMethodGithub is the github auth method
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
package models
|
|
||||||
|
|
||||||
// SMSVerificationRequest is SMS verification requests model for database
|
|
||||||
type SMSVerificationRequest struct {
|
|
||||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
|
||||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
|
||||||
PhoneNumber string `gorm:"unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number" index:"phone_number,hash"`
|
|
||||||
Code string `json:"code" bson:"code" cql:"code" dynamo:"code"`
|
|
||||||
CodeExpiresAt int64 `json:"code_expires_at" bson:"code_expires_at" cql:"code_expires_at" dynamo:"code_expires_at"`
|
|
||||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
|
||||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package arangodb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,17 +13,31 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
id := uuid.NewString()
|
id := uuid.NewString()
|
||||||
otp = &models.OTP{
|
otp = &models.OTP{
|
||||||
ID: id,
|
ID: id,
|
||||||
Key: id,
|
Key: id,
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
CreatedAt: time.Now().Unix(),
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
|
CreatedAt: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
shouldCreate = true
|
shouldCreate = true
|
||||||
} else {
|
} else {
|
||||||
|
@ -67,7 +82,35 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
|
||||||
for {
|
for {
|
||||||
if !cursor.HasMore() {
|
if !cursor.HasMore() {
|
||||||
if otp.Key == "" {
|
if otp.Key == "" {
|
||||||
return nil, fmt.Errorf("email template not found")
|
return nil, fmt.Errorf("otp with given email not found")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err := cursor.ReadDocument(ctx, &otp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
var otp models.OTP
|
||||||
|
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.OTP)
|
||||||
|
bindVars := map[string]interface{}{
|
||||||
|
"phone_number": phoneNumber,
|
||||||
|
}
|
||||||
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close()
|
||||||
|
for {
|
||||||
|
if !cursor.HasMore() {
|
||||||
|
if otp.Key == "" {
|
||||||
|
return nil, fmt.Errorf("otp with given phone_number not found")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,22 +233,7 @@ func NewProvider() (*provider, error) {
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
otpCollection.EnsureHashIndex(ctx, []string{"phone_number"}, &arangoDriver.EnsureHashIndexOptions{
|
||||||
smsVerificationCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.SMSVerificationRequest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !smsVerificationCollectionExists {
|
|
||||||
_, err = arangodb.CreateCollection(ctx, models.Collections.SMSVerificationRequest, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
smsVerificationCollection, err := arangodb.Collection(ctx, models.Collections.SMSVerificationRequest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
smsVerificationCollection.EnsureHashIndex(ctx, []string{"phone_number"}, &arangoDriver.EnsureHashIndexOptions{
|
|
||||||
Unique: true,
|
Unique: true,
|
||||||
Sparse: true,
|
Sparse: true,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package arangodb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package cassandradb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,17 +13,31 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
shouldCreate = true
|
shouldCreate = true
|
||||||
otp = &models.OTP{
|
otp = &models.OTP{
|
||||||
ID: uuid.NewString(),
|
ID: uuid.NewString(),
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
CreatedAt: time.Now().Unix(),
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
UpdatedAt: time.Now().Unix(),
|
CreatedAt: time.Now().Unix(),
|
||||||
|
UpdatedAt: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
otp.Otp = otpParam.Otp
|
otp.Otp = otpParam.Otp
|
||||||
|
@ -32,7 +47,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
query := ""
|
query := ""
|
||||||
if shouldCreate {
|
if shouldCreate {
|
||||||
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)
|
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)
|
||||||
} else {
|
} else {
|
||||||
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)
|
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)
|
||||||
}
|
}
|
||||||
|
@ -48,8 +63,19 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
// GetOTPByEmail to get otp for a given email address
|
// GetOTPByEmail to get otp for a given email address
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
var otp models.OTP
|
var otp models.OTP
|
||||||
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)
|
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)
|
||||||
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
var otp models.OTP
|
||||||
|
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)
|
||||||
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&otp.ID, &otp.Email, &otp.PhoneNumber, &otp.Otp, &otp.ExpiresAt, &otp.CreatedAt, &otp.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,7 +254,11 @@ func NewProvider() (*provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
otpIndexQueryPhoneNumber := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_otp_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.OTP)
|
||||||
|
err = session.Query(otpIndexQueryPhoneNumber).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &provider{
|
return &provider{
|
||||||
db: session,
|
db: session,
|
||||||
}, err
|
}, err
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package cassandradb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package couchbase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,24 +13,36 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
shouldCreate = true
|
shouldCreate = true
|
||||||
otp = &models.OTP{
|
otp = &models.OTP{
|
||||||
ID: uuid.NewString(),
|
ID: uuid.NewString(),
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
CreatedAt: time.Now().Unix(),
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
UpdatedAt: time.Now().Unix(),
|
CreatedAt: time.Now().Unix(),
|
||||||
|
UpdatedAt: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
otp.Otp = otpParam.Otp
|
otp.Otp = otpParam.Otp
|
||||||
otp.ExpiresAt = otpParam.ExpiresAt
|
otp.ExpiresAt = otpParam.ExpiresAt
|
||||||
}
|
}
|
||||||
|
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
if shouldCreate {
|
if shouldCreate {
|
||||||
insertOpt := gocb.InsertOptions{
|
insertOpt := gocb.InsertOptions{
|
||||||
|
@ -54,7 +67,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
// GetOTPByEmail to get otp for a given email address
|
// GetOTPByEmail to get otp for a given email address
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
otp := models.OTP{}
|
otp := models.OTP{}
|
||||||
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)
|
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)
|
||||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
PositionalParameters: []interface{}{emailAddress},
|
PositionalParameters: []interface{}{emailAddress},
|
||||||
|
@ -63,11 +76,27 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = q.One(&otp)
|
err = q.One(&otp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
otp := models.OTP{}
|
||||||
|
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)
|
||||||
|
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||||
|
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||||
|
PositionalParameters: []interface{}{phoneNumber},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = q.One(&otp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &otp, nil
|
return &otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,5 +166,9 @@ func GetIndex(scopeName string) map[string][]string {
|
||||||
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
|
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
|
||||||
indices[models.Collections.OTP] = []string{otpIndex1}
|
indices[models.Collections.OTP] = []string{otpIndex1}
|
||||||
|
|
||||||
|
// OTP index
|
||||||
|
otpIndex2 := fmt.Sprintf("CREATE INDEX OTPPhoneNumberIndex ON %s.%s(phone_number)", scopeName, models.Collections.OTP)
|
||||||
|
indices[models.Collections.OTP] = []string{otpIndex2}
|
||||||
|
|
||||||
return indices
|
return indices
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package couchbase
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -11,27 +11,39 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
// check if email or phone number is present
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
|
return nil, errors.New("email or phone_number is required")
|
||||||
|
}
|
||||||
|
uniqueField := models.FieldNameEmail
|
||||||
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
id := uuid.NewString()
|
id := uuid.NewString()
|
||||||
otp = &models.OTP{
|
otp = &models.OTP{
|
||||||
ID: id,
|
ID: id,
|
||||||
Key: id,
|
Key: id,
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
CreatedAt: time.Now().Unix(),
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
|
CreatedAt: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
shouldCreate = true
|
shouldCreate = true
|
||||||
} else {
|
} else {
|
||||||
otp.Otp = otpParam.Otp
|
otp.Otp = otpParam.Otp
|
||||||
otp.ExpiresAt = otpParam.ExpiresAt
|
otp.ExpiresAt = otpParam.ExpiresAt
|
||||||
}
|
}
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.OTP)
|
collection := p.db.Table(models.Collections.OTP)
|
||||||
otp.UpdatedAt = time.Now().Unix()
|
otp.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if shouldCreate {
|
if shouldCreate {
|
||||||
err = collection.Put(otp).RunWithContext(ctx)
|
err = collection.Put(otp).RunWithContext(ctx)
|
||||||
|
@ -41,7 +53,6 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return otp, nil
|
return otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,20 +60,32 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
var otps []models.OTP
|
var otps []models.OTP
|
||||||
var otp models.OTP
|
var otp models.OTP
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.OTP)
|
collection := p.db.Table(models.Collections.OTP)
|
||||||
|
|
||||||
err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps)
|
err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(otps) > 0 {
|
if len(otps) > 0 {
|
||||||
otp = otps[0]
|
otp = otps[0]
|
||||||
return &otp, nil
|
return &otp, nil
|
||||||
} else {
|
|
||||||
return nil, errors.New("no docuemnt found")
|
|
||||||
}
|
}
|
||||||
|
return nil, errors.New("no docuemnt found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
var otps []models.OTP
|
||||||
|
var otp models.OTP
|
||||||
|
collection := p.db.Table(models.Collections.OTP)
|
||||||
|
err := collection.Scan().Index("phone_number").Filter("'phone_number' = ?", phoneNumber).Limit(1).AllWithContext(ctx, &otps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(otps) > 0 {
|
||||||
|
otp = otps[0]
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("no docuemnt found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOTP to delete otp
|
// DeleteOTP to delete otp
|
||||||
|
@ -75,6 +98,5 @@ func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package dynamodb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -13,29 +13,31 @@ import (
|
||||||
|
|
||||||
// UpsertOTP to add or update otp
|
// UpsertOTP to add or update otp
|
||||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||||
// check if email or phone number is present
|
|
||||||
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
|
||||||
return nil, errors.New("email or phone_number is required")
|
|
||||||
}
|
|
||||||
// check if email or phone number is present
|
// check if email or phone number is present
|
||||||
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||||
return nil, errors.New("email or phone_number is required")
|
return nil, errors.New("email or phone_number is required")
|
||||||
}
|
}
|
||||||
uniqueField := models.FieldNameEmail
|
uniqueField := models.FieldNameEmail
|
||||||
if otp.Email == "" && otp.PhoneNumber != "" {
|
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||||
uniqueField = models.FieldNamePhoneNumber
|
uniqueField = models.FieldNamePhoneNumber
|
||||||
}
|
}
|
||||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
var otp *models.OTP
|
||||||
|
if uniqueField == models.FieldNameEmail {
|
||||||
|
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||||
|
} else {
|
||||||
|
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||||
|
}
|
||||||
shouldCreate := false
|
shouldCreate := false
|
||||||
if otp == nil {
|
if otp == nil {
|
||||||
id := uuid.NewString()
|
id := uuid.NewString()
|
||||||
otp = &models.OTP{
|
otp = &models.OTP{
|
||||||
ID: id,
|
ID: id,
|
||||||
Key: id,
|
Key: id,
|
||||||
Otp: otpParam.Otp,
|
Otp: otpParam.Otp,
|
||||||
Email: otpParam.Email,
|
Email: otpParam.Email,
|
||||||
ExpiresAt: otpParam.ExpiresAt,
|
PhoneNumber: otpParam.PhoneNumber,
|
||||||
CreatedAt: time.Now().Unix(),
|
ExpiresAt: otpParam.ExpiresAt,
|
||||||
|
CreatedAt: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
shouldCreate = true
|
shouldCreate = true
|
||||||
} else {
|
} else {
|
||||||
|
@ -54,20 +56,28 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return otp, nil
|
return otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOTPByEmail to get otp for a given email address
|
// GetOTPByEmail to get otp for a given email address
|
||||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||||
var otp models.OTP
|
var otp models.OTP
|
||||||
|
|
||||||
otpCollection := p.db.Collection(models.Collections.OTP, options.Collection())
|
otpCollection := p.db.Collection(models.Collections.OTP, options.Collection())
|
||||||
err := otpCollection.FindOne(ctx, bson.M{"email": emailAddress}).Decode(&otp)
|
err := otpCollection.FindOne(ctx, bson.M{"email": emailAddress}).Decode(&otp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &otp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
var otp models.OTP
|
||||||
|
otpCollection := p.db.Collection(models.Collections.OTP, options.Collection())
|
||||||
|
err := otpCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&otp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &otp, nil
|
return &otp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,15 +125,6 @@ func NewProvider() (*provider, error) {
|
||||||
},
|
},
|
||||||
}, options.CreateIndexes())
|
}, options.CreateIndexes())
|
||||||
|
|
||||||
mongodb.CreateCollection(ctx, models.Collections.SMSVerificationRequest, options.CreateCollection())
|
|
||||||
smsCollection := mongodb.Collection(models.Collections.SMSVerificationRequest, options.Collection())
|
|
||||||
smsCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
|
|
||||||
{
|
|
||||||
Keys: bson.M{"phone_number": 1},
|
|
||||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
|
||||||
},
|
|
||||||
}, options.CreateIndexes())
|
|
||||||
|
|
||||||
return &provider{
|
return &provider{
|
||||||
db: mongodb,
|
db: mongodb,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
package mongodb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
|
|
||||||
smsVerificationRequest, _ := p.GetCodeByPhone(ctx, smsRequest.PhoneNumber)
|
|
||||||
// Boolean to check if we should create a new record or update the existing one
|
|
||||||
shouldCreate := false
|
|
||||||
if smsVerificationRequest == nil {
|
|
||||||
id := uuid.NewString()
|
|
||||||
smsVerificationRequest = &models.SMSVerificationRequest{
|
|
||||||
ID: id,
|
|
||||||
CreatedAt: time.Now().Unix(),
|
|
||||||
Code: smsRequest.Code,
|
|
||||||
PhoneNumber: smsRequest.PhoneNumber,
|
|
||||||
CodeExpiresAt: smsRequest.CodeExpiresAt,
|
|
||||||
}
|
|
||||||
shouldCreate = true
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
smsVerificationRequest.UpdatedAt = time.Now().Unix()
|
|
||||||
smsRequestCollection := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection())
|
|
||||||
if shouldCreate {
|
|
||||||
_, err = smsRequestCollection.InsertOne(ctx, smsVerificationRequest)
|
|
||||||
} else {
|
|
||||||
_, err = smsRequestCollection.UpdateOne(ctx, bson.M{"phone_number": bson.M{"$eq": smsRequest.PhoneNumber}}, bson.M{"$set": smsVerificationRequest}, options.MergeUpdateOptions())
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return smsVerificationRequest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) {
|
|
||||||
var smsVerificationRequest models.SMSVerificationRequest
|
|
||||||
|
|
||||||
smsRequestCollection := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection())
|
|
||||||
err := smsRequestCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&smsVerificationRequest)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &smsVerificationRequest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error {
|
|
||||||
smsVerificationRequests := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection())
|
|
||||||
_, err := smsVerificationRequests.DeleteOne(nil, bson.M{"_id": smsRequest.ID}, options.Delete())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -16,6 +16,11 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOTPByPhoneNumber to get otp for a given phone number
|
||||||
|
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteOTP to delete otp
|
// DeleteOTP to delete otp
|
||||||
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package provider_template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -86,11 +86,4 @@ type Provider interface {
|
||||||
GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error)
|
GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error)
|
||||||
// DeleteOTP to delete otp
|
// DeleteOTP to delete otp
|
||||||
DeleteOTP(ctx context.Context, otp *models.OTP) error
|
DeleteOTP(ctx context.Context, otp *models.OTP) error
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error)
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error)
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func NewProvider() (*provider, error) {
|
||||||
logrus.Debug("Failed to drop phone number constraint:", err)
|
logrus.Debug("Failed to drop phone number constraint:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, models.WebhookLog{}, models.EmailTemplate{}, &models.OTP{}, &models.SMSVerificationRequest{})
|
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, models.WebhookLog{}, models.EmailTemplate{}, &models.OTP{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"gorm.io/gorm/clause"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpsertSMSRequest adds/updates SMS verification request
|
|
||||||
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
|
|
||||||
if smsRequest.ID == "" {
|
|
||||||
smsRequest.ID = uuid.New().String()
|
|
||||||
}
|
|
||||||
smsRequest.CreatedAt = time.Now().Unix()
|
|
||||||
smsRequest.UpdatedAt = time.Now().Unix()
|
|
||||||
res := p.db.Clauses(clause.OnConflict{
|
|
||||||
Columns: []clause.Column{{Name: "phone_number"}},
|
|
||||||
DoUpdates: clause.AssignmentColumns([]string{"code", "code_expires_at", "updated_at"}),
|
|
||||||
}).Create(smsRequest)
|
|
||||||
if res.Error != nil {
|
|
||||||
return nil, res.Error
|
|
||||||
}
|
|
||||||
return smsRequest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCodeByPhone to get code for a given phone number
|
|
||||||
func (p *provider) GetCodeByPhone(ctx context.Context, phoneNumber string) (*models.SMSVerificationRequest, error) {
|
|
||||||
var sms_verification_request models.SMSVerificationRequest
|
|
||||||
|
|
||||||
result := p.db.Where("phone_number = ?", phoneNumber).First(&sms_verification_request)
|
|
||||||
if result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
return &sms_verification_request, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSMSRequest to delete SMS verification request
|
|
||||||
func (p *provider) DeleteSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) error {
|
|
||||||
result := p.db.Delete(&models.SMSVerificationRequest{
|
|
||||||
ID: smsRequest.ID,
|
|
||||||
})
|
|
||||||
if result.Error != nil {
|
|
||||||
return result.Error
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -198,7 +198,6 @@ type ComplexityRoot struct {
|
||||||
UpdateUser func(childComplexity int, params model.UpdateUserInput) int
|
UpdateUser func(childComplexity int, params model.UpdateUserInput) int
|
||||||
UpdateWebhook func(childComplexity int, params model.UpdateWebhookRequest) int
|
UpdateWebhook func(childComplexity int, params model.UpdateWebhookRequest) int
|
||||||
VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int
|
VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int
|
||||||
VerifyMobile func(childComplexity int, params model.VerifyMobileRequest) int
|
|
||||||
VerifyOtp func(childComplexity int, params model.VerifyOTPRequest) int
|
VerifyOtp func(childComplexity int, params model.VerifyOTPRequest) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +343,6 @@ type MutationResolver interface {
|
||||||
Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error)
|
Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error)
|
||||||
VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error)
|
VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error)
|
||||||
ResendOtp(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error)
|
ResendOtp(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error)
|
||||||
VerifyMobile(ctx context.Context, params model.VerifyMobileRequest) (*model.AuthResponse, error)
|
|
||||||
DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error)
|
DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error)
|
||||||
UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error)
|
UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error)
|
||||||
AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error)
|
AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error)
|
||||||
|
@ -1438,18 +1436,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Mutation.VerifyEmail(childComplexity, args["params"].(model.VerifyEmailInput)), true
|
return e.complexity.Mutation.VerifyEmail(childComplexity, args["params"].(model.VerifyEmailInput)), true
|
||||||
|
|
||||||
case "Mutation.verify_mobile":
|
|
||||||
if e.complexity.Mutation.VerifyMobile == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
args, err := ec.field_Mutation_verify_mobile_args(context.TODO(), rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.Mutation.VerifyMobile(childComplexity, args["params"].(model.VerifyMobileRequest)), true
|
|
||||||
|
|
||||||
case "Mutation.verify_otp":
|
case "Mutation.verify_otp":
|
||||||
if e.complexity.Mutation.VerifyOtp == nil {
|
if e.complexity.Mutation.VerifyOtp == nil {
|
||||||
break
|
break
|
||||||
|
@ -2120,7 +2106,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||||
ec.unmarshalInputValidateJWTTokenInput,
|
ec.unmarshalInputValidateJWTTokenInput,
|
||||||
ec.unmarshalInputValidateSessionInput,
|
ec.unmarshalInputValidateSessionInput,
|
||||||
ec.unmarshalInputVerifyEmailInput,
|
ec.unmarshalInputVerifyEmailInput,
|
||||||
ec.unmarshalInputVerifyMobileRequest,
|
|
||||||
ec.unmarshalInputVerifyOTPRequest,
|
ec.unmarshalInputVerifyOTPRequest,
|
||||||
ec.unmarshalInputWebhookRequest,
|
ec.unmarshalInputWebhookRequest,
|
||||||
)
|
)
|
||||||
|
@ -2269,11 +2254,6 @@ type SMSVerificationRequests {
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyMobileRequest {
|
|
||||||
phone_number: String!
|
|
||||||
code: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Error {
|
type Error {
|
||||||
message: String!
|
message: String!
|
||||||
reason: String!
|
reason: String!
|
||||||
|
@ -2728,7 +2708,9 @@ input DeleteEmailTemplateRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyOTPRequest {
|
input VerifyOTPRequest {
|
||||||
email: String!
|
# either email or phone_number is required
|
||||||
|
email: String
|
||||||
|
phone_number: String
|
||||||
otp: String!
|
otp: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
|
@ -2764,7 +2746,6 @@ type Mutation {
|
||||||
revoke(params: OAuthRevokeInput!): Response!
|
revoke(params: OAuthRevokeInput!): Response!
|
||||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||||
resend_otp(params: ResendOTPRequest!): Response!
|
resend_otp(params: ResendOTPRequest!): Response!
|
||||||
verify_mobile(params: VerifyMobileRequest!): AuthResponse!
|
|
||||||
# admin only apis
|
# admin only apis
|
||||||
_delete_user(params: DeleteUserInput!): Response!
|
_delete_user(params: DeleteUserInput!): Response!
|
||||||
_update_user(params: UpdateUserInput!): User!
|
_update_user(params: UpdateUserInput!): User!
|
||||||
|
@ -3230,21 +3211,6 @@ func (ec *executionContext) field_Mutation_verify_email_args(ctx context.Context
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_verify_mobile_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
|
||||||
var err error
|
|
||||||
args := map[string]interface{}{}
|
|
||||||
var arg0 model.VerifyMobileRequest
|
|
||||||
if tmp, ok := rawArgs["params"]; ok {
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
|
|
||||||
arg0, err = ec.unmarshalNVerifyMobileRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyMobileRequest(ctx, tmp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
args["params"] = arg0
|
|
||||||
return args, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_verify_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation_verify_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
|
@ -8635,77 +8601,6 @@ func (ec *executionContext) fieldContext_Mutation_resend_otp(ctx context.Context
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_verify_mobile(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
|
||||||
fc, err := ec.fieldContext_Mutation_verify_mobile(ctx, field)
|
|
||||||
if err != nil {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
|
||||||
ret = graphql.Null
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
|
||||||
ctx = rctx // use context from middleware stack in children
|
|
||||||
return ec.resolvers.Mutation().VerifyMobile(rctx, fc.Args["params"].(model.VerifyMobileRequest))
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
if resTmp == nil {
|
|
||||||
if !graphql.HasFieldError(ctx, fc) {
|
|
||||||
ec.Errorf(ctx, "must not be null")
|
|
||||||
}
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
res := resTmp.(*model.AuthResponse)
|
|
||||||
fc.Result = res
|
|
||||||
return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_Mutation_verify_mobile(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
|
||||||
fc = &graphql.FieldContext{
|
|
||||||
Object: "Mutation",
|
|
||||||
Field: field,
|
|
||||||
IsMethod: true,
|
|
||||||
IsResolver: true,
|
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
|
||||||
switch field.Name {
|
|
||||||
case "message":
|
|
||||||
return ec.fieldContext_AuthResponse_message(ctx, field)
|
|
||||||
case "should_show_otp_screen":
|
|
||||||
return ec.fieldContext_AuthResponse_should_show_otp_screen(ctx, field)
|
|
||||||
case "access_token":
|
|
||||||
return ec.fieldContext_AuthResponse_access_token(ctx, field)
|
|
||||||
case "id_token":
|
|
||||||
return ec.fieldContext_AuthResponse_id_token(ctx, field)
|
|
||||||
case "refresh_token":
|
|
||||||
return ec.fieldContext_AuthResponse_refresh_token(ctx, field)
|
|
||||||
case "expires_in":
|
|
||||||
return ec.fieldContext_AuthResponse_expires_in(ctx, field)
|
|
||||||
case "user":
|
|
||||||
return ec.fieldContext_AuthResponse_user(ctx, field)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("no field named %q was found under type AuthResponse", field.Name)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
err = ec.Recover(ctx, r)
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
|
||||||
if fc.Args, err = ec.field_Mutation_verify_mobile_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return fc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation__delete_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation__delete_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Mutation__delete_user(ctx, field)
|
fc, err := ec.fieldContext_Mutation__delete_user(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17781,42 +17676,6 @@ func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context,
|
||||||
return it, nil
|
return it, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputVerifyMobileRequest(ctx context.Context, obj interface{}) (model.VerifyMobileRequest, error) {
|
|
||||||
var it model.VerifyMobileRequest
|
|
||||||
asMap := map[string]interface{}{}
|
|
||||||
for k, v := range obj.(map[string]interface{}) {
|
|
||||||
asMap[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"phone_number", "code"}
|
|
||||||
for _, k := range fieldsInOrder {
|
|
||||||
v, ok := asMap[k]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch k {
|
|
||||||
case "phone_number":
|
|
||||||
var err error
|
|
||||||
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
|
|
||||||
it.PhoneNumber, err = ec.unmarshalNString2string(ctx, v)
|
|
||||||
if err != nil {
|
|
||||||
return it, err
|
|
||||||
}
|
|
||||||
case "code":
|
|
||||||
var err error
|
|
||||||
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("code"))
|
|
||||||
it.Code, err = ec.unmarshalNString2string(ctx, v)
|
|
||||||
if err != nil {
|
|
||||||
return it, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return it, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, obj interface{}) (model.VerifyOTPRequest, error) {
|
func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context, obj interface{}) (model.VerifyOTPRequest, error) {
|
||||||
var it model.VerifyOTPRequest
|
var it model.VerifyOTPRequest
|
||||||
asMap := map[string]interface{}{}
|
asMap := map[string]interface{}{}
|
||||||
|
@ -17824,7 +17683,7 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"email", "otp", "state"}
|
fieldsInOrder := [...]string{"email", "phone_number", "otp", "state"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -17835,7 +17694,15 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
|
||||||
it.Email, err = ec.unmarshalNString2string(ctx, v)
|
it.Email, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "phone_number":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
|
||||||
|
it.PhoneNumber, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
|
@ -18723,15 +18590,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||||
return ec._Mutation_resend_otp(ctx, field)
|
return ec._Mutation_resend_otp(ctx, field)
|
||||||
})
|
})
|
||||||
|
|
||||||
if out.Values[i] == graphql.Null {
|
|
||||||
invalids++
|
|
||||||
}
|
|
||||||
case "verify_mobile":
|
|
||||||
|
|
||||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
|
||||||
return ec._Mutation_verify_mobile(ctx, field)
|
|
||||||
})
|
|
||||||
|
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
@ -20798,11 +20656,6 @@ func (ec *executionContext) unmarshalNVerifyEmailInput2githubᚗcomᚋauthorizer
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNVerifyMobileRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyMobileRequest(ctx context.Context, v interface{}) (model.VerifyMobileRequest, error) {
|
|
||||||
res, err := ec.unmarshalInputVerifyMobileRequest(ctx, v)
|
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNVerifyOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyOTPRequest(ctx context.Context, v interface{}) (model.VerifyOTPRequest, error) {
|
func (ec *executionContext) unmarshalNVerifyOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerifyOTPRequest(ctx context.Context, v interface{}) (model.VerifyOTPRequest, error) {
|
||||||
res, err := ec.unmarshalInputVerifyOTPRequest(ctx, v)
|
res, err := ec.unmarshalInputVerifyOTPRequest(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
|
|
@ -486,15 +486,11 @@ type VerifyEmailInput struct {
|
||||||
State *string `json:"state"`
|
State *string `json:"state"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerifyMobileRequest struct {
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type VerifyOTPRequest struct {
|
type VerifyOTPRequest struct {
|
||||||
Email string `json:"email"`
|
Email *string `json:"email"`
|
||||||
Otp string `json:"otp"`
|
PhoneNumber *string `json:"phone_number"`
|
||||||
State *string `json:"state"`
|
Otp string `json:"otp"`
|
||||||
|
State *string `json:"state"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Webhook struct {
|
type Webhook struct {
|
||||||
|
|
|
@ -84,11 +84,6 @@ type SMSVerificationRequests {
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyMobileRequest {
|
|
||||||
phone_number: String!
|
|
||||||
code: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Error {
|
type Error {
|
||||||
message: String!
|
message: String!
|
||||||
reason: String!
|
reason: String!
|
||||||
|
@ -543,7 +538,9 @@ input DeleteEmailTemplateRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyOTPRequest {
|
input VerifyOTPRequest {
|
||||||
email: String!
|
# either email or phone_number is required
|
||||||
|
email: String
|
||||||
|
phone_number: String
|
||||||
otp: String!
|
otp: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
|
@ -579,7 +576,6 @@ type Mutation {
|
||||||
revoke(params: OAuthRevokeInput!): Response!
|
revoke(params: OAuthRevokeInput!): Response!
|
||||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||||
resend_otp(params: ResendOTPRequest!): Response!
|
resend_otp(params: ResendOTPRequest!): Response!
|
||||||
verify_mobile(params: VerifyMobileRequest!): AuthResponse!
|
|
||||||
# admin only apis
|
# admin only apis
|
||||||
_delete_user(params: DeleteUserInput!): Response!
|
_delete_user(params: DeleteUserInput!): Response!
|
||||||
_update_user(params: UpdateUserInput!): User!
|
_update_user(params: UpdateUserInput!): User!
|
||||||
|
|
|
@ -81,11 +81,6 @@ func (r *mutationResolver) ResendOtp(ctx context.Context, params model.ResendOTP
|
||||||
return resolvers.ResendOTPResolver(ctx, params)
|
return resolvers.ResendOTPResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyMobile is the resolver for the verify_mobile field.
|
|
||||||
func (r *mutationResolver) VerifyMobile(ctx context.Context, params model.VerifyMobileRequest) (*model.AuthResponse, error) {
|
|
||||||
return resolvers.VerifyMobileResolver(ctx, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteUser is the resolver for the _delete_user field.
|
// DeleteUser is the resolver for the _delete_user field.
|
||||||
func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) {
|
func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) {
|
||||||
return resolvers.DeleteUserResolver(ctx, params)
|
return resolvers.DeleteUserResolver(ctx, params)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
|
@ -17,9 +17,9 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/smsproviders"
|
||||||
"github.com/authorizerdev/authorizer/server/token"
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/authorizerdev/authorizer/server/smsproviders"
|
|
||||||
"github.com/authorizerdev/authorizer/server/validators"
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -133,8 +133,8 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
user := models.User{
|
user := models.User{
|
||||||
Email: emailInput,
|
Email: emailInput,
|
||||||
PhoneNumber: &mobile,
|
PhoneNumber: &mobile,
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Roles = strings.Join(inputRoles, ",")
|
user.Roles = strings.Join(inputRoles, ",")
|
||||||
|
@ -179,7 +179,7 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput)
|
||||||
log.Debug("MFA service not enabled: ", err)
|
log.Debug("MFA service not enabled: ", err)
|
||||||
isMFAEnforced = false
|
isMFAEnforced = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if isMFAEnforced {
|
if isMFAEnforced {
|
||||||
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
||||||
}
|
}
|
||||||
|
@ -197,11 +197,11 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput)
|
||||||
log.Debug("Failed to add user: ", err)
|
log.Debug("Failed to add user: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !disablePhoneVerification {
|
if !disablePhoneVerification {
|
||||||
duration, _ := time.ParseDuration("10m")
|
duration, _ := time.ParseDuration("10m")
|
||||||
smsCode := utils.GenerateOTP()
|
smsCode := utils.GenerateOTP()
|
||||||
|
|
||||||
smsBody := strings.Builder{}
|
smsBody := strings.Builder{}
|
||||||
smsBody.WriteString("Your verification code is: ")
|
smsBody.WriteString("Your verification code is: ")
|
||||||
smsBody.WriteString(smsCode)
|
smsBody.WriteString(smsCode)
|
||||||
|
@ -213,10 +213,10 @@ func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
db.Provider.UpsertSMSRequest(ctx, &models.SMSVerificationRequest{
|
db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
PhoneNumber: mobile,
|
PhoneNumber: mobile,
|
||||||
Code: smsCode,
|
Otp: smsCode,
|
||||||
CodeExpiresAt: time.Now().Add(duration).Unix(),
|
ExpiresAt: time.Now().Add(duration).Unix(),
|
||||||
})
|
})
|
||||||
smsproviders.SendSMS(mobile, smsBody.String())
|
smsproviders.SendSMS(mobile, smsBody.String())
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
package resolvers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func VerifyMobileResolver(ctx context.Context, params model.VerifyMobileRequest) (*model.AuthResponse, error) {
|
|
||||||
var res *model.AuthResponse
|
|
||||||
|
|
||||||
_, err := utils.GinContextFromContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
smsVerificationRequest, err := db.Provider.GetCodeByPhone(ctx, params.PhoneNumber)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to get sms request by phone: ", err)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if smsVerificationRequest.Code != params.Code {
|
|
||||||
log.Debug("Failed to verify request: bad credentials")
|
|
||||||
return res, fmt.Errorf(`bad credentials`)
|
|
||||||
}
|
|
||||||
|
|
||||||
expiresIn := smsVerificationRequest.CodeExpiresAt - time.Now().Unix()
|
|
||||||
if expiresIn < 0 {
|
|
||||||
log.Debug("Failed to verify sms request: Timeout")
|
|
||||||
return res, fmt.Errorf("time expired")
|
|
||||||
}
|
|
||||||
|
|
||||||
res = &model.AuthResponse{
|
|
||||||
Message: "successful",
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := db.Provider.GetUserByPhoneNumber(ctx, params.PhoneNumber)
|
|
||||||
if user.PhoneNumberVerifiedAt == nil {
|
|
||||||
now := time.Now().Unix()
|
|
||||||
user.PhoneNumberVerifiedAt = &now
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = db.Provider.UpdateUser(ctx, *user)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to update user: ", err)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = db.Provider.DeleteSMSRequest(ctx, smsVerificationRequest)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to delete sms request: ", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
|
@ -27,36 +27,53 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
if refs.StringValue(params.Email) == "" && refs.StringValue(params.PhoneNumber) == "" {
|
||||||
otp, err := db.Provider.GetOTPByEmail(ctx, params.Email)
|
log.Debug("Email or phone number is required")
|
||||||
if err != nil {
|
return res, fmt.Errorf(`email or phone_number is required`)
|
||||||
log.Debug("Failed to get otp request by email: ", err)
|
|
||||||
return res, fmt.Errorf(`invalid email: %s`, err.Error())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentField := models.FieldNameEmail
|
||||||
|
if refs.StringValue(params.Email) == "" {
|
||||||
|
currentField = models.FieldNamePhoneNumber
|
||||||
|
}
|
||||||
|
var otp *models.OTP
|
||||||
|
if currentField == models.FieldNameEmail {
|
||||||
|
otp, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email))
|
||||||
|
} else {
|
||||||
|
otp, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber))
|
||||||
|
}
|
||||||
|
if otp == nil && err != nil {
|
||||||
|
log.Debugf("Failed to get otp request for %s: %s", currentField, err.Error())
|
||||||
|
return res, fmt.Errorf(`invalid %s: %s`, currentField, err.Error())
|
||||||
|
}
|
||||||
if params.Otp != otp.Otp {
|
if params.Otp != otp.Otp {
|
||||||
log.Debug("Failed to verify otp request: Incorrect value")
|
log.Debug("Failed to verify otp request: Incorrect value")
|
||||||
return res, fmt.Errorf(`invalid otp`)
|
return res, fmt.Errorf(`invalid otp`)
|
||||||
}
|
}
|
||||||
|
|
||||||
expiresIn := otp.ExpiresAt - time.Now().Unix()
|
expiresIn := otp.ExpiresAt - time.Now().Unix()
|
||||||
|
|
||||||
if expiresIn < 0 {
|
if expiresIn < 0 {
|
||||||
log.Debug("Failed to verify otp request: Timeout")
|
log.Debug("Failed to verify otp request: Timeout")
|
||||||
return res, fmt.Errorf("otp expired")
|
return res, fmt.Errorf("otp expired")
|
||||||
}
|
}
|
||||||
|
var user models.User
|
||||||
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
if currentField == models.FieldNameEmail {
|
||||||
if err != nil {
|
user, err = db.Provider.GetUserByEmail(ctx, refs.StringValue(params.Email))
|
||||||
|
} else {
|
||||||
|
// TODO fix after refs of db providers are fixed
|
||||||
|
var u *models.User
|
||||||
|
u, err = db.Provider.GetUserByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber))
|
||||||
|
user = *u
|
||||||
|
}
|
||||||
|
if user.ID == "" && err != nil {
|
||||||
log.Debug("Failed to get user by email: ", err)
|
log.Debug("Failed to get user by email: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
isSignUp := user.EmailVerifiedAt == nil && user.PhoneNumberVerifiedAt == nil
|
||||||
isSignUp := user.EmailVerifiedAt == nil
|
|
||||||
|
|
||||||
// TODO - Add Login method in DB when we introduce OTP for social media login
|
// TODO - Add Login method in DB when we introduce OTP for social media login
|
||||||
loginMethod := constants.AuthRecipeMethodBasicAuth
|
loginMethod := constants.AuthRecipeMethodBasicAuth
|
||||||
|
if currentField == models.FieldNamePhoneNumber {
|
||||||
|
loginMethod = constants.AuthRecipeMethodMobileOTP
|
||||||
|
}
|
||||||
roles := strings.Split(user.Roles, ",")
|
roles := strings.Split(user.Roles, ",")
|
||||||
scope := []string{"openid", "email", "profile"}
|
scope := []string{"openid", "email", "profile"}
|
||||||
code := ""
|
code := ""
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -54,17 +54,17 @@ func mobileLoginTests(t *testing.T, s TestSetup) {
|
||||||
assert.NotNil(t, err, "should fail because phone is not verified")
|
assert.NotNil(t, err, "should fail because phone is not verified")
|
||||||
assert.Nil(t, res)
|
assert.Nil(t, res)
|
||||||
|
|
||||||
smsRequest, err := db.Provider.GetCodeByPhone(ctx, phoneNumber)
|
smsRequest, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, smsRequest.Code)
|
assert.NotEmpty(t, smsRequest.Otp)
|
||||||
|
|
||||||
verifySMSRequest, err := resolvers.VerifyMobileResolver(ctx, model.VerifyMobileRequest{
|
verifySMSRequest, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
PhoneNumber: phoneNumber,
|
PhoneNumber: &phoneNumber,
|
||||||
Code: smsRequest.Code,
|
Otp: smsRequest.Otp,
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotEqual(t, verifySMSRequest.Message, "", "message should not be empty")
|
assert.NotEqual(t, verifySMSRequest.Message, "", "message should not be empty")
|
||||||
|
|
||||||
res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
|
res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
|
||||||
PhoneNumber: phoneNumber,
|
PhoneNumber: phoneNumber,
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
|
|
|
@ -84,13 +84,13 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
||||||
|
|
||||||
// Should return error for older otp
|
// Should return error for older otp
|
||||||
verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
Email: email,
|
Email: &email,
|
||||||
Otp: otp.Otp,
|
Otp: otp.Otp,
|
||||||
})
|
})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Nil(t, verifyOtpRes)
|
assert.Nil(t, verifyOtpRes)
|
||||||
verifyOtpRes, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
verifyOtpRes, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
Email: email,
|
Email: &email,
|
||||||
Otp: newOtp.Otp,
|
Otp: newOtp.Otp,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -135,7 +135,6 @@ func TestResolvers(t *testing.T) {
|
||||||
validateJwtTokenTest(t, s)
|
validateJwtTokenTest(t, s)
|
||||||
verifyOTPTest(t, s)
|
verifyOTPTest(t, s)
|
||||||
resendOTPTest(t, s)
|
resendOTPTest(t, s)
|
||||||
verifyMobileTest(t, s)
|
|
||||||
validateSessionTests(t, s)
|
validateSessionTests(t, s)
|
||||||
|
|
||||||
updateAllUsersTest(t, s)
|
updateAllUsersTest(t, s)
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func verifyMobileTest(t *testing.T, s TestSetup) {
|
|
||||||
t.Helper()
|
|
||||||
t.Run(`should verify mobile`, func(t *testing.T) {
|
|
||||||
_, ctx := createContext(s)
|
|
||||||
email := "mobile_verification." + s.TestInfo.Email
|
|
||||||
phoneNumber := "2234567890"
|
|
||||||
signUpRes, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
|
||||||
Email: refs.NewStringRef(email),
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
Password: s.TestInfo.Password,
|
|
||||||
ConfirmPassword: s.TestInfo.Password,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, signUpRes)
|
|
||||||
assert.Equal(t, email, signUpRes.User.Email)
|
|
||||||
assert.Equal(t, phoneNumber, refs.StringValue(signUpRes.User.PhoneNumber))
|
|
||||||
assert.True(t, strings.Contains(signUpRes.User.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth))
|
|
||||||
assert.Len(t, strings.Split(signUpRes.User.SignupMethods, ","), 1)
|
|
||||||
|
|
||||||
res, err := resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
Password: "random_test",
|
|
||||||
})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, res)
|
|
||||||
|
|
||||||
// should fail because phone is not verified
|
|
||||||
res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
Password: s.TestInfo.Password,
|
|
||||||
})
|
|
||||||
assert.NotNil(t, err, "should fail because phone is not verified")
|
|
||||||
assert.Nil(t, res)
|
|
||||||
|
|
||||||
// get code from db
|
|
||||||
smsRequest, err := db.Provider.GetCodeByPhone(ctx, phoneNumber)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotEmpty(t, smsRequest.Code)
|
|
||||||
|
|
||||||
// throw an error if the code is not correct
|
|
||||||
verifySMSRequest, err := resolvers.VerifyMobileResolver(ctx, model.VerifyMobileRequest{
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
Code: "rand_12@1",
|
|
||||||
})
|
|
||||||
assert.NotNil(t, err, "should fail because of bad credentials")
|
|
||||||
assert.Nil(t, verifySMSRequest)
|
|
||||||
|
|
||||||
verifySMSRequest, err = resolvers.VerifyMobileResolver(ctx, model.VerifyMobileRequest{
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
Code: smsRequest.Code,
|
|
||||||
})
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotEqual(t, verifySMSRequest.Message, "", "message should not be empty")
|
|
||||||
|
|
||||||
res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
Password: s.TestInfo.Password,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotEmpty(t, res.AccessToken)
|
|
||||||
assert.NotEmpty(t, res.IDToken)
|
|
||||||
|
|
||||||
cleanData(email)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -65,7 +65,7 @@ func verifyOTPTest(t *testing.T, s TestSetup) {
|
||||||
assert.NotEmpty(t, otp.Otp)
|
assert.NotEmpty(t, otp.Otp)
|
||||||
|
|
||||||
verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
verifyOtpRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
Email: email,
|
Email: &email,
|
||||||
Otp: otp.Otp,
|
Otp: otp.Otp,
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user