feat: add totp login API (#416)
* fix: * removed hasReversedValue in playground * feat: * added totp methods in db's providers * adding totp in login method * feat: * added toggle in dashboard * fixing issue with env set * feat: * integrated totp * feat: * encrypted userid * added totp_verified column in user table * started test for totp * feat: * test cases totp * test-cases: * completed test cases * tested for all dbs * fixes: * return variable to snake case * import refactoring * feat: * created seperate folder for authenticator with totp subfolder * refactored code * created new table for authenticators * added recovery code for totp * feat: * adding functions to different db providers * feat: * added authenticators method for all db * feat: * added logic for updating mfa in user_profile update * fix: * merge conflict * fix: * resolved mongodb, dynamodb and arangodb test case bug * added new condition for checking first time totp user or not * feat: * changes in all respective db with authenticator * fix: * PR suggested changes * fix(cassandra): list users * Update verify otp * fix totp login api --------- Co-authored-by: lemonScaletech <anand.panigrahi@scaletech.xyz>
This commit is contained in:
81
server/db/providers/couchbase/authenticator.go
Normal file
81
server/db/providers/couchbase/authenticator.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
)
|
||||
|
||||
func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
exists, _ := p.GetAuthenticatorDetailsByUserId(ctx, authenticators.UserID, authenticators.Method)
|
||||
if exists != nil {
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
if authenticators.ID == "" {
|
||||
authenticators.ID = uuid.New().String()
|
||||
}
|
||||
authenticators.Key = authenticators.ID
|
||||
authenticators.CreatedAt = time.Now().Unix()
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *models.Authenticator) (*models.Authenticator, error) {
|
||||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
bytes, err := json.Marshal(authenticators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
decoder.UseNumber()
|
||||
authenticator := map[string]interface{}{}
|
||||
err = decoder.Decode(&authenticator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updateFields, params := GetSetFields(authenticator)
|
||||
query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = '%s'", p.scopeName, models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
||||
func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId string, authenticatorType string) (*models.Authenticator, error) {
|
||||
var authenticators *models.Authenticator
|
||||
query := fmt.Sprintf("SELECT _id, user_id, method, secret, recovery_code, verified_at, created_at, updated_at FROM %s.%s WHERE user_id = $1 AND method = $2 LIMIT 1", p.scopeName, models.Collections.Authenticators)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{userId, authenticatorType},
|
||||
})
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
}
|
||||
err = q.One(&authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
@@ -43,10 +43,10 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
||||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.User, error) {
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
unsertOpt := gocb.UpsertOptions{
|
||||
upsertOpt := gocb.UpsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &unsertOpt)
|
||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
Reference in New Issue
Block a user