Merge branch 'main' of https://github.com/authorizerdev/authorizer
This commit is contained in:
commit
ef2a590608
8
app/package-lock.json
generated
8
app/package-lock.json
generated
|
@ -27,9 +27,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-js": {
|
||||
"version": "1.2.18",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.18.tgz",
|
||||
"integrity": "sha512-9j5U/4lqaaEcG78Zli+TtLJ0migSKhFwnXXunulAGTZOzQSTCJ/CSSPip5wWNa/Mkr6gdEMwk1HYfhIdk2A9Mg==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-cEzEVe7AewvOwOwoettiKRCq1e5Y33k9g8fJjqAoe3B/36iNN8wnZ5qgsPPZkqhv+Cvn6huj+YWtRimfVJ6d0w==",
|
||||
"dependencies": {
|
||||
"cross-fetch": "^3.1.5"
|
||||
},
|
||||
|
@ -45,7 +45,7 @@
|
|||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.2.0.tgz",
|
||||
"integrity": "sha512-MtunZgh30rzY9jSADVP1DRC4sOBC82zx/yhK8O/1ufOAi7vTDZwPjDHIMrG/xWPNUYTCeFPEKpZlKyB+TH/M1w==",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-js": "^1.2.18",
|
||||
"@authorizerdev/authorizer-js": "^2.0.0-beta.3",
|
||||
"validator": "^13.11.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
@ -71,6 +71,9 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
|||
...urlProps,
|
||||
redirect_uri: `${window.location.origin}/app/reset-password`,
|
||||
}}
|
||||
onPasswordReset={() => {
|
||||
setView(VIEW_TYPES.LOGIN);
|
||||
}}
|
||||
/>
|
||||
<Footer>
|
||||
<Link
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@authorizerdev/authorizer-js@^1.2.18":
|
||||
version "1.2.18"
|
||||
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.18.tgz"
|
||||
integrity sha512-9j5U/4lqaaEcG78Zli+TtLJ0migSKhFwnXXunulAGTZOzQSTCJ/CSSPip5wWNa/Mkr6gdEMwk1HYfhIdk2A9Mg==
|
||||
"@authorizerdev/authorizer-js@^2.0.0-beta.3":
|
||||
version "2.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.0-beta.3.tgz"
|
||||
integrity sha512-cEzEVe7AewvOwOwoettiKRCq1e5Y33k9g8fJjqAoe3B/36iNN8wnZ5qgsPPZkqhv+Cvn6huj+YWtRimfVJ6d0w==
|
||||
dependencies:
|
||||
cross-fetch "^3.1.5"
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.2.0.tgz"
|
||||
integrity sha512-MtunZgh30rzY9jSADVP1DRC4sOBC82zx/yhK8O/1ufOAi7vTDZwPjDHIMrG/xWPNUYTCeFPEKpZlKyB+TH/M1w==
|
||||
dependencies:
|
||||
"@authorizerdev/authorizer-js" "^1.2.18"
|
||||
"@authorizerdev/authorizer-js" "^2.0.0-beta.3"
|
||||
validator "^13.11.0"
|
||||
|
||||
"@babel/code-frame@^7.22.13":
|
||||
|
|
|
@ -150,6 +150,11 @@ type ComplexityRoot struct {
|
|||
Reason func(childComplexity int) int
|
||||
}
|
||||
|
||||
ForgotPasswordResponse struct {
|
||||
Message func(childComplexity int) int
|
||||
ShouldShowMobileOtpScreen func(childComplexity int) int
|
||||
}
|
||||
|
||||
GenerateJWTKeysResponse struct {
|
||||
PrivateKey func(childComplexity int) int
|
||||
PublicKey func(childComplexity int) int
|
||||
|
@ -356,7 +361,7 @@ type MutationResolver interface {
|
|||
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
|
||||
VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error)
|
||||
ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error)
|
||||
ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error)
|
||||
ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error)
|
||||
ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error)
|
||||
Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error)
|
||||
VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error)
|
||||
|
@ -1039,6 +1044,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Error.Reason(childComplexity), true
|
||||
|
||||
case "ForgotPasswordResponse.message":
|
||||
if e.complexity.ForgotPasswordResponse.Message == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ForgotPasswordResponse.Message(childComplexity), true
|
||||
|
||||
case "ForgotPasswordResponse.should_show_mobile_otp_screen":
|
||||
if e.complexity.ForgotPasswordResponse.ShouldShowMobileOtpScreen == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ForgotPasswordResponse.ShouldShowMobileOtpScreen(childComplexity), true
|
||||
|
||||
case "GenerateJWTKeysResponse.private_key":
|
||||
if e.complexity.GenerateJWTKeysResponse.PrivateKey == nil {
|
||||
break
|
||||
|
@ -2459,6 +2478,11 @@ type Response {
|
|||
message: String!
|
||||
}
|
||||
|
||||
type ForgotPasswordResponse {
|
||||
message: String!
|
||||
should_show_mobile_otp_screen: Boolean
|
||||
}
|
||||
|
||||
type InviteMembersResponse {
|
||||
message: String!
|
||||
Users: [User!]!
|
||||
|
@ -2791,13 +2815,16 @@ input UpdateUserInput {
|
|||
}
|
||||
|
||||
input ForgotPasswordInput {
|
||||
email: String!
|
||||
email: String
|
||||
phone_number: String
|
||||
state: String
|
||||
redirect_uri: String
|
||||
}
|
||||
|
||||
input ResetPasswordInput {
|
||||
token: String!
|
||||
token: String
|
||||
otp: String
|
||||
phone_number: String
|
||||
password: String!
|
||||
confirm_password: String!
|
||||
}
|
||||
|
@ -2950,7 +2977,7 @@ type Mutation {
|
|||
update_profile(params: UpdateProfileInput!): Response!
|
||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||
forgot_password(params: ForgotPasswordInput!): Response!
|
||||
forgot_password(params: ForgotPasswordInput!): ForgotPasswordResponse!
|
||||
reset_password(params: ResetPasswordInput!): Response!
|
||||
revoke(params: OAuthRevokeInput!): Response!
|
||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||
|
@ -7434,6 +7461,91 @@ func (ec *executionContext) fieldContext_Error_reason(ctx context.Context, field
|
|||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ForgotPasswordResponse_message(ctx context.Context, field graphql.CollectedField, obj *model.ForgotPasswordResponse) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ForgotPasswordResponse_message(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 obj.Message, nil
|
||||
})
|
||||
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.(string)
|
||||
fc.Result = res
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_ForgotPasswordResponse_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "ForgotPasswordResponse",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ForgotPasswordResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.ForgotPasswordResponse) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(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 obj.ShouldShowMobileOtpScreen, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*bool)
|
||||
fc.Result = res
|
||||
return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "ForgotPasswordResponse",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Boolean does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _GenerateJWTKeysResponse_secret(ctx context.Context, field graphql.CollectedField, obj *model.GenerateJWTKeysResponse) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_GenerateJWTKeysResponse_secret(ctx, field)
|
||||
if err != nil {
|
||||
|
@ -9135,9 +9247,9 @@ func (ec *executionContext) _Mutation_forgot_password(ctx context.Context, field
|
|||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*model.Response)
|
||||
res := resTmp.(*model.ForgotPasswordResponse)
|
||||
fc.Result = res
|
||||
return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
|
||||
return ec.marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_forgot_password(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
|
@ -9149,9 +9261,11 @@ func (ec *executionContext) fieldContext_Mutation_forgot_password(ctx context.Co
|
|||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "message":
|
||||
return ec.fieldContext_Response_message(ctx, field)
|
||||
return ec.fieldContext_ForgotPasswordResponse_message(ctx, field)
|
||||
case "should_show_mobile_otp_screen":
|
||||
return ec.fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type Response", field.Name)
|
||||
return nil, fmt.Errorf("no field named %q was found under type ForgotPasswordResponse", field.Name)
|
||||
},
|
||||
}
|
||||
defer func() {
|
||||
|
@ -16821,7 +16935,7 @@ func (ec *executionContext) unmarshalInputForgotPasswordInput(ctx context.Contex
|
|||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"email", "state", "redirect_uri"}
|
||||
fieldsInOrder := [...]string{"email", "phone_number", "state", "redirect_uri"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
|
@ -16832,11 +16946,20 @@ func (ec *executionContext) unmarshalInputForgotPasswordInput(ctx context.Contex
|
|||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
|
||||
data, err := ec.unmarshalNString2string(ctx, v)
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Email = data
|
||||
case "phone_number":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.PhoneNumber = data
|
||||
case "state":
|
||||
var err error
|
||||
|
||||
|
@ -17578,7 +17701,7 @@ func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context
|
|||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"token", "password", "confirm_password"}
|
||||
fieldsInOrder := [...]string{"token", "otp", "phone_number", "password", "confirm_password"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
|
@ -17589,11 +17712,29 @@ func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context
|
|||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("token"))
|
||||
data, err := ec.unmarshalNString2string(ctx, v)
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Token = data
|
||||
case "otp":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("otp"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Otp = data
|
||||
case "phone_number":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.PhoneNumber = data
|
||||
case "password":
|
||||
var err error
|
||||
|
||||
|
@ -19529,6 +19670,47 @@ func (ec *executionContext) _Error(ctx context.Context, sel ast.SelectionSet, ob
|
|||
return out
|
||||
}
|
||||
|
||||
var forgotPasswordResponseImplementors = []string{"ForgotPasswordResponse"}
|
||||
|
||||
func (ec *executionContext) _ForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, obj *model.ForgotPasswordResponse) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, forgotPasswordResponseImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
deferred := make(map[string]*graphql.FieldSet)
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("ForgotPasswordResponse")
|
||||
case "message":
|
||||
out.Values[i] = ec._ForgotPasswordResponse_message(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "should_show_mobile_otp_screen":
|
||||
out.Values[i] = ec._ForgotPasswordResponse_should_show_mobile_otp_screen(ctx, field, obj)
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch(ctx)
|
||||
if out.Invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
|
||||
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||
|
||||
for label, dfs := range deferred {
|
||||
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||
Label: label,
|
||||
Path: graphql.GetPath(ctx),
|
||||
FieldSet: dfs,
|
||||
Context: ctx,
|
||||
})
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
var generateJWTKeysResponseImplementors = []string{"GenerateJWTKeysResponse"}
|
||||
|
||||
func (ec *executionContext) _GenerateJWTKeysResponse(ctx context.Context, sel ast.SelectionSet, obj *model.GenerateJWTKeysResponse) graphql.Marshaler {
|
||||
|
@ -21531,6 +21713,20 @@ func (ec *executionContext) unmarshalNForgotPasswordInput2githubᚗcomᚋauthori
|
|||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNForgotPasswordResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v model.ForgotPasswordResponse) graphql.Marshaler {
|
||||
return ec._ForgotPasswordResponse(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v *model.ForgotPasswordResponse) graphql.Marshaler {
|
||||
if v == nil {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._ForgotPasswordResponse(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNGenerateJWTKeysInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysInput(ctx context.Context, v interface{}) (model.GenerateJWTKeysInput, error) {
|
||||
res, err := ec.unmarshalInputGenerateJWTKeysInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
|
|
|
@ -138,11 +138,17 @@ type Error struct {
|
|||
}
|
||||
|
||||
type ForgotPasswordInput struct {
|
||||
Email string `json:"email"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||
}
|
||||
|
||||
type ForgotPasswordResponse struct {
|
||||
Message string `json:"message"`
|
||||
ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen,omitempty"`
|
||||
}
|
||||
|
||||
type GenerateJWTKeysInput struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
@ -272,9 +278,11 @@ type ResendVerifyEmailInput struct {
|
|||
}
|
||||
|
||||
type ResetPasswordInput struct {
|
||||
Token string `json:"token"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
Token *string `json:"token,omitempty"`
|
||||
Otp *string `json:"otp,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Password string `json:"password"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
|
|
|
@ -117,6 +117,11 @@ type Response {
|
|||
message: String!
|
||||
}
|
||||
|
||||
type ForgotPasswordResponse {
|
||||
message: String!
|
||||
should_show_mobile_otp_screen: Boolean
|
||||
}
|
||||
|
||||
type InviteMembersResponse {
|
||||
message: String!
|
||||
Users: [User!]!
|
||||
|
@ -449,13 +454,16 @@ input UpdateUserInput {
|
|||
}
|
||||
|
||||
input ForgotPasswordInput {
|
||||
email: String!
|
||||
email: String
|
||||
phone_number: String
|
||||
state: String
|
||||
redirect_uri: String
|
||||
}
|
||||
|
||||
input ResetPasswordInput {
|
||||
token: String!
|
||||
token: String
|
||||
otp: String
|
||||
phone_number: String
|
||||
password: String!
|
||||
confirm_password: String!
|
||||
}
|
||||
|
@ -608,7 +616,7 @@ type Mutation {
|
|||
update_profile(params: UpdateProfileInput!): Response!
|
||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||
forgot_password(params: ForgotPasswordInput!): Response!
|
||||
forgot_password(params: ForgotPasswordInput!): ForgotPasswordResponse!
|
||||
reset_password(params: ResetPasswordInput!): Response!
|
||||
revoke(params: OAuthRevokeInput!): Response!
|
||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||
|
|
|
@ -58,7 +58,7 @@ func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.R
|
|||
}
|
||||
|
||||
// ForgotPassword is the resolver for the forgot_password field.
|
||||
func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) {
|
||||
func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) {
|
||||
return resolvers.ForgotPasswordResolver(ctx, params)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,29 +6,29 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/email"
|
||||
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/parsers"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/authorizerdev/authorizer/server/smsproviders"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/authorizerdev/authorizer/server/validators"
|
||||
)
|
||||
|
||||
// ForgotPasswordResolver is a resolver for forgot password mutation
|
||||
func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) {
|
||||
var res *model.Response
|
||||
|
||||
func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) {
|
||||
gc, err := utils.GinContextFromContext(ctx)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get GinContext: ", err)
|
||||
return res, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
||||
|
@ -36,74 +36,134 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
|||
log.Debug("Error getting basic auth disabled: ", err)
|
||||
isBasicAuthDisabled = true
|
||||
}
|
||||
if isBasicAuthDisabled {
|
||||
log.Debug("Basic authentication is disabled")
|
||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||
}
|
||||
params.Email = strings.ToLower(params.Email)
|
||||
|
||||
if !validators.IsValidEmail(params.Email) {
|
||||
log.Debug("Invalid email address: ", params.Email)
|
||||
return res, fmt.Errorf("invalid email")
|
||||
}
|
||||
|
||||
log := log.WithFields(log.Fields{
|
||||
"email": params.Email,
|
||||
})
|
||||
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
||||
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
|
||||
if err != nil {
|
||||
log.Debug("User not found: ", err)
|
||||
return res, fmt.Errorf(`user with this email not found`)
|
||||
log.Debug("Error getting email verification disabled: ", err)
|
||||
isEmailVerificationDisabled = true
|
||||
}
|
||||
|
||||
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||
if err != nil {
|
||||
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||
isMobileBasicAuthDisabled = true
|
||||
}
|
||||
isMobileVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
|
||||
if err != nil {
|
||||
log.Debug("Error getting mobile verification disabled: ", err)
|
||||
isMobileVerificationDisabled = true
|
||||
}
|
||||
|
||||
email := refs.StringValue(params.Email)
|
||||
phoneNumber := refs.StringValue(params.PhoneNumber)
|
||||
if email == "" && phoneNumber == "" {
|
||||
log.Debug("Email or phone number is required")
|
||||
return nil, fmt.Errorf(`email or phone number is required`)
|
||||
}
|
||||
log := log.WithFields(log.Fields{
|
||||
"email": refs.StringValue(params.Email),
|
||||
"phone_number": refs.StringValue(params.PhoneNumber),
|
||||
})
|
||||
isEmailLogin := email != ""
|
||||
isMobileLogin := phoneNumber != ""
|
||||
if isBasicAuthDisabled && isEmailLogin && !isEmailVerificationDisabled {
|
||||
log.Debug("Basic authentication is disabled.")
|
||||
return nil, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||
}
|
||||
if isMobileBasicAuthDisabled && isMobileLogin && !isMobileVerificationDisabled {
|
||||
log.Debug("Mobile basic authentication is disabled.")
|
||||
return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`)
|
||||
}
|
||||
var user *models.User
|
||||
if isEmailLogin {
|
||||
user, err = db.Provider.GetUserByEmail(ctx, email)
|
||||
} else {
|
||||
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user: ", err)
|
||||
return nil, fmt.Errorf(`bad user credentials`)
|
||||
}
|
||||
hostname := parsers.GetHost(gc)
|
||||
_, nonceHash, err := utils.GenerateNonce()
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate nonce: ", err)
|
||||
return res, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
redirectURI := ""
|
||||
// give higher preference to params redirect uri
|
||||
if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" {
|
||||
redirectURI = refs.StringValue(params.RedirectURI)
|
||||
} else {
|
||||
redirectURI, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||
if err != nil {
|
||||
log.Debug("ResetPasswordURL not found using default app url: ", err)
|
||||
redirectURI = hostname + "/app/reset-password"
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, redirectURI)
|
||||
if user.RevokedTimestamp != nil {
|
||||
log.Debug("User access is revoked")
|
||||
return nil, fmt.Errorf(`user access has been revoked`)
|
||||
}
|
||||
if isEmailLogin {
|
||||
redirectURI := ""
|
||||
// give higher preference to params redirect uri
|
||||
if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" {
|
||||
redirectURI = refs.StringValue(params.RedirectURI)
|
||||
} else {
|
||||
redirectURI, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||
if err != nil {
|
||||
log.Debug("ResetPasswordURL not found using default app url: ", err)
|
||||
redirectURI = hostname + "/app/reset-password"
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, redirectURI)
|
||||
}
|
||||
}
|
||||
verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create verification token", err)
|
||||
return nil, err
|
||||
}
|
||||
_, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{
|
||||
Token: verificationToken,
|
||||
Identifier: constants.VerificationTypeForgotPassword,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: email,
|
||||
Nonce: nonceHash,
|
||||
RedirectURI: redirectURI,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add verification request", err)
|
||||
return nil, err
|
||||
}
|
||||
// execute it as go routine so that we can reduce the api latency
|
||||
go mailService.SendEmail([]string{email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
"organization": utils.GetOrganization(),
|
||||
"verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI),
|
||||
})
|
||||
return &model.ForgotPasswordResponse{
|
||||
Message: `Please check your inbox! We have sent a password reset link.`,
|
||||
}, nil
|
||||
}
|
||||
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create verification token", err)
|
||||
return res, err
|
||||
if isMobileLogin {
|
||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||
otp := utils.GenerateOTP()
|
||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
Email: refs.StringValue(user.Email),
|
||||
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||
Otp: otp,
|
||||
ExpiresAt: expiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
mfaSession := uuid.NewString()
|
||||
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to add mfasession: ", err)
|
||||
return nil, err
|
||||
}
|
||||
cookie.SetMfaSession(gc, mfaSession)
|
||||
smsBody := strings.Builder{}
|
||||
smsBody.WriteString("Your verification code is: ")
|
||||
smsBody.WriteString(otpData.Otp)
|
||||
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
||||
log.Debug("Failed to send sms: ", err)
|
||||
// continue
|
||||
}
|
||||
return &model.ForgotPasswordResponse{
|
||||
Message: "Please enter the OTP sent to your phone number and change your password.",
|
||||
ShouldShowMobileOtpScreen: refs.NewBoolRef(true),
|
||||
}, nil
|
||||
}
|
||||
_, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{
|
||||
Token: verificationToken,
|
||||
Identifier: constants.VerificationTypeForgotPassword,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: params.Email,
|
||||
Nonce: nonceHash,
|
||||
RedirectURI: redirectURI,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add verification request", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// execute it as go routine so that we can reduce the api latency
|
||||
go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
"organization": utils.GetOrganization(),
|
||||
"verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI),
|
||||
})
|
||||
|
||||
res = &model.Response{
|
||||
Message: `Please check your inbox! We have sent a password reset link.`,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return nil, fmt.Errorf(`email or phone number verification needs to be enabled`)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
|
@ -23,8 +24,6 @@ import (
|
|||
"github.com/authorizerdev/authorizer/server/token"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
"github.com/authorizerdev/authorizer/server/validators"
|
||||
|
||||
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||
)
|
||||
|
||||
// LoginResolver is a resolver for login mutation
|
||||
|
@ -172,9 +171,10 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||
otp := utils.GenerateOTP()
|
||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
Email: refs.StringValue(user.Email),
|
||||
Otp: otp,
|
||||
ExpiresAt: expiresAt,
|
||||
Email: refs.StringValue(user.Email),
|
||||
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||
Otp: otp,
|
||||
ExpiresAt: expiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add otp: ", err)
|
||||
|
|
|
@ -9,8 +9,10 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/crypto"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/parsers"
|
||||
|
@ -29,97 +31,155 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
|
|||
log.Debug("Failed to get GinContext: ", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
verifyingToken := refs.StringValue(params.Token)
|
||||
otp := refs.StringValue(params.Otp)
|
||||
if verifyingToken == "" && otp == "" {
|
||||
log.Debug("Token or OTP is required")
|
||||
return res, fmt.Errorf(`token or otp is required`)
|
||||
}
|
||||
isTokenVerification := verifyingToken != ""
|
||||
isOtpVerification := otp != ""
|
||||
if isOtpVerification && refs.StringValue(params.PhoneNumber) == "" {
|
||||
log.Debug("Phone number is required")
|
||||
return res, fmt.Errorf(`phone number is required`)
|
||||
}
|
||||
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
||||
if err != nil {
|
||||
log.Debug("Error getting basic auth disabled: ", err)
|
||||
isBasicAuthDisabled = true
|
||||
}
|
||||
if isBasicAuthDisabled {
|
||||
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||
if err != nil {
|
||||
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||
isBasicAuthDisabled = true
|
||||
}
|
||||
if isTokenVerification && isBasicAuthDisabled {
|
||||
log.Debug("Basic authentication is disabled")
|
||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||
}
|
||||
|
||||
verificationRequest, err := db.Provider.GetVerificationRequestByToken(ctx, params.Token)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get verification request: ", err)
|
||||
return res, fmt.Errorf(`invalid token`)
|
||||
if isOtpVerification && isMobileBasicAuthDisabled {
|
||||
log.Debug("Mobile basic authentication is disabled")
|
||||
return res, fmt.Errorf(`mobile basic authentication is disabled for this instance`)
|
||||
}
|
||||
email := ""
|
||||
phoneNumber := refs.StringValue(params.PhoneNumber)
|
||||
var user *models.User
|
||||
var verificationRequest *models.VerificationRequest
|
||||
var otpRequest *models.OTP
|
||||
if isTokenVerification {
|
||||
verificationRequest, err = db.Provider.GetVerificationRequestByToken(ctx, verifyingToken)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get verification request: ", err)
|
||||
return res, fmt.Errorf(`invalid token`)
|
||||
}
|
||||
// verify if token exists in db
|
||||
hostname := parsers.GetHost(gc)
|
||||
claim, err := token.ParseJWTToken(verifyingToken)
|
||||
if err != nil {
|
||||
log.Debug("Failed to parse token: ", err)
|
||||
return res, fmt.Errorf(`invalid token`)
|
||||
}
|
||||
|
||||
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
||||
log.Debug("Failed to validate jwt claims: ", err)
|
||||
return res, fmt.Errorf(`invalid token`)
|
||||
}
|
||||
email = claim["sub"].(string)
|
||||
user, err = db.Provider.GetUserByEmail(ctx, email)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user: ", err)
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
if isOtpVerification {
|
||||
mfaSession, err := cookie.GetMfaSession(gc)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get otp request by email: ", err)
|
||||
return res, fmt.Errorf(`invalid session: %s`, err.Error())
|
||||
}
|
||||
// Get user by phone number
|
||||
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user by phone number: ", err)
|
||||
return res, fmt.Errorf(`user not found`)
|
||||
}
|
||||
if _, err := memorystore.Provider.GetMfaSession(user.ID, mfaSession); err != nil {
|
||||
log.Debug("Failed to get mfa session: ", err)
|
||||
return res, fmt.Errorf(`invalid session: %s`, err.Error())
|
||||
}
|
||||
otpRequest, err = db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get otp request by phone number: ", err)
|
||||
return res, fmt.Errorf(`invalid otp`)
|
||||
}
|
||||
if otpRequest.Otp != otp {
|
||||
log.Debug("Failed to verify otp request: Incorrect value")
|
||||
return res, fmt.Errorf(`invalid otp`)
|
||||
}
|
||||
}
|
||||
if params.Password != params.ConfirmPassword {
|
||||
log.Debug("Passwords do not match")
|
||||
return res, fmt.Errorf(`passwords don't match`)
|
||||
}
|
||||
|
||||
if err := validators.IsValidPassword(params.Password); err != nil {
|
||||
log.Debug("Invalid password")
|
||||
return res, err
|
||||
}
|
||||
|
||||
// verify if token exists in db
|
||||
hostname := parsers.GetHost(gc)
|
||||
claim, err := token.ParseJWTToken(params.Token)
|
||||
if err != nil {
|
||||
log.Debug("Failed to parse token: ", err)
|
||||
return res, fmt.Errorf(`invalid token`)
|
||||
}
|
||||
|
||||
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
||||
log.Debug("Failed to validate jwt claims: ", err)
|
||||
return res, fmt.Errorf(`invalid token`)
|
||||
}
|
||||
|
||||
email := claim["sub"].(string)
|
||||
log := log.WithFields(log.Fields{
|
||||
"email": email,
|
||||
"phone": phoneNumber,
|
||||
})
|
||||
user, err := db.Provider.GetUserByEmail(ctx, email)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user: ", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
password, _ := crypto.EncryptPassword(params.Password)
|
||||
user.Password = &password
|
||||
|
||||
signupMethod := user.SignupMethods
|
||||
if !strings.Contains(signupMethod, constants.AuthRecipeMethodBasicAuth) {
|
||||
if !strings.Contains(signupMethod, constants.AuthRecipeMethodBasicAuth) && isTokenVerification {
|
||||
signupMethod = signupMethod + "," + constants.AuthRecipeMethodBasicAuth
|
||||
|
||||
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||
if err != nil {
|
||||
log.Debug("MFA service not enabled: ", err)
|
||||
isMFAEnforced = false
|
||||
// helpful if user has not signed up with basic auth
|
||||
if user.EmailVerifiedAt == nil {
|
||||
now := time.Now().Unix()
|
||||
user.EmailVerifiedAt = &now
|
||||
}
|
||||
|
||||
if isMFAEnforced {
|
||||
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
||||
}
|
||||
if !strings.Contains(signupMethod, constants.AuthRecipeMethodMobileOTP) && isOtpVerification {
|
||||
signupMethod = signupMethod + "," + constants.AuthRecipeMethodMobileOTP
|
||||
// helpful if user has not signed up with basic auth
|
||||
if user.PhoneNumberVerifiedAt == nil {
|
||||
now := time.Now().Unix()
|
||||
user.PhoneNumberVerifiedAt = &now
|
||||
}
|
||||
}
|
||||
user.SignupMethods = signupMethod
|
||||
|
||||
// helpful if user has not signed up with basic auth
|
||||
if user.EmailVerifiedAt == nil {
|
||||
now := time.Now().Unix()
|
||||
user.EmailVerifiedAt = &now
|
||||
}
|
||||
|
||||
// delete from verification table
|
||||
err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
|
||||
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||
if err != nil {
|
||||
log.Debug("Failed to delete verification request: ", err)
|
||||
return res, err
|
||||
log.Debug("MFA service not enabled: ", err)
|
||||
isMFAEnforced = false
|
||||
}
|
||||
if isMFAEnforced {
|
||||
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
||||
}
|
||||
|
||||
_, err = db.Provider.UpdateUser(ctx, user)
|
||||
if err != nil {
|
||||
log.Debug("Failed to update user: ", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
if isTokenVerification {
|
||||
// delete from verification table
|
||||
err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
|
||||
if err != nil {
|
||||
log.Debug("Failed to delete verification request: ", err)
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
if isOtpVerification {
|
||||
// delete from otp table
|
||||
err = db.Provider.DeleteOTP(ctx, otpRequest)
|
||||
if err != nil {
|
||||
log.Debug("Failed to delete otp request: ", err)
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
res = &model.Response{
|
||||
Message: `Password updated successfully.`,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
|
61
server/test/forgot_password_mobile_test.go
Normal file
61
server/test/forgot_password_mobile_test.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func forgotPasswordMobileTest(t *testing.T, s TestSetup) {
|
||||
t.Helper()
|
||||
t.Run(`should run forgot password for mobile`, func(t *testing.T) {
|
||||
req, ctx := createContext(s)
|
||||
phoneNumber := "6240345678"
|
||||
res, err := resolvers.SignupResolver(ctx, model.SignUpInput{
|
||||
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
forgotPasswordRes, err := resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
||||
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||
})
|
||||
assert.Nil(t, err, "no errors for forgot password")
|
||||
assert.NotNil(t, forgotPasswordRes)
|
||||
assert.True(t, *forgotPasswordRes.ShouldShowMobileOtpScreen)
|
||||
otpReq, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
||||
assert.Nil(t, err)
|
||||
mfaSession := uuid.NewString()
|
||||
memorystore.Provider.SetMfaSession(res.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix())
|
||||
cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession)
|
||||
cookie = strings.TrimSuffix(cookie, ";")
|
||||
req.Header.Set("Cookie", cookie)
|
||||
// Reset password
|
||||
resetPasswordRes, err := resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||
Otp: refs.NewStringRef(otpReq.Otp),
|
||||
Password: s.TestInfo.Password + "test",
|
||||
ConfirmPassword: s.TestInfo.Password + "test",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, resetPasswordRes)
|
||||
// Test login
|
||||
loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{
|
||||
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||
Password: s.TestInfo.Password + "test",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, loginRes)
|
||||
})
|
||||
}
|
|
@ -24,7 +24,7 @@ func forgotPasswordTest(t *testing.T, s TestSetup) {
|
|||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
forgotPasswordRes, err := resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
||||
Email: email,
|
||||
Email: refs.NewStringRef(email),
|
||||
})
|
||||
assert.Nil(t, err, "no errors for forgot password")
|
||||
assert.NotNil(t, forgotPasswordRes)
|
||||
|
|
|
@ -130,6 +130,7 @@ func TestResolvers(t *testing.T) {
|
|||
mobileLoginTests(t, s)
|
||||
totpLoginTest(t, s)
|
||||
forgotPasswordTest(t, s)
|
||||
forgotPasswordMobileTest(t, s)
|
||||
resendVerifyEmailTests(t, s)
|
||||
resetPasswordTest(t, s)
|
||||
verifyEmailTest(t, s)
|
||||
|
|
|
@ -23,37 +23,30 @@ func resetPasswordTest(t *testing.T, s TestSetup) {
|
|||
})
|
||||
assert.NoError(t, err)
|
||||
_, err = resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
||||
Email: email,
|
||||
Email: refs.NewStringRef(email),
|
||||
})
|
||||
assert.Nil(t, err, "no errors for forgot password")
|
||||
|
||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword)
|
||||
assert.Nil(t, err, "should get forgot password request")
|
||||
assert.NotNil(t, verificationRequest)
|
||||
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||
Token: verificationRequest.Token,
|
||||
Token: refs.NewStringRef(verificationRequest.Token),
|
||||
Password: "test1",
|
||||
ConfirmPassword: "test",
|
||||
})
|
||||
|
||||
assert.NotNil(t, err, "passwords don't match")
|
||||
|
||||
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||
Token: verificationRequest.Token,
|
||||
Token: refs.NewStringRef(verificationRequest.Token),
|
||||
Password: "test1",
|
||||
ConfirmPassword: "test1",
|
||||
})
|
||||
|
||||
assert.NotNil(t, err, "invalid password")
|
||||
|
||||
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||
Token: verificationRequest.Token,
|
||||
Token: refs.NewStringRef(verificationRequest.Token),
|
||||
Password: "Test@1234",
|
||||
ConfirmPassword: "Test@1234",
|
||||
})
|
||||
|
||||
assert.Nil(t, err, "password changed successfully")
|
||||
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user