Merge pull request #307 from authorizerdev/feat/mobile-basic-auth
feat: add mobile based basic auth
This commit is contained in:
commit
4f810d2f8b
|
@ -3,6 +3,8 @@ package constants
|
||||||
const (
|
const (
|
||||||
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
||||||
AuthRecipeMethodBasicAuth = "basic_auth"
|
AuthRecipeMethodBasicAuth = "basic_auth"
|
||||||
|
// AuthRecipeMethodMobileBasicAuth is the mobile basic_auth method, where user can signup using mobile number and password
|
||||||
|
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"
|
||||||
// AuthRecipeMethodGoogle is the google auth method
|
// AuthRecipeMethodGoogle is the google auth method
|
||||||
|
|
|
@ -125,6 +125,8 @@ const (
|
||||||
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
||||||
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
||||||
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
||||||
|
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_MOBILE_BASIC_AUTH
|
||||||
|
EnvKeyDisableMobileBasicAuthentication = "DISABLE_MOBILE_BASIC_AUTHENTICATION"
|
||||||
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
||||||
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
||||||
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
|
@ -32,6 +33,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
|
@ -48,6 +55,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
// UpdateUser to update user information in database
|
// UpdateUser to update user information in database
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -211,3 +219,34 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User)
|
||||||
|
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 user.Key == "" {
|
||||||
|
return nil, fmt.Errorf("user not found")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err := cursor.ReadDocument(ctx, &user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -161,6 +161,12 @@ func NewProvider() (*provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userPhoneNumberIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.User)
|
||||||
|
err = session.Query(userPhoneNumberIndexQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// add is_multi_factor_auth_enabled on users table
|
// add is_multi_factor_auth_enabled on users table
|
||||||
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User)
|
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User)
|
||||||
err = session.Query(userTableAlterQuery).Exec()
|
err = session.Query(userTableAlterQuery).Exec()
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"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/gocql/gocql"
|
"github.com/gocql/gocql"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
@ -30,6 +31,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
@ -299,3 +306,14 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, phoneNumber)
|
||||||
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro
|
||||||
|
|
||||||
// UpdateEnv to update environment information in database
|
// UpdateEnv to update environment information in database
|
||||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.Env)
|
collection := p.db.Table(models.Collections.Env)
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,15 @@ package dynamodb
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"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/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/guregu/dynamo"
|
"github.com/guregu/dynamo"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -30,6 +33,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
@ -193,3 +202,23 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var users []models.User
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
collection := p.db.Table(models.Collections.User)
|
||||||
|
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) > 0 {
|
||||||
|
user = users[0]
|
||||||
|
return &user, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("no record found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -155,3 +155,16 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||||
|
err := userCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -69,3 +69,10 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user *models.User
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ type Provider interface {
|
||||||
ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
|
ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
|
||||||
// GetUserByEmail to get user information from database using email address
|
// GetUserByEmail to get user information from database using email address
|
||||||
GetUserByEmail(ctx context.Context, email string) (models.User, error)
|
GetUserByEmail(ctx context.Context, email string) (models.User, error)
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error)
|
||||||
// GetUserByID to get user information from database using user ID
|
// GetUserByID to get user information from database using user ID
|
||||||
GetUserByID(ctx context.Context, id string) (models.User, error)
|
GetUserByID(ctx context.Context, id string) (models.User, error)
|
||||||
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
||||||
|
|
|
@ -31,7 +31,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
if u, _ := p.GetUserByPhone(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
|
||||||
if u, _ := p.GetUserByPhone(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := p.db.Save(&user)
|
result := p.db.Save(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
|
@ -156,12 +150,13 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) GetUserByPhone(ctx context.Context, phoneNumber string) (*models.User, error) {
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
var user *models.User
|
var user *models.User
|
||||||
result := p.db.Where("phone_number = ?", phoneNumber).First(&user)
|
result := p.db.Where("phone_number = ?", phoneNumber).First(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
|
|
14
server/env/env.go
vendored
14
server/env/env.go
vendored
|
@ -86,6 +86,7 @@ func InitAllEnv() error {
|
||||||
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
|
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
|
||||||
osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure)
|
osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure)
|
||||||
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
|
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
|
||||||
|
osDisableMobileBasicAuthentication := os.Getenv(constants.AuthRecipeMethodMobileBasicAuth)
|
||||||
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
|
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
|
||||||
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
|
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
|
||||||
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
||||||
|
@ -498,6 +499,19 @@ func InitAllEnv() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := envData[constants.EnvKeyDisableMobileBasicAuthentication]; !ok {
|
||||||
|
envData[constants.EnvKeyDisableMobileBasicAuthentication] = osDisableBasicAuthentication == "true"
|
||||||
|
}
|
||||||
|
if osDisableMobileBasicAuthentication != "" {
|
||||||
|
boolValue, err := strconv.ParseBool(osDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if boolValue != envData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) {
|
||||||
|
envData[constants.EnvKeyDisableMobileBasicAuthentication] = boolValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
|
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
|
||||||
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
|
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
|
||||||
}
|
}
|
||||||
|
|
3
server/env/persist_env.go
vendored
3
server/env/persist_env.go
vendored
|
@ -75,7 +75,6 @@ func GetEnvData() (map[string]interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||||
|
|
||||||
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error while decrypting env data from B64: ", err)
|
log.Debug("Error while decrypting env data from B64: ", err)
|
||||||
|
@ -201,7 +200,7 @@ func PersistEnv() error {
|
||||||
envValue := strings.TrimSpace(os.Getenv(key))
|
envValue := strings.TrimSpace(os.Getenv(key))
|
||||||
if envValue != "" {
|
if envValue != "" {
|
||||||
switch key {
|
switch key {
|
||||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure:
|
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure:
|
||||||
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
||||||
if value.(bool) != envValueBool {
|
if value.(bool) != envValueBool {
|
||||||
storeData[key] = envValueBool
|
storeData[key] = envValueBool
|
||||||
|
|
|
@ -447,7 +447,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
|
|
||||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
|
@ -524,8 +523,6 @@ golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b h1:uKO3Js8lXGjpjdc4J3rqs0/Ex5yDKUGfk43tTYWVLas=
|
|
||||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
|
||||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
@ -598,16 +595,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -617,7 +610,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
|
|
@ -171,6 +171,8 @@ type ComplexityRoot struct {
|
||||||
Login func(childComplexity int, params model.LoginInput) int
|
Login func(childComplexity int, params model.LoginInput) int
|
||||||
Logout func(childComplexity int) int
|
Logout func(childComplexity int) int
|
||||||
MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int
|
MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int
|
||||||
|
MobileLogin func(childComplexity int, params model.MobileLoginInput) int
|
||||||
|
MobileSignup func(childComplexity int, params *model.MobileSignUpInput) int
|
||||||
ResendOtp func(childComplexity int, params model.ResendOTPRequest) int
|
ResendOtp func(childComplexity int, params model.ResendOTPRequest) int
|
||||||
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
|
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
|
||||||
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
|
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
|
||||||
|
@ -300,7 +302,9 @@ type ComplexityRoot struct {
|
||||||
|
|
||||||
type MutationResolver interface {
|
type MutationResolver interface {
|
||||||
Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error)
|
Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error)
|
||||||
|
MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error)
|
||||||
Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error)
|
Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error)
|
||||||
|
MobileLogin(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error)
|
||||||
MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error)
|
MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error)
|
||||||
Logout(ctx context.Context) (*model.Response, error)
|
Logout(ctx context.Context) (*model.Response, error)
|
||||||
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
|
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
|
||||||
|
@ -1159,6 +1163,30 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true
|
return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true
|
||||||
|
|
||||||
|
case "Mutation.mobile_login":
|
||||||
|
if e.complexity.Mutation.MobileLogin == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_mobile_login_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.MobileLogin(childComplexity, args["params"].(model.MobileLoginInput)), true
|
||||||
|
|
||||||
|
case "Mutation.mobile_signup":
|
||||||
|
if e.complexity.Mutation.MobileSignup == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_mobile_signup_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.MobileSignup(childComplexity, args["params"].(*model.MobileSignUpInput)), true
|
||||||
|
|
||||||
case "Mutation.resend_otp":
|
case "Mutation.resend_otp":
|
||||||
if e.complexity.Mutation.ResendOtp == nil {
|
if e.complexity.Mutation.ResendOtp == nil {
|
||||||
break
|
break
|
||||||
|
@ -1884,6 +1912,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||||
ec.unmarshalInputListWebhookLogRequest,
|
ec.unmarshalInputListWebhookLogRequest,
|
||||||
ec.unmarshalInputLoginInput,
|
ec.unmarshalInputLoginInput,
|
||||||
ec.unmarshalInputMagicLinkLoginInput,
|
ec.unmarshalInputMagicLinkLoginInput,
|
||||||
|
ec.unmarshalInputMobileLoginInput,
|
||||||
|
ec.unmarshalInputMobileSignUpInput,
|
||||||
ec.unmarshalInputOAuthRevokeInput,
|
ec.unmarshalInputOAuthRevokeInput,
|
||||||
ec.unmarshalInputPaginatedInput,
|
ec.unmarshalInputPaginatedInput,
|
||||||
ec.unmarshalInputPaginationInput,
|
ec.unmarshalInputPaginationInput,
|
||||||
|
@ -2234,6 +2264,28 @@ input AdminSignupInput {
|
||||||
admin_secret: String!
|
admin_secret: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input MobileSignUpInput {
|
||||||
|
email: String
|
||||||
|
given_name: String
|
||||||
|
family_name: String
|
||||||
|
middle_name: String
|
||||||
|
nickname: String
|
||||||
|
gender: String
|
||||||
|
birthdate: String
|
||||||
|
phone_number: String!
|
||||||
|
picture: String
|
||||||
|
password: String!
|
||||||
|
confirm_password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
redirect_uri: String
|
||||||
|
is_multi_factor_auth_enabled: Boolean
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# it is used to get code for an on-going auth process during login
|
||||||
|
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
|
||||||
|
state: String
|
||||||
|
}
|
||||||
|
|
||||||
input SignUpInput {
|
input SignUpInput {
|
||||||
email: String!
|
email: String!
|
||||||
given_name: String
|
given_name: String
|
||||||
|
@ -2267,6 +2319,17 @@ input LoginInput {
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input MobileLoginInput {
|
||||||
|
phone_number: String!
|
||||||
|
password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# it is used to get code for an on-going auth process during login
|
||||||
|
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
|
||||||
|
state: String
|
||||||
|
}
|
||||||
|
|
||||||
input VerifyEmailInput {
|
input VerifyEmailInput {
|
||||||
token: String!
|
token: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
|
@ -2411,6 +2474,8 @@ input AddEmailTemplateRequest {
|
||||||
event_name: String!
|
event_name: String!
|
||||||
subject: String!
|
subject: String!
|
||||||
template: String!
|
template: String!
|
||||||
|
# Design value is set when editor is used
|
||||||
|
# If raw HTML is used design value is set to null
|
||||||
design: String
|
design: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2419,6 +2484,8 @@ input UpdateEmailTemplateRequest {
|
||||||
event_name: String
|
event_name: String
|
||||||
template: String
|
template: String
|
||||||
subject: String
|
subject: String
|
||||||
|
# Design value is set when editor is used
|
||||||
|
# If raw HTML is used design value is set to null
|
||||||
design: String
|
design: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2445,7 +2512,9 @@ input ResendOTPRequest {
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
signup(params: SignUpInput!): AuthResponse!
|
signup(params: SignUpInput!): AuthResponse!
|
||||||
|
mobile_signup(params: MobileSignUpInput): AuthResponse!
|
||||||
login(params: LoginInput!): AuthResponse!
|
login(params: LoginInput!): AuthResponse!
|
||||||
|
mobile_login(params: MobileLoginInput!): AuthResponse!
|
||||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||||
logout: Response!
|
logout: Response!
|
||||||
update_profile(params: UpdateProfileInput!): Response!
|
update_profile(params: UpdateProfileInput!): Response!
|
||||||
|
@ -2784,6 +2853,36 @@ func (ec *executionContext) field_Mutation_magic_link_login_args(ctx context.Con
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_mobile_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 model.MobileLoginInput
|
||||||
|
if tmp, ok := rawArgs["params"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
|
||||||
|
arg0, err = ec.unmarshalNMobileLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileLoginInput(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["params"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_mobile_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 *model.MobileSignUpInput
|
||||||
|
if tmp, ok := rawArgs["params"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
|
||||||
|
arg0, err = ec.unmarshalOMobileSignUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileSignUpInput(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["params"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_resend_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation_resend_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{}{}
|
||||||
|
@ -7015,6 +7114,77 @@ func (ec *executionContext) fieldContext_Mutation_signup(ctx context.Context, fi
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_mobile_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Mutation_mobile_signup(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().MobileSignup(rctx, fc.Args["params"].(*model.MobileSignUpInput))
|
||||||
|
})
|
||||||
|
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_mobile_signup(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_mobile_signup_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Mutation_login(ctx, field)
|
fc, err := ec.fieldContext_Mutation_login(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7086,6 +7256,77 @@ func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, fie
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_mobile_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Mutation_mobile_login(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().MobileLogin(rctx, fc.Args["params"].(model.MobileLoginInput))
|
||||||
|
})
|
||||||
|
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_mobile_login(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_mobile_login_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_magic_link_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_magic_link_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Mutation_magic_link_login(ctx, field)
|
fc, err := ec.fieldContext_Mutation_magic_link_login(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -14592,6 +14833,214 @@ func (ec *executionContext) unmarshalInputMagicLinkLoginInput(ctx context.Contex
|
||||||
return it, nil
|
return it, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputMobileLoginInput(ctx context.Context, obj interface{}) (model.MobileLoginInput, error) {
|
||||||
|
var it model.MobileLoginInput
|
||||||
|
asMap := map[string]interface{}{}
|
||||||
|
for k, v := range obj.(map[string]interface{}) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsInOrder := [...]string{"phone_number", "password", "roles", "scope", "state"}
|
||||||
|
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 "password":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
|
||||||
|
it.Password, err = ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "roles":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roles"))
|
||||||
|
it.Roles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "scope":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("scope"))
|
||||||
|
it.Scope, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "state":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
|
||||||
|
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputMobileSignUpInput(ctx context.Context, obj interface{}) (model.MobileSignUpInput, error) {
|
||||||
|
var it model.MobileSignUpInput
|
||||||
|
asMap := map[string]interface{}{}
|
||||||
|
for k, v := range obj.(map[string]interface{}) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsInOrder := [...]string{"email", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "password", "confirm_password", "roles", "scope", "redirect_uri", "is_multi_factor_auth_enabled", "state"}
|
||||||
|
for _, k := range fieldsInOrder {
|
||||||
|
v, ok := asMap[k]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
case "email":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
|
||||||
|
it.Email, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "given_name":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("given_name"))
|
||||||
|
it.GivenName, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "family_name":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("family_name"))
|
||||||
|
it.FamilyName, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "middle_name":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("middle_name"))
|
||||||
|
it.MiddleName, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "nickname":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("nickname"))
|
||||||
|
it.Nickname, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "gender":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender"))
|
||||||
|
it.Gender, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "birthdate":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birthdate"))
|
||||||
|
it.Birthdate, 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.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "picture":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("picture"))
|
||||||
|
it.Picture, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "password":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
|
||||||
|
it.Password, err = ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "confirm_password":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("confirm_password"))
|
||||||
|
it.ConfirmPassword, err = ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "roles":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roles"))
|
||||||
|
it.Roles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "scope":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("scope"))
|
||||||
|
it.Scope, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "redirect_uri":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("redirect_uri"))
|
||||||
|
it.RedirectURI, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "is_multi_factor_auth_enabled":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_multi_factor_auth_enabled"))
|
||||||
|
it.IsMultiFactorAuthEnabled, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "state":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
|
||||||
|
it.State, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputOAuthRevokeInput(ctx context.Context, obj interface{}) (model.OAuthRevokeInput, error) {
|
func (ec *executionContext) unmarshalInputOAuthRevokeInput(ctx context.Context, obj interface{}) (model.OAuthRevokeInput, error) {
|
||||||
var it model.OAuthRevokeInput
|
var it model.OAuthRevokeInput
|
||||||
asMap := map[string]interface{}{}
|
asMap := map[string]interface{}{}
|
||||||
|
@ -16623,6 +17072,15 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||||
return ec._Mutation_signup(ctx, field)
|
return ec._Mutation_signup(ctx, field)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "mobile_signup":
|
||||||
|
|
||||||
|
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||||
|
return ec._Mutation_mobile_signup(ctx, field)
|
||||||
|
})
|
||||||
|
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
@ -16632,6 +17090,15 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||||
return ec._Mutation_login(ctx, field)
|
return ec._Mutation_login(ctx, field)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "mobile_login":
|
||||||
|
|
||||||
|
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||||
|
return ec._Mutation_mobile_login(ctx, field)
|
||||||
|
})
|
||||||
|
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
@ -18303,6 +18770,11 @@ func (ec *executionContext) marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋautho
|
||||||
return ec._Meta(ctx, sel, v)
|
return ec._Meta(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalNMobileLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileLoginInput(ctx context.Context, v interface{}) (model.MobileLoginInput, error) {
|
||||||
|
res, err := ec.unmarshalInputMobileLoginInput(ctx, v)
|
||||||
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNOAuthRevokeInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐOAuthRevokeInput(ctx context.Context, v interface{}) (model.OAuthRevokeInput, error) {
|
func (ec *executionContext) unmarshalNOAuthRevokeInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐOAuthRevokeInput(ctx context.Context, v interface{}) (model.OAuthRevokeInput, error) {
|
||||||
res, err := ec.unmarshalInputOAuthRevokeInput(ctx, v)
|
res, err := ec.unmarshalInputOAuthRevokeInput(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
@ -19097,6 +19569,14 @@ func (ec *executionContext) marshalOMap2map(ctx context.Context, sel ast.Selecti
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalOMobileSignUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileSignUpInput(ctx context.Context, v interface{}) (*model.MobileSignUpInput, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
res, err := ec.unmarshalInputMobileSignUpInput(ctx, v)
|
||||||
|
return &res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx context.Context, v interface{}) (*model.PaginatedInput, error) {
|
func (ec *executionContext) unmarshalOPaginatedInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPaginatedInput(ctx context.Context, v interface{}) (*model.PaginatedInput, error) {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -179,6 +179,33 @@ type Meta struct {
|
||||||
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MobileLoginInput struct {
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
Scope []string `json:"scope"`
|
||||||
|
State *string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MobileSignUpInput struct {
|
||||||
|
Email *string `json:"email"`
|
||||||
|
GivenName *string `json:"given_name"`
|
||||||
|
FamilyName *string `json:"family_name"`
|
||||||
|
MiddleName *string `json:"middle_name"`
|
||||||
|
Nickname *string `json:"nickname"`
|
||||||
|
Gender *string `json:"gender"`
|
||||||
|
Birthdate *string `json:"birthdate"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Picture *string `json:"picture"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ConfirmPassword string `json:"confirm_password"`
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
Scope []string `json:"scope"`
|
||||||
|
RedirectURI *string `json:"redirect_uri"`
|
||||||
|
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
|
||||||
|
State *string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
type OAuthRevokeInput struct {
|
type OAuthRevokeInput struct {
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,6 +269,28 @@ input AdminSignupInput {
|
||||||
admin_secret: String!
|
admin_secret: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input MobileSignUpInput {
|
||||||
|
email: String
|
||||||
|
given_name: String
|
||||||
|
family_name: String
|
||||||
|
middle_name: String
|
||||||
|
nickname: String
|
||||||
|
gender: String
|
||||||
|
birthdate: String
|
||||||
|
phone_number: String!
|
||||||
|
picture: String
|
||||||
|
password: String!
|
||||||
|
confirm_password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
redirect_uri: String
|
||||||
|
is_multi_factor_auth_enabled: Boolean
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# it is used to get code for an on-going auth process during login
|
||||||
|
# and use that code for setting `c_hash` in id_token
|
||||||
|
state: String
|
||||||
|
}
|
||||||
|
|
||||||
input SignUpInput {
|
input SignUpInput {
|
||||||
email: String!
|
email: String!
|
||||||
given_name: String
|
given_name: String
|
||||||
|
@ -302,6 +324,17 @@ input LoginInput {
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input MobileLoginInput {
|
||||||
|
phone_number: String!
|
||||||
|
password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# it is used to get code for an on-going auth process during login
|
||||||
|
# and use that code for setting `c_hash` in id_token
|
||||||
|
state: String
|
||||||
|
}
|
||||||
|
|
||||||
input VerifyEmailInput {
|
input VerifyEmailInput {
|
||||||
token: String!
|
token: String!
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
|
@ -484,7 +517,9 @@ input ResendOTPRequest {
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
signup(params: SignUpInput!): AuthResponse!
|
signup(params: SignUpInput!): AuthResponse!
|
||||||
|
mobile_signup(params: MobileSignUpInput): AuthResponse!
|
||||||
login(params: LoginInput!): AuthResponse!
|
login(params: LoginInput!): AuthResponse!
|
||||||
|
mobile_login(params: MobileLoginInput!): AuthResponse!
|
||||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||||
logout: Response!
|
logout: Response!
|
||||||
update_profile(params: UpdateProfileInput!): Response!
|
update_profile(params: UpdateProfileInput!): Response!
|
||||||
|
|
|
@ -16,11 +16,21 @@ func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput)
|
||||||
return resolvers.SignupResolver(ctx, params)
|
return resolvers.SignupResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MobileSignup is the resolver for the mobile_signup field.
|
||||||
|
func (r *mutationResolver) MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) {
|
||||||
|
return resolvers.MobileSignupResolver(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
// Login is the resolver for the login field.
|
// Login is the resolver for the login field.
|
||||||
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
|
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
|
||||||
return resolvers.LoginResolver(ctx, params)
|
return resolvers.LoginResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MobileLogin is the resolver for the mobile_login field.
|
||||||
|
func (r *mutationResolver) MobileLogin(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) {
|
||||||
|
return resolvers.MobileLoginResolver(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
// MagicLinkLogin is the resolver for the magic_link_login field.
|
// MagicLinkLogin is the resolver for the magic_link_login field.
|
||||||
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
||||||
return resolvers.MagicLinkLoginResolver(ctx, params)
|
return resolvers.MagicLinkLoginResolver(ctx, params)
|
||||||
|
|
|
@ -26,6 +26,7 @@ func InitMemStore() error {
|
||||||
|
|
||||||
// boolean envs
|
// boolean envs
|
||||||
constants.EnvKeyDisableBasicAuthentication: false,
|
constants.EnvKeyDisableBasicAuthentication: false,
|
||||||
|
constants.EnvKeyDisableMobileBasicAuthentication: false,
|
||||||
constants.EnvKeyDisableMagicLinkLogin: false,
|
constants.EnvKeyDisableMagicLinkLogin: false,
|
||||||
constants.EnvKeyDisableEmailVerification: false,
|
constants.EnvKeyDisableEmailVerification: false,
|
||||||
constants.EnvKeyDisableLoginPage: false,
|
constants.EnvKeyDisableLoginPage: false,
|
||||||
|
|
|
@ -161,7 +161,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for key, value := range data {
|
for key, value := range data {
|
||||||
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure {
|
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure {
|
||||||
boolValue, err := strconv.ParseBool(value)
|
boolValue, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
|
216
server/resolvers/mobile_login.go
Normal file
216
server/resolvers/mobile_login.go
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MobileLoginResolver is a resolver for mobile login mutation
|
||||||
|
func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) {
|
||||||
|
var res *model.AuthResponse
|
||||||
|
|
||||||
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
isBasiAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||||
|
isBasiAuthDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isBasiAuthDisabled {
|
||||||
|
log.Debug("Basic authentication is disabled.")
|
||||||
|
return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`)
|
||||||
|
}
|
||||||
|
|
||||||
|
log := log.WithFields(log.Fields{
|
||||||
|
"phone_number": params.PhoneNumber,
|
||||||
|
})
|
||||||
|
|
||||||
|
user, err := db.Provider.GetUserByPhoneNumber(ctx, params.PhoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user by phone number: ", err)
|
||||||
|
return res, fmt.Errorf(`bad user credentials`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.RevokedTimestamp != nil {
|
||||||
|
log.Debug("User access is revoked")
|
||||||
|
return res, fmt.Errorf(`user access has been revoked`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) {
|
||||||
|
log.Debug("User signup method is not mobile basic auth")
|
||||||
|
return res, fmt.Errorf(`user has not signed up with phone number & password`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumberVerifiedAt == nil {
|
||||||
|
log.Debug("User phone number is not verified")
|
||||||
|
return res, fmt.Errorf(`phone number is not verified`)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to compare password: ", err)
|
||||||
|
return res, fmt.Errorf(`bad user credentials`)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
|
roles := []string{}
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting default roles: ", err)
|
||||||
|
defaultRolesString = ""
|
||||||
|
} else {
|
||||||
|
roles = strings.Split(defaultRolesString, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRoles := strings.Split(user.Roles, ",")
|
||||||
|
if len(params.Roles) > 0 {
|
||||||
|
if !validators.IsValidRoles(params.Roles, currentRoles) {
|
||||||
|
log.Debug("Invalid roles: ", params.Roles)
|
||||||
|
return res, fmt.Errorf(`invalid roles`)
|
||||||
|
}
|
||||||
|
|
||||||
|
roles = params.Roles
|
||||||
|
}
|
||||||
|
|
||||||
|
scope := []string{"openid", "email", "profile"}
|
||||||
|
if params.Scope != nil && len(scope) > 0 {
|
||||||
|
scope = params.Scope
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO use sms authentication for MFA
|
||||||
|
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
|
if err != nil || !isEmailServiceEnabled {
|
||||||
|
log.Debug("Email service not enabled: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication)
|
||||||
|
if err != nil || !isEmailServiceEnabled {
|
||||||
|
log.Debug("MFA service not enabled: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If email service is not enabled continue the process in any way
|
||||||
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isEmailServiceEnabled && !isMFADisabled {
|
||||||
|
otp := utils.GenerateOTP()
|
||||||
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
|
Email: user.Email,
|
||||||
|
Otp: otp,
|
||||||
|
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// exec it as go routine so that we can reduce the api latency
|
||||||
|
go email.SendEmail([]string{params.PhoneNumber}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"otp": otpData.Otp,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to send otp email: ", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return &model.AuthResponse{
|
||||||
|
Message: "Please check the OTP in your inbox",
|
||||||
|
ShouldShowOtpScreen: refs.NewBoolRef(true),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
code := ""
|
||||||
|
codeChallenge := ""
|
||||||
|
nonce := ""
|
||||||
|
if params.State != nil {
|
||||||
|
// Get state from store
|
||||||
|
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
|
||||||
|
if authorizeState != "" {
|
||||||
|
authorizeStateSplit := strings.Split(authorizeState, "@@")
|
||||||
|
if len(authorizeStateSplit) > 1 {
|
||||||
|
code = authorizeStateSplit[0]
|
||||||
|
codeChallenge = authorizeStateSplit[1]
|
||||||
|
} else {
|
||||||
|
nonce = authorizeState
|
||||||
|
}
|
||||||
|
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nonce == "" {
|
||||||
|
nonce = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken, err := token.CreateAuthToken(gc, *user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create auth token", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add to other login options as well
|
||||||
|
// Code challenge could be optional if PKCE flow is not used
|
||||||
|
if code != "" {
|
||||||
|
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
|
||||||
|
log.Debug("SetState failed: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
|
if expiresIn <= 0 {
|
||||||
|
expiresIn = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &model.AuthResponse{
|
||||||
|
Message: `Logged in successfully`,
|
||||||
|
AccessToken: &authToken.AccessToken.Token,
|
||||||
|
IDToken: &authToken.IDToken.Token,
|
||||||
|
ExpiresIn: &expiresIn,
|
||||||
|
User: user.AsAPIUser(),
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
sessionStoreKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID
|
||||||
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, *user)
|
||||||
|
db.Provider.AddSession(ctx, models.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
270
server/resolvers/mobile_signup.go
Normal file
270
server/resolvers/mobile_signup.go
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MobileSignupResolver is a resolver for mobile_basic_auth_signup mutation
|
||||||
|
func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) {
|
||||||
|
var res *model.AuthResponse
|
||||||
|
|
||||||
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting signup disabled: ", err)
|
||||||
|
isSignupDisabled = true
|
||||||
|
}
|
||||||
|
if isSignupDisabled {
|
||||||
|
log.Debug("Signup is disabled")
|
||||||
|
return res, fmt.Errorf(`signup is disabled for this instance`)
|
||||||
|
}
|
||||||
|
|
||||||
|
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting basic auth disabled: ", err)
|
||||||
|
isBasicAuthDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isBasicAuthDisabled {
|
||||||
|
log.Debug("Mobile based Basic authentication is disabled")
|
||||||
|
return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.ConfirmPassword != params.Password {
|
||||||
|
log.Debug("Passwords do not match")
|
||||||
|
return res, fmt.Errorf(`password and confirm password does not match`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validators.IsValidPassword(params.Password); err != nil {
|
||||||
|
log.Debug("Invalid password")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mobile := strings.TrimSpace(params.PhoneNumber)
|
||||||
|
if mobile == "" || len(mobile) < 10 {
|
||||||
|
log.Debug("Invalid phone number")
|
||||||
|
return res, fmt.Errorf("invalid phone number")
|
||||||
|
}
|
||||||
|
|
||||||
|
emailInput := strings.ToLower(strings.TrimSpace(refs.StringValue(params.Email)))
|
||||||
|
|
||||||
|
// if email is null set random dummy email for db constraint
|
||||||
|
|
||||||
|
if emailInput != "" && !validators.IsValidEmail(emailInput) {
|
||||||
|
log.Debug("Invalid email: ", emailInput)
|
||||||
|
return res, fmt.Errorf(`invalid email address`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if emailInput == "" {
|
||||||
|
emailInput = mobile + "@authorizer.dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
log := log.WithFields(log.Fields{
|
||||||
|
"email": emailInput,
|
||||||
|
"phone_number": mobile,
|
||||||
|
})
|
||||||
|
// find user with email
|
||||||
|
existingUser, err := db.Provider.GetUserByPhoneNumber(ctx, mobile)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user by email: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if existingUser != nil {
|
||||||
|
if existingUser.PhoneNumberVerifiedAt != nil {
|
||||||
|
// email is verified
|
||||||
|
log.Debug("Phone number is already verified and signed up.")
|
||||||
|
return res, fmt.Errorf(`%s has already signed up`, mobile)
|
||||||
|
} else if existingUser.ID != "" && existingUser.PhoneNumberVerifiedAt == nil {
|
||||||
|
log.Debug("Phone number is already signed up. Verification pending...")
|
||||||
|
return res, fmt.Errorf("%s has already signed up. please complete the phone number verification process or reset the password", mobile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputRoles := []string{}
|
||||||
|
|
||||||
|
if len(params.Roles) > 0 {
|
||||||
|
// check if roles exists
|
||||||
|
rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles)
|
||||||
|
roles := []string{}
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting roles: ", err)
|
||||||
|
return res, err
|
||||||
|
} else {
|
||||||
|
roles = strings.Split(rolesString, ",")
|
||||||
|
}
|
||||||
|
if !validators.IsValidRoles(params.Roles, roles) {
|
||||||
|
log.Debug("Invalid roles: ", params.Roles)
|
||||||
|
return res, fmt.Errorf(`invalid roles`)
|
||||||
|
} else {
|
||||||
|
inputRoles = params.Roles
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting default roles: ", err)
|
||||||
|
return res, err
|
||||||
|
} else {
|
||||||
|
inputRoles = strings.Split(inputRolesString, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
user := models.User{
|
||||||
|
Email: emailInput,
|
||||||
|
PhoneNumber: &mobile,
|
||||||
|
PhoneNumberVerifiedAt: &now,
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Roles = strings.Join(inputRoles, ",")
|
||||||
|
|
||||||
|
password, _ := crypto.EncryptPassword(params.Password)
|
||||||
|
user.Password = &password
|
||||||
|
|
||||||
|
if params.GivenName != nil {
|
||||||
|
user.GivenName = params.GivenName
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.FamilyName != nil {
|
||||||
|
user.FamilyName = params.FamilyName
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.MiddleName != nil {
|
||||||
|
user.MiddleName = params.MiddleName
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Nickname != nil {
|
||||||
|
user.Nickname = params.Nickname
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Gender != nil {
|
||||||
|
user.Gender = params.Gender
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Birthdate != nil {
|
||||||
|
user.Birthdate = params.Birthdate
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Picture != nil {
|
||||||
|
user.Picture = params.Picture
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.IsMultiFactorAuthEnabled != nil {
|
||||||
|
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("MFA service not enabled: ", err)
|
||||||
|
isMFAEnforced = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if isMFAEnforced {
|
||||||
|
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth
|
||||||
|
user, err = db.Provider.AddUser(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add user: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
roles := strings.Split(user.Roles, ",")
|
||||||
|
userToReturn := user.AsAPIUser()
|
||||||
|
|
||||||
|
scope := []string{"openid", "email", "profile"}
|
||||||
|
if params.Scope != nil && len(scope) > 0 {
|
||||||
|
scope = params.Scope
|
||||||
|
}
|
||||||
|
|
||||||
|
code := ""
|
||||||
|
codeChallenge := ""
|
||||||
|
nonce := ""
|
||||||
|
if params.State != nil {
|
||||||
|
// Get state from store
|
||||||
|
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
|
||||||
|
if authorizeState != "" {
|
||||||
|
authorizeStateSplit := strings.Split(authorizeState, "@@")
|
||||||
|
if len(authorizeStateSplit) > 1 {
|
||||||
|
code = authorizeStateSplit[0]
|
||||||
|
codeChallenge = authorizeStateSplit[1]
|
||||||
|
} else {
|
||||||
|
nonce = authorizeState
|
||||||
|
}
|
||||||
|
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nonce == "" {
|
||||||
|
nonce = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create auth token: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code challenge could be optional if PKCE flow is not used
|
||||||
|
if code != "" {
|
||||||
|
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
|
||||||
|
log.Debug("SetState failed: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
|
if expiresIn <= 0 {
|
||||||
|
expiresIn = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &model.AuthResponse{
|
||||||
|
Message: `Signed up successfully.`,
|
||||||
|
AccessToken: &authToken.AccessToken.Token,
|
||||||
|
ExpiresIn: &expiresIn,
|
||||||
|
User: userToReturn,
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||||
|
db.Provider.AddSession(ctx, models.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import (
|
||||||
// remove the session tokens for those methods
|
// remove the session tokens for those methods
|
||||||
func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
|
isCurrentMobileBasicAuthEnabled := !currentData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
||||||
isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != ""
|
isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != ""
|
||||||
isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
||||||
|
@ -34,6 +35,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != ""
|
isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != ""
|
||||||
|
|
||||||
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
|
isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
||||||
isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != ""
|
isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != ""
|
||||||
isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
||||||
|
@ -46,6 +48,10 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isCurrentMobileBasicAuthEnabled && !isUpdatedMobileBasicAuthEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMobileBasicAuth)
|
||||||
|
}
|
||||||
|
|
||||||
if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled {
|
if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled {
|
||||||
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin)
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin)
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,11 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
||||||
|
// verify if phone number is unique
|
||||||
|
if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil {
|
||||||
|
log.Debug("user with given phone number already exists")
|
||||||
|
return nil, errors.New("user with given phone number already exists")
|
||||||
|
}
|
||||||
user.PhoneNumber = params.PhoneNumber
|
user.PhoneNumber = params.PhoneNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,8 +159,14 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
isBasicAuthDisabled = true
|
isBasicAuthDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||||
|
isBasicAuthDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
if params.NewPassword != nil && params.ConfirmNewPassword != nil {
|
if params.NewPassword != nil && params.ConfirmNewPassword != nil {
|
||||||
if isBasicAuthDisabled {
|
if isBasicAuthDisabled || isMobileBasicAuthDisabled {
|
||||||
log.Debug("Cannot update password as basic authentication is disabled")
|
log.Debug("Cannot update password as basic authentication is disabled")
|
||||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,11 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
||||||
|
// verify if phone number is unique
|
||||||
|
if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil {
|
||||||
|
log.Debug("user with given phone number already exists")
|
||||||
|
return nil, errors.New("user with given phone number already exists")
|
||||||
|
}
|
||||||
user.PhoneNumber = params.PhoneNumber
|
user.PhoneNumber = params.PhoneNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
58
server/test/mobile_login_test.go
Normal file
58
server/test/mobile_login_test.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mobileLoginTests(t *testing.T, s TestSetup) {
|
||||||
|
t.Helper()
|
||||||
|
t.Run(`should login via mobile`, func(t *testing.T) {
|
||||||
|
_, ctx := createContext(s)
|
||||||
|
email := "mobile_login." + 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 for email login
|
||||||
|
res, err = resolvers.LoginResolver(ctx, model.LoginInput{
|
||||||
|
Email: email,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
85
server/test/mobile_signup_test.go
Normal file
85
server/test/mobile_signup_test.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mobileSingupTest(t *testing.T, s TestSetup) {
|
||||||
|
t.Helper()
|
||||||
|
t.Run(`should complete the signup with mobile and check duplicates`, func(t *testing.T) {
|
||||||
|
_, ctx := createContext(s)
|
||||||
|
email := "mobile_basic_auth_signup." + s.TestInfo.Email
|
||||||
|
res, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password + "s",
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
assert.Nil(t, res)
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: "test",
|
||||||
|
ConfirmPassword: "test",
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true)
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "singup disabled")
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false)
|
||||||
|
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, true)
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "singup disabled")
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, false)
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: " ",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid mobile")
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: "test",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid mobile")
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: "1234567890",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, res.AccessToken)
|
||||||
|
assert.Equal(t, "1234567890@authorizer.dev", res.User.Email)
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: "1234567890",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.Error(t, err, "user exists")
|
||||||
|
|
||||||
|
cleanData(email)
|
||||||
|
cleanData("1234567890@authorizer.dev")
|
||||||
|
})
|
||||||
|
}
|
|
@ -111,6 +111,8 @@ func TestResolvers(t *testing.T) {
|
||||||
// user resolvers tests
|
// user resolvers tests
|
||||||
loginTests(t, s)
|
loginTests(t, s)
|
||||||
signupTests(t, s)
|
signupTests(t, s)
|
||||||
|
mobileSingupTest(t, s)
|
||||||
|
mobileLoginTests(t, s)
|
||||||
forgotPasswordTest(t, s)
|
forgotPasswordTest(t, s)
|
||||||
resendVerifyEmailTests(t, s)
|
resendVerifyEmailTests(t, s)
|
||||||
resetPasswordTest(t, s)
|
resetPasswordTest(t, s)
|
||||||
|
|
|
@ -31,7 +31,7 @@ func testEndpointTest(t *testing.T, s TestSetup) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, res)
|
assert.NotNil(t, res)
|
||||||
assert.GreaterOrEqual(t, int64(201), *res.HTTPStatus)
|
assert.GreaterOrEqual(t, *res.HTTPStatus, int64(200))
|
||||||
assert.NotEmpty(t, res.Response)
|
assert.NotEmpty(t, res.Response)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user