From 313b510ba11c21e7466e4ee9cd2972caf88dfcd9 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sun, 25 Dec 2022 03:22:42 +0530 Subject: [PATCH] feat: add signup + login using mobile --- server/db/models/user.go | 2 +- server/db/providers/cassandradb/user.go | 6 - server/db/providers/dynamodb/env.go | 1 - server/db/providers/dynamodb/user.go | 8 +- server/db/providers/sql/user.go | 6 - server/env/persist_env.go | 1 - server/graph/generated/generated.go | 291 ++++++++++++++---- server/graph/model/models_gen.go | 10 +- server/graph/schema.graphqls | 16 +- server/graph/schema.resolvers.go | 11 +- server/resolvers/mobile_login.go | 216 +++++++++++++ ..._basic_auth_signup.go => mobile_signup.go} | 10 +- server/resolvers/update_profile.go | 5 + server/resolvers/update_user.go | 5 + server/test/mobile_login_test.go | 58 ++++ ...h_signup_test.go => mobile_signup_test.go} | 21 +- server/test/resolvers_test.go | 3 +- server/test/test_endpoint_test.go | 2 +- 18 files changed, 576 insertions(+), 96 deletions(-) create mode 100644 server/resolvers/mobile_login.go rename server/resolvers/{mobile_basic_auth_signup.go => mobile_signup.go} (95%) create mode 100644 server/test/mobile_login_test.go rename server/test/{mobile_basic_auth_signup_test.go => mobile_signup_test.go} (73%) diff --git a/server/db/models/user.go b/server/db/models/user.go index 6a50741..4628359 100644 --- a/server/db/models/user.go +++ b/server/db/models/user.go @@ -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"` diff --git a/server/db/providers/cassandradb/user.go b/server/db/providers/cassandradb/user.go index 5dd7c31..f8be709 100644 --- a/server/db/providers/cassandradb/user.go +++ b/server/db/providers/cassandradb/user.go @@ -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 diff --git a/server/db/providers/dynamodb/env.go b/server/db/providers/dynamodb/env.go index 7179555..d491e19 100644 --- a/server/db/providers/dynamodb/env.go +++ b/server/db/providers/dynamodb/env.go @@ -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() diff --git a/server/db/providers/dynamodb/user.go b/server/db/providers/dynamodb/user.go index 2ca1346..d7c47e3 100644 --- a/server/db/providers/dynamodb/user.go +++ b/server/db/providers/dynamodb/user.go @@ -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 diff --git a/server/db/providers/sql/user.go b/server/db/providers/sql/user.go index b8fd94f..a4b40c0 100644 --- a/server/db/providers/sql/user.go +++ b/server/db/providers/sql/user.go @@ -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 { diff --git a/server/env/persist_env.go b/server/env/persist_env.go index a460dbb..a224336 100644 --- a/server/env/persist_env.go +++ b/server/env/persist_env.go @@ -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) diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index 8ec60f1..88ae09a 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -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) } diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go index 6cffad0..d7c93fb 100644 --- a/server/graph/model/models_gen.go +++ b/server/graph/model/models_gen.go @@ -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"` diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index 2fb8d95..6986ada 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -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! diff --git a/server/graph/schema.resolvers.go b/server/graph/schema.resolvers.go index 4cbd9f0..3cc7b76 100644 --- a/server/graph/schema.resolvers.go +++ b/server/graph/schema.resolvers.go @@ -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) diff --git a/server/resolvers/mobile_login.go b/server/resolvers/mobile_login.go new file mode 100644 index 0000000..b6302b4 --- /dev/null +++ b/server/resolvers/mobile_login.go @@ -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 +} diff --git a/server/resolvers/mobile_basic_auth_signup.go b/server/resolvers/mobile_signup.go similarity index 95% rename from server/resolvers/mobile_basic_auth_signup.go rename to server/resolvers/mobile_signup.go index b626fae..e6b0027 100644 --- a/server/resolvers/mobile_basic_auth_signup.go +++ b/server/resolvers/mobile_signup.go @@ -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), diff --git a/server/resolvers/update_profile.go b/server/resolvers/update_profile.go index 1d45b61..ed8a8d4 100644 --- a/server/resolvers/update_profile.go +++ b/server/resolvers/update_profile.go @@ -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 } diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go index 057b797..9cc769a 100644 --- a/server/resolvers/update_user.go +++ b/server/resolvers/update_user.go @@ -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 } diff --git a/server/test/mobile_login_test.go b/server/test/mobile_login_test.go new file mode 100644 index 0000000..544a140 --- /dev/null +++ b/server/test/mobile_login_test.go @@ -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) + }) +} diff --git a/server/test/mobile_basic_auth_signup_test.go b/server/test/mobile_signup_test.go similarity index 73% rename from server/test/mobile_basic_auth_signup_test.go rename to server/test/mobile_signup_test.go index 17002e9..0135a66 100644 --- a/server/test/mobile_basic_auth_signup_test.go +++ b/server/test/mobile_signup_test.go @@ -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") }) } diff --git a/server/test/resolvers_test.go b/server/test/resolvers_test.go index bd27c11..2f93041 100644 --- a/server/test/resolvers_test.go +++ b/server/test/resolvers_test.go @@ -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) diff --git a/server/test/test_endpoint_test.go b/server/test/test_endpoint_test.go index 6613c58..1b29395 100644 --- a/server/test/test_endpoint_test.go +++ b/server/test/test_endpoint_test.go @@ -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) }) }