feat: add signup + login using mobile
This commit is contained in:
parent
1eb8965f98
commit
313b510ba1
|
@ -25,7 +25,7 @@ type User struct {
|
|||
Nickname *string `json:"nickname" bson:"nickname" cql:"nickname" dynamo:"nickname"`
|
||||
Gender *string `json:"gender" bson:"gender" cql:"gender" dynamo:"gender"`
|
||||
Birthdate *string `json:"birthdate" bson:"birthdate" cql:"birthdate" dynamo:"birthdate"`
|
||||
PhoneNumber *string `gorm:"index" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number" index:"phone_number,hash"`
|
||||
PhoneNumber *string `gorm:"index" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"`
|
||||
PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at" cql:"phone_number_verified_at" dynamo:"phone_number_verified_at"`
|
||||
Picture *string `json:"picture" bson:"picture" cql:"picture" dynamo:"picture"`
|
||||
Roles string `json:"roles" bson:"roles" cql:"roles" dynamo:"roles"`
|
||||
|
|
|
@ -90,12 +90,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) {
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
|
|
|
@ -34,7 +34,6 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro
|
|||
|
||||
// UpdateEnv to update environment information in database
|
||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
||||
|
||||
collection := p.db.Table(models.Collections.Env)
|
||||
env.UpdatedAt = time.Now().Unix()
|
||||
|
||||
|
|
|
@ -58,12 +58,6 @@ func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.Use
|
|||
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
err := UpdateByHashKey(collection, "id", user.ID, user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
|
@ -215,7 +209,7 @@ func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string)
|
|||
var user models.User
|
||||
|
||||
collection := p.db.Table(models.Collections.User)
|
||||
err := collection.Scan().Index("phone_number").Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
|
||||
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -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) {
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
result := p.db.Save(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
|
|
1
server/env/persist_env.go
vendored
1
server/env/persist_env.go
vendored
|
@ -75,7 +75,6 @@ func GetEnvData() (map[string]interface{}, error) {
|
|||
}
|
||||
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||
|
||||
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
||||
if err != nil {
|
||||
log.Debug("Error while decrypting env data from B64: ", err)
|
||||
|
|
|
@ -156,36 +156,37 @@ type ComplexityRoot struct {
|
|||
}
|
||||
|
||||
Mutation struct {
|
||||
AddEmailTemplate func(childComplexity int, params model.AddEmailTemplateRequest) int
|
||||
AddWebhook func(childComplexity int, params model.AddWebhookRequest) int
|
||||
AdminLogin func(childComplexity int, params model.AdminLoginInput) int
|
||||
AdminLogout func(childComplexity int) int
|
||||
AdminSignup func(childComplexity int, params model.AdminSignupInput) int
|
||||
DeleteEmailTemplate func(childComplexity int, params model.DeleteEmailTemplateRequest) int
|
||||
DeleteUser func(childComplexity int, params model.DeleteUserInput) int
|
||||
DeleteWebhook func(childComplexity int, params model.WebhookRequest) int
|
||||
EnableAccess func(childComplexity int, param model.UpdateAccessInput) int
|
||||
ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int
|
||||
GenerateJwtKeys func(childComplexity int, params model.GenerateJWTKeysInput) int
|
||||
InviteMembers func(childComplexity int, params model.InviteMemberInput) int
|
||||
Login func(childComplexity int, params model.LoginInput) int
|
||||
Logout func(childComplexity int) int
|
||||
MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int
|
||||
MobileBasicAuthSignup func(childComplexity int, params *model.MobileBasicAuthSignUpUpInput) int
|
||||
ResendOtp func(childComplexity int, params model.ResendOTPRequest) int
|
||||
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
|
||||
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
|
||||
Revoke func(childComplexity int, params model.OAuthRevokeInput) int
|
||||
RevokeAccess func(childComplexity int, param model.UpdateAccessInput) int
|
||||
Signup func(childComplexity int, params model.SignUpInput) int
|
||||
TestEndpoint func(childComplexity int, params model.TestEndpointRequest) int
|
||||
UpdateEmailTemplate func(childComplexity int, params model.UpdateEmailTemplateRequest) int
|
||||
UpdateEnv func(childComplexity int, params model.UpdateEnvInput) int
|
||||
UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int
|
||||
UpdateUser func(childComplexity int, params model.UpdateUserInput) int
|
||||
UpdateWebhook func(childComplexity int, params model.UpdateWebhookRequest) int
|
||||
VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int
|
||||
VerifyOtp func(childComplexity int, params model.VerifyOTPRequest) int
|
||||
AddEmailTemplate func(childComplexity int, params model.AddEmailTemplateRequest) int
|
||||
AddWebhook func(childComplexity int, params model.AddWebhookRequest) int
|
||||
AdminLogin func(childComplexity int, params model.AdminLoginInput) int
|
||||
AdminLogout func(childComplexity int) int
|
||||
AdminSignup func(childComplexity int, params model.AdminSignupInput) int
|
||||
DeleteEmailTemplate func(childComplexity int, params model.DeleteEmailTemplateRequest) int
|
||||
DeleteUser func(childComplexity int, params model.DeleteUserInput) int
|
||||
DeleteWebhook func(childComplexity int, params model.WebhookRequest) int
|
||||
EnableAccess func(childComplexity int, param model.UpdateAccessInput) int
|
||||
ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int
|
||||
GenerateJwtKeys func(childComplexity int, params model.GenerateJWTKeysInput) int
|
||||
InviteMembers func(childComplexity int, params model.InviteMemberInput) int
|
||||
Login func(childComplexity int, params model.LoginInput) int
|
||||
Logout func(childComplexity int) 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
|
||||
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
|
||||
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
|
||||
Revoke func(childComplexity int, params model.OAuthRevokeInput) int
|
||||
RevokeAccess func(childComplexity int, param model.UpdateAccessInput) int
|
||||
Signup func(childComplexity int, params model.SignUpInput) int
|
||||
TestEndpoint func(childComplexity int, params model.TestEndpointRequest) int
|
||||
UpdateEmailTemplate func(childComplexity int, params model.UpdateEmailTemplateRequest) int
|
||||
UpdateEnv func(childComplexity int, params model.UpdateEnvInput) int
|
||||
UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int
|
||||
UpdateUser func(childComplexity int, params model.UpdateUserInput) int
|
||||
UpdateWebhook func(childComplexity int, params model.UpdateWebhookRequest) int
|
||||
VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int
|
||||
VerifyOtp func(childComplexity int, params model.VerifyOTPRequest) int
|
||||
}
|
||||
|
||||
Pagination struct {
|
||||
|
@ -301,8 +302,9 @@ type ComplexityRoot struct {
|
|||
|
||||
type MutationResolver interface {
|
||||
Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error)
|
||||
MobileBasicAuthSignup(ctx context.Context, params *model.MobileBasicAuthSignUpUpInput) (*model.AuthResponse, error)
|
||||
MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*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)
|
||||
Logout(ctx context.Context) (*model.Response, error)
|
||||
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
|
||||
|
@ -1161,17 +1163,29 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true
|
||||
|
||||
case "Mutation.mobile_basic_auth_signup":
|
||||
if e.complexity.Mutation.MobileBasicAuthSignup == nil {
|
||||
case "Mutation.mobile_login":
|
||||
if e.complexity.Mutation.MobileLogin == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_mobile_basic_auth_signup_args(context.TODO(), rawArgs)
|
||||
args, err := ec.field_Mutation_mobile_login_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.MobileBasicAuthSignup(childComplexity, args["params"].(*model.MobileBasicAuthSignUpUpInput)), true
|
||||
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":
|
||||
if e.complexity.Mutation.ResendOtp == nil {
|
||||
|
@ -1898,7 +1912,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
|||
ec.unmarshalInputListWebhookLogRequest,
|
||||
ec.unmarshalInputLoginInput,
|
||||
ec.unmarshalInputMagicLinkLoginInput,
|
||||
ec.unmarshalInputMobileBasicAuthSignUpUpInput,
|
||||
ec.unmarshalInputMobileLoginInput,
|
||||
ec.unmarshalInputMobileSignUpInput,
|
||||
ec.unmarshalInputOAuthRevokeInput,
|
||||
ec.unmarshalInputPaginatedInput,
|
||||
ec.unmarshalInputPaginationInput,
|
||||
|
@ -2249,7 +2264,7 @@ input AdminSignupInput {
|
|||
admin_secret: String!
|
||||
}
|
||||
|
||||
input MobileBasicAuthSignUpUpInput {
|
||||
input MobileSignUpInput {
|
||||
email: String
|
||||
given_name: String
|
||||
family_name: String
|
||||
|
@ -2304,6 +2319,17 @@ input LoginInput {
|
|||
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 {
|
||||
token: String!
|
||||
# state is used for authorization code grant flow
|
||||
|
@ -2486,8 +2512,9 @@ input ResendOTPRequest {
|
|||
|
||||
type Mutation {
|
||||
signup(params: SignUpInput!): AuthResponse!
|
||||
mobile_basic_auth_signup(params: MobileBasicAuthSignUpUpInput): AuthResponse!
|
||||
mobile_signup(params: MobileSignUpInput): AuthResponse!
|
||||
login(params: LoginInput!): AuthResponse!
|
||||
mobile_login(params: MobileLoginInput!): AuthResponse!
|
||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||
logout: Response!
|
||||
update_profile(params: UpdateProfileInput!): Response!
|
||||
|
@ -2826,13 +2853,28 @@ func (ec *executionContext) field_Mutation_magic_link_login_args(ctx context.Con
|
|||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_mobile_basic_auth_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
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.MobileBasicAuthSignUpUpInput
|
||||
var arg0 model.MobileLoginInput
|
||||
if tmp, ok := rawArgs["params"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
|
||||
arg0, err = ec.unmarshalOMobileBasicAuthSignUpUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileBasicAuthSignUpUpInput(ctx, tmp)
|
||||
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
|
||||
}
|
||||
|
@ -7072,8 +7114,8 @@ func (ec *executionContext) fieldContext_Mutation_signup(ctx context.Context, fi
|
|||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_mobile_basic_auth_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Mutation_mobile_basic_auth_signup(ctx, field)
|
||||
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
|
||||
}
|
||||
|
@ -7086,7 +7128,7 @@ func (ec *executionContext) _Mutation_mobile_basic_auth_signup(ctx context.Conte
|
|||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().MobileBasicAuthSignup(rctx, fc.Args["params"].(*model.MobileBasicAuthSignUpUpInput))
|
||||
return ec.resolvers.Mutation().MobileSignup(rctx, fc.Args["params"].(*model.MobileSignUpInput))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
|
@ -7103,7 +7145,7 @@ func (ec *executionContext) _Mutation_mobile_basic_auth_signup(ctx context.Conte
|
|||
return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_mobile_basic_auth_signup(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
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,
|
||||
|
@ -7136,7 +7178,7 @@ func (ec *executionContext) fieldContext_Mutation_mobile_basic_auth_signup(ctx c
|
|||
}
|
||||
}()
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_mobile_basic_auth_signup_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
if fc.Args, err = ec.field_Mutation_mobile_signup_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
|
@ -7214,6 +7256,77 @@ func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, fie
|
|||
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) {
|
||||
fc, err := ec.fieldContext_Mutation_magic_link_login(ctx, field)
|
||||
if err != nil {
|
||||
|
@ -14720,8 +14833,68 @@ func (ec *executionContext) unmarshalInputMagicLinkLoginInput(ctx context.Contex
|
|||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputMobileBasicAuthSignUpUpInput(ctx context.Context, obj interface{}) (model.MobileBasicAuthSignUpUpInput, error) {
|
||||
var it model.MobileBasicAuthSignUpUpInput
|
||||
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
|
||||
|
@ -16902,10 +17075,10 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "mobile_basic_auth_signup":
|
||||
case "mobile_signup":
|
||||
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_mobile_basic_auth_signup(ctx, field)
|
||||
return ec._Mutation_mobile_signup(ctx, field)
|
||||
})
|
||||
|
||||
if out.Values[i] == graphql.Null {
|
||||
|
@ -16917,6 +17090,15 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||
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 {
|
||||
invalids++
|
||||
}
|
||||
|
@ -18588,6 +18770,11 @@ func (ec *executionContext) marshalNMeta2ᚖgithubᚗcomᚋauthorizerdevᚋautho
|
|||
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) {
|
||||
res, err := ec.unmarshalInputOAuthRevokeInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
|
@ -19382,11 +19569,11 @@ func (ec *executionContext) marshalOMap2map(ctx context.Context, sel ast.Selecti
|
|||
return res
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOMobileBasicAuthSignUpUpInput2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐMobileBasicAuthSignUpUpInput(ctx context.Context, v interface{}) (*model.MobileBasicAuthSignUpUpInput, error) {
|
||||
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.unmarshalInputMobileBasicAuthSignUpUpInput(ctx, v)
|
||||
res, err := ec.unmarshalInputMobileSignUpInput(ctx, v)
|
||||
return &res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,15 @@ type Meta struct {
|
|||
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
||||
}
|
||||
|
||||
type MobileBasicAuthSignUpUpInput struct {
|
||||
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"`
|
||||
|
|
|
@ -269,7 +269,7 @@ input AdminSignupInput {
|
|||
admin_secret: String!
|
||||
}
|
||||
|
||||
input MobileBasicAuthSignUpUpInput {
|
||||
input MobileSignUpInput {
|
||||
email: String
|
||||
given_name: String
|
||||
family_name: String
|
||||
|
@ -324,6 +324,17 @@ input LoginInput {
|
|||
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 {
|
||||
token: String!
|
||||
# state is used for authorization code grant flow
|
||||
|
@ -506,8 +517,9 @@ input ResendOTPRequest {
|
|||
|
||||
type Mutation {
|
||||
signup(params: SignUpInput!): AuthResponse!
|
||||
mobile_basic_auth_signup(params: MobileBasicAuthSignUpUpInput): AuthResponse!
|
||||
mobile_signup(params: MobileSignUpInput): AuthResponse!
|
||||
login(params: LoginInput!): AuthResponse!
|
||||
mobile_login(params: MobileLoginInput!): AuthResponse!
|
||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||
logout: Response!
|
||||
update_profile(params: UpdateProfileInput!): Response!
|
||||
|
|
|
@ -16,9 +16,9 @@ func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput)
|
|||
return resolvers.SignupResolver(ctx, params)
|
||||
}
|
||||
|
||||
// MobileBasicAuthSignup is the resolver for the mobile_basic_auth_signup field.
|
||||
func (r *mutationResolver) MobileBasicAuthSignup(ctx context.Context, params *model.MobileBasicAuthSignUpUpInput) (*model.AuthResponse, error) {
|
||||
return resolvers.MobileBasicAuthSignupResolver(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.
|
||||
|
@ -26,6 +26,11 @@ func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (
|
|||
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.
|
||||
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
||||
return resolvers.MagicLinkLoginResolver(ctx, params)
|
||||
|
|
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
|
||||
}
|
|
@ -22,8 +22,8 @@ import (
|
|||
"github.com/authorizerdev/authorizer/server/validators"
|
||||
)
|
||||
|
||||
// MobileBasicAuthSignupResolver is a resolver for mobile_basic_auth_signup mutation
|
||||
func MobileBasicAuthSignupResolver(ctx context.Context, params *model.MobileBasicAuthSignUpUpInput) (*model.AuthResponse, error) {
|
||||
// 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)
|
||||
|
@ -221,7 +221,7 @@ func MobileBasicAuthSignupResolver(ctx context.Context, params *model.MobileBasi
|
|||
nonce = uuid.New().String()
|
||||
}
|
||||
|
||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce, code)
|
||||
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
|
||||
|
@ -247,7 +247,7 @@ func MobileBasicAuthSignupResolver(ctx context.Context, params *model.MobileBasi
|
|||
User: userToReturn,
|
||||
}
|
||||
|
||||
sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID
|
||||
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)
|
||||
|
@ -258,7 +258,7 @@ func MobileBasicAuthSignupResolver(ctx context.Context, params *model.MobileBasi
|
|||
}
|
||||
|
||||
go func() {
|
||||
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
||||
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||
db.Provider.AddSession(ctx, models.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(gc.Request),
|
|
@ -88,6 +88,11 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
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)
|
||||
})
|
||||
}
|
|
@ -11,12 +11,12 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func mobileBasicAuthSingupTest(t *testing.T, s TestSetup) {
|
||||
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.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
res, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||
Email: refs.NewStringRef(email),
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password + "s",
|
||||
|
@ -24,7 +24,7 @@ func mobileBasicAuthSingupTest(t *testing.T, s TestSetup) {
|
|||
assert.NotNil(t, err, "invalid password")
|
||||
assert.Nil(t, res)
|
||||
|
||||
res, err = resolvers.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||
Email: refs.NewStringRef(email),
|
||||
Password: "test",
|
||||
ConfirmPassword: "test",
|
||||
|
@ -32,7 +32,7 @@ func mobileBasicAuthSingupTest(t *testing.T, s TestSetup) {
|
|||
assert.NotNil(t, err, "invalid password")
|
||||
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true)
|
||||
res, err = resolvers.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||
Email: refs.NewStringRef(email),
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
|
@ -41,7 +41,7 @@ func mobileBasicAuthSingupTest(t *testing.T, s TestSetup) {
|
|||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false)
|
||||
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, true)
|
||||
res, err = resolvers.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||
Email: refs.NewStringRef(email),
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
|
@ -49,21 +49,21 @@ func mobileBasicAuthSingupTest(t *testing.T, s TestSetup) {
|
|||
assert.NotNil(t, err, "singup disabled")
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, false)
|
||||
|
||||
res, err = resolvers.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
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.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
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.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||
PhoneNumber: "1234567890",
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
|
@ -72,11 +72,14 @@ func mobileBasicAuthSingupTest(t *testing.T, s TestSetup) {
|
|||
assert.NotEmpty(t, res.AccessToken)
|
||||
assert.Equal(t, "1234567890@authorizer.dev", res.User.Email)
|
||||
|
||||
res, err = resolvers.MobileBasicAuthSignupResolver(ctx, &model.MobileBasicAuthSignUpUpInput{
|
||||
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,7 +111,8 @@ func TestResolvers(t *testing.T) {
|
|||
// user resolvers tests
|
||||
loginTests(t, s)
|
||||
signupTests(t, s)
|
||||
mobileBasicAuthSingupTest(t, s)
|
||||
mobileSingupTest(t, s)
|
||||
mobileLoginTests(t, s)
|
||||
forgotPasswordTest(t, s)
|
||||
resendVerifyEmailTests(t, s)
|
||||
resetPasswordTest(t, s)
|
||||
|
|
|
@ -31,7 +31,7 @@ func testEndpointTest(t *testing.T, s TestSetup) {
|
|||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
assert.GreaterOrEqual(t, int64(201), *res.HTTPStatus)
|
||||
assert.GreaterOrEqual(t, *res.HTTPStatus, int64(200))
|
||||
assert.NotEmpty(t, res.Response)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user