From 4cc41dc4f82cc592696511c6fdd3821134a7d8f4 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 21 Jul 2021 13:36:26 +0530 Subject: [PATCH] fix: get token logic, add buffer time fix typos --- server/graph/generated/generated.go | 297 +++++++++------------- server/graph/model/models_gen.go | 13 +- server/graph/schema.graphqls | 9 +- server/graph/schema.resolvers.go | 8 +- server/resolvers/forgotPassword.go | 41 +-- server/resolvers/forgotPasswordRequest.go | 50 ---- server/resolvers/resetPassword.go | 47 ++++ server/resolvers/token.go | 7 +- server/resolvers/users.go | 1 - 9 files changed, 215 insertions(+), 258 deletions(-) delete mode 100644 server/resolvers/forgotPasswordRequest.go create mode 100644 server/resolvers/resetPassword.go diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index a6bc86a..ddc2479 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -56,14 +56,14 @@ type ComplexityRoot struct { } Mutation struct { - ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int - ForgotPasswordRequest func(childComplexity int, params model.ForgotPasswordRequestInput) int - Login func(childComplexity int, params model.LoginInput) int - Logout func(childComplexity int) int - ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int - Signup func(childComplexity int, params model.SignUpInput) int - UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int - VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int + ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int + Login func(childComplexity int, params model.LoginInput) int + Logout func(childComplexity int) int + ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int + ResetPassword func(childComplexity int, params model.ResetPassowrdInput) int + Signup func(childComplexity int, params model.SignUpInput) int + UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int + VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int } Query struct { @@ -85,7 +85,6 @@ type ComplexityRoot struct { ID func(childComplexity int) int Image func(childComplexity int) int LastName func(childComplexity int) int - Password func(childComplexity int) int SignupMethod func(childComplexity int) int UpdatedAt func(childComplexity int) int } @@ -108,8 +107,8 @@ type MutationResolver interface { UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.LoginResponse, error) ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) - ForgotPasswordRequest(ctx context.Context, params model.ForgotPasswordRequestInput) (*model.Response, error) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) + ResetPassword(ctx context.Context, params model.ResetPassowrdInput) (*model.Response, error) } type QueryResolver interface { Users(ctx context.Context) ([]*model.User, error) @@ -187,18 +186,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.ForgotPassword(childComplexity, args["params"].(model.ForgotPasswordInput)), true - case "Mutation.forgotPasswordRequest": - if e.complexity.Mutation.ForgotPasswordRequest == nil { - break - } - - args, err := ec.field_Mutation_forgotPasswordRequest_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Mutation.ForgotPasswordRequest(childComplexity, args["params"].(model.ForgotPasswordRequestInput)), true - case "Mutation.login": if e.complexity.Mutation.Login == nil { break @@ -230,6 +217,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.ResendVerifyEmail(childComplexity, args["params"].(model.ResendVerifyEmailInput)), true + case "Mutation.resetPassword": + if e.complexity.Mutation.ResetPassword == nil { + break + } + + args, err := ec.field_Mutation_resetPassword_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ResetPassword(childComplexity, args["params"].(model.ResetPassowrdInput)), true + case "Mutation.signup": if e.complexity.Mutation.Signup == nil { break @@ -350,13 +349,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.User.LastName(childComplexity), true - case "User.password": - if e.complexity.User.Password == nil { - break - } - - return e.complexity.User.Password(childComplexity), true - case "User.signupMethod": if e.complexity.User.SignupMethod == nil { break @@ -496,7 +488,6 @@ type User { firstName: String lastName: String emailVerifiedAt: Int64 - password: String image: String createdAt: Int64 updatedAt: Int64 @@ -560,13 +551,13 @@ input UpdateProfileInput { email: String } -input ForgotPasswordRequestInput { +input ForgotPasswordInput { email: String! } -input ForgotPasswordInput { +input ResetPassowrdInput { token: String! - newPassword: String! + password: String! confirmPassword: String! } @@ -577,8 +568,8 @@ type Mutation { updateProfile(params: UpdateProfileInput!): Response! verifyEmail(params: VerifyEmailInput!): LoginResponse! resendVerifyEmail(params: ResendVerifyEmailInput!): Response! - forgotPasswordRequest(params: ForgotPasswordRequestInput!): Response! forgotPassword(params: ForgotPasswordInput!): Response! + resetPassword(params: ResetPassowrdInput!): Response! } type Query { @@ -595,21 +586,6 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) // region ***************************** args.gotpl ***************************** -func (ec *executionContext) field_Mutation_forgotPasswordRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.ForgotPasswordRequestInput - if tmp, ok := rawArgs["params"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) - arg0, err = ec.unmarshalNForgotPasswordRequestInput2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐForgotPasswordRequestInput(ctx, tmp) - if err != nil { - return nil, err - } - } - args["params"] = arg0 - return args, nil -} - func (ec *executionContext) field_Mutation_forgotPassword_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -655,6 +631,21 @@ func (ec *executionContext) field_Mutation_resendVerifyEmail_args(ctx context.Co return args, nil } +func (ec *executionContext) field_Mutation_resetPassword_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.ResetPassowrdInput + if tmp, ok := rawArgs["params"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + arg0, err = ec.unmarshalNResetPassowrdInput2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResetPassowrdInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["params"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_signup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1199,48 +1190,6 @@ func (ec *executionContext) _Mutation_resendVerifyEmail(ctx context.Context, fie return ec.marshalNResponse2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } -func (ec *executionContext) _Mutation_forgotPasswordRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Mutation", - Field: field, - Args: nil, - IsMethod: true, - IsResolver: true, - } - - ctx = graphql.WithFieldContext(ctx, fc) - rawArgs := field.ArgumentMap(ec.Variables) - args, err := ec.field_Mutation_forgotPasswordRequest_args(ctx, rawArgs) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - fc.Args = args - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().ForgotPasswordRequest(rctx, args["params"].(model.ForgotPasswordRequestInput)) - }) - 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.Response) - fc.Result = res - return ec.marshalNResponse2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) -} - func (ec *executionContext) _Mutation_forgotPassword(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1283,6 +1232,48 @@ func (ec *executionContext) _Mutation_forgotPassword(ctx context.Context, field return ec.marshalNResponse2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_resetPassword(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_resetPassword_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ResetPassword(rctx, args["params"].(model.ResetPassowrdInput)) + }) + 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.Response) + fc.Result = res + return ec.marshalNResponse2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_users(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1727,38 +1718,6 @@ func (ec *executionContext) _User_emailVerifiedAt(ctx context.Context, field gra return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) } -func (ec *executionContext) _User_password(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "User", - Field: field, - Args: nil, - IsMethod: false, - IsResolver: false, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Password, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - func (ec *executionContext) _User_image(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -3173,42 +3132,6 @@ func (ec *executionContext) unmarshalInputForgotPasswordInput(ctx context.Contex var it model.ForgotPasswordInput var asMap = obj.(map[string]interface{}) - for k, v := range asMap { - switch k { - case "token": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("token")) - it.Token, err = ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - case "newPassword": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("newPassword")) - it.NewPassword, err = ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - case "confirmPassword": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("confirmPassword")) - it.ConfirmPassword, err = ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - } - } - - return it, nil -} - -func (ec *executionContext) unmarshalInputForgotPasswordRequestInput(ctx context.Context, obj interface{}) (model.ForgotPasswordRequestInput, error) { - var it model.ForgotPasswordRequestInput - var asMap = obj.(map[string]interface{}) - for k, v := range asMap { switch k { case "email": @@ -3273,6 +3196,42 @@ func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Con return it, nil } +func (ec *executionContext) unmarshalInputResetPassowrdInput(ctx context.Context, obj interface{}) (model.ResetPassowrdInput, error) { + var it model.ResetPassowrdInput + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "token": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("token")) + it.Token, 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 "confirmPassword": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("confirmPassword")) + it.ConfirmPassword, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj interface{}) (model.SignUpInput, error) { var it model.SignUpInput var asMap = obj.(map[string]interface{}) @@ -3539,13 +3498,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } - case "forgotPasswordRequest": - out.Values[i] = ec._Mutation_forgotPasswordRequest(ctx, field) + case "forgotPassword": + out.Values[i] = ec._Mutation_forgotPassword(ctx, field) if out.Values[i] == graphql.Null { invalids++ } - case "forgotPassword": - out.Values[i] = ec._Mutation_forgotPassword(ctx, field) + case "resetPassword": + out.Values[i] = ec._Mutation_resetPassword(ctx, field) if out.Values[i] == graphql.Null { invalids++ } @@ -3702,8 +3661,6 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj out.Values[i] = ec._User_lastName(ctx, field, obj) case "emailVerifiedAt": out.Values[i] = ec._User_emailVerifiedAt(ctx, field, obj) - case "password": - out.Values[i] = ec._User_password(ctx, field, obj) case "image": out.Values[i] = ec._User_image(ctx, field, obj) case "createdAt": @@ -4025,11 +3982,6 @@ func (ec *executionContext) unmarshalNForgotPasswordInput2githubᚗcomᚋyauthde return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNForgotPasswordRequestInput2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐForgotPasswordRequestInput(ctx context.Context, v interface{}) (model.ForgotPasswordRequestInput, error) { - res, err := ec.unmarshalInputForgotPasswordRequestInput(ctx, v) - return res, graphql.ErrorOnPath(ctx, err) -} - func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) { res, err := graphql.UnmarshalID(v) return res, graphql.ErrorOnPath(ctx, err) @@ -4069,6 +4021,11 @@ func (ec *executionContext) unmarshalNResendVerifyEmailInput2githubᚗcomᚋyaut return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalNResetPassowrdInput2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResetPassowrdInput(ctx context.Context, v interface{}) (model.ResetPassowrdInput, error) { + res, err := ec.unmarshalInputResetPassowrdInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalNResponse2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐResponse(ctx context.Context, sel ast.SelectionSet, v model.Response) graphql.Marshaler { return ec._Response(ctx, sel, &v) } diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go index c880d39..11aeb68 100644 --- a/server/graph/model/models_gen.go +++ b/server/graph/model/models_gen.go @@ -8,12 +8,6 @@ type Error struct { } type ForgotPasswordInput struct { - Token string `json:"token"` - NewPassword string `json:"newPassword"` - ConfirmPassword string `json:"confirmPassword"` -} - -type ForgotPasswordRequestInput struct { Email string `json:"email"` } @@ -33,6 +27,12 @@ type ResendVerifyEmailInput struct { Email string `json:"email"` } +type ResetPassowrdInput struct { + Token string `json:"token"` + Password string `json:"password"` + ConfirmPassword string `json:"confirmPassword"` +} + type Response struct { Message string `json:"message"` } @@ -63,7 +63,6 @@ type User struct { FirstName *string `json:"firstName"` LastName *string `json:"lastName"` EmailVerifiedAt *int64 `json:"emailVerifiedAt"` - Password *string `json:"password"` Image *string `json:"image"` CreatedAt *int64 `json:"createdAt"` UpdatedAt *int64 `json:"updatedAt"` diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index 1b988b5..a0b7cce 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -10,7 +10,6 @@ type User { firstName: String lastName: String emailVerifiedAt: Int64 - password: String image: String createdAt: Int64 updatedAt: Int64 @@ -74,13 +73,13 @@ input UpdateProfileInput { email: String } -input ForgotPasswordRequestInput { +input ForgotPasswordInput { email: String! } -input ForgotPasswordInput { +input ResetPassowrdInput { token: String! - newPassword: String! + password: String! confirmPassword: String! } @@ -91,8 +90,8 @@ type Mutation { updateProfile(params: UpdateProfileInput!): Response! verifyEmail(params: VerifyEmailInput!): LoginResponse! resendVerifyEmail(params: ResendVerifyEmailInput!): Response! - forgotPasswordRequest(params: ForgotPasswordRequestInput!): Response! forgotPassword(params: ForgotPasswordInput!): Response! + resetPassword(params: ResetPassowrdInput!): Response! } type Query { diff --git a/server/graph/schema.resolvers.go b/server/graph/schema.resolvers.go index b9501e8..b29541c 100644 --- a/server/graph/schema.resolvers.go +++ b/server/graph/schema.resolvers.go @@ -35,14 +35,14 @@ func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.R return resolvers.ResendVerifyEmail(ctx, params) } -func (r *mutationResolver) ForgotPasswordRequest(ctx context.Context, params model.ForgotPasswordRequestInput) (*model.Response, error) { - return resolvers.ForgotPasswordRequest(ctx, params) -} - func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) { return resolvers.ForgotPassword(ctx, params) } +func (r *mutationResolver) ResetPassword(ctx context.Context, params model.ResetPassowrdInput) (*model.Response, error) { + return resolvers.ResetPassword(ctx, params) +} + func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) { return resolvers.Users(ctx) } diff --git a/server/resolvers/forgotPassword.go b/server/resolvers/forgotPassword.go index c17b1f4..a70591a 100644 --- a/server/resolvers/forgotPassword.go +++ b/server/resolvers/forgotPassword.go @@ -3,44 +3,47 @@ package resolvers import ( "context" "fmt" + "log" + "strings" + "time" "github.com/yauthdev/yauth/server/db" + "github.com/yauthdev/yauth/server/enum" "github.com/yauthdev/yauth/server/graph/model" "github.com/yauthdev/yauth/server/utils" ) func ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) { var res *model.Response + params.Email = strings.ToLower(params.Email) - if params.NewPassword != params.ConfirmPassword { - return res, fmt.Errorf(`passwords don't match`) + if !utils.IsValidEmail(params.Email) { + return res, fmt.Errorf("invalid email") } - _, err := db.Mgr.GetVerificationByToken(params.Token) + _, err := db.Mgr.GetUserByEmail(params.Email) if err != nil { - return res, fmt.Errorf(`invalid token`) + return res, fmt.Errorf(`user with this email not found`) } - // verify if token exists in db - claim, err := utils.VerifyVerificationToken(params.Token) + token, err := utils.CreateVerificationToken(params.Email, enum.ForgotPassword.String()) if err != nil { - return res, fmt.Errorf(`invalid token`) + log.Println(`Error generating token`, err) } + db.Mgr.AddVerification(db.VerificationRequest{ + Token: token, + Identifier: enum.ForgotPassword.String(), + ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), + Email: params.Email, + }) - user, err := db.Mgr.GetUserByEmail(claim.Email) - if err != nil { - return res, err - } - - password, _ := utils.HashPassword(params.NewPassword) - user.Password = password - - // delete from verification table - db.Mgr.DeleteToken(claim.Email) - db.Mgr.UpdateUser(user) + // exec it as go routin so that we can reduce the api latency + go func() { + utils.SendForgotPasswordMail(params.Email, token) + }() res = &model.Response{ - Message: `Password updated successfully.`, + Message: `Please check your inbox! We have sent a password reset link.`, } return res, nil diff --git a/server/resolvers/forgotPasswordRequest.go b/server/resolvers/forgotPasswordRequest.go deleted file mode 100644 index 4e38537..0000000 --- a/server/resolvers/forgotPasswordRequest.go +++ /dev/null @@ -1,50 +0,0 @@ -package resolvers - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/yauthdev/yauth/server/db" - "github.com/yauthdev/yauth/server/enum" - "github.com/yauthdev/yauth/server/graph/model" - "github.com/yauthdev/yauth/server/utils" -) - -func ForgotPasswordRequest(ctx context.Context, params model.ForgotPasswordRequestInput) (*model.Response, error) { - var res *model.Response - params.Email = strings.ToLower(params.Email) - - if !utils.IsValidEmail(params.Email) { - return res, fmt.Errorf("invalid email") - } - - _, err := db.Mgr.GetUserByEmail(params.Email) - if err != nil { - return res, fmt.Errorf(`user with this email not found`) - } - - token, err := utils.CreateVerificationToken(params.Email, enum.ForgotPassword.String()) - if err != nil { - log.Println(`Error generating token`, err) - } - db.Mgr.AddVerification(db.VerificationRequest{ - Token: token, - Identifier: enum.ForgotPassword.String(), - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - Email: params.Email, - }) - - // exec it as go routin so that we can reduce the api latency - go func() { - utils.SendForgotPasswordMail(params.Email, token) - }() - - res = &model.Response{ - Message: `Please check your inbox! We have sent a password reset link.`, - } - - return res, nil -} diff --git a/server/resolvers/resetPassword.go b/server/resolvers/resetPassword.go new file mode 100644 index 0000000..6c09257 --- /dev/null +++ b/server/resolvers/resetPassword.go @@ -0,0 +1,47 @@ +package resolvers + +import ( + "context" + "fmt" + + "github.com/yauthdev/yauth/server/db" + "github.com/yauthdev/yauth/server/graph/model" + "github.com/yauthdev/yauth/server/utils" +) + +func ResetPassword(ctx context.Context, params model.ResetPassowrdInput) (*model.Response, error) { + var res *model.Response + + if params.Password != params.ConfirmPassword { + return res, fmt.Errorf(`passwords don't match`) + } + + _, err := db.Mgr.GetVerificationByToken(params.Token) + if err != nil { + return res, fmt.Errorf(`invalid token`) + } + + // verify if token exists in db + claim, err := utils.VerifyVerificationToken(params.Token) + if err != nil { + return res, fmt.Errorf(`invalid token`) + } + + user, err := db.Mgr.GetUserByEmail(claim.Email) + if err != nil { + return res, err + } + + password, _ := utils.HashPassword(params.Password) + user.Password = password + + // delete from verification table + db.Mgr.DeleteToken(claim.Email) + db.Mgr.UpdateUser(user) + + res = &model.Response{ + Message: `Password updated successfully.`, + } + + return res, nil +} diff --git a/server/resolvers/token.go b/server/resolvers/token.go index 8a67099..be62f95 100644 --- a/server/resolvers/token.go +++ b/server/resolvers/token.go @@ -3,6 +3,7 @@ package resolvers import ( "context" "fmt" + "time" "github.com/yauthdev/yauth/server/db" "github.com/yauthdev/yauth/server/enum" @@ -37,9 +38,11 @@ func Token(ctx context.Context) (*model.LoginResponse, error) { if sessionToken == "" { return res, fmt.Errorf(`unauthorized`) } - // TODO check if session token has expired + // TODO check if refresh/session token has expired - if accessTokenErr != nil { + expiresTimeObj := time.Unix(expiresAt, 0) + currentTimeObj := time.Now() + if accessTokenErr != nil || expiresTimeObj.Sub(currentTimeObj).Minutes() <= 5 { // if access token has expired and refresh/session token is valid // generate new accessToken token, expiresAt, _ = utils.CreateAuthToken(utils.UserAuthInfo{ diff --git a/server/resolvers/users.go b/server/resolvers/users.go index 3c0de2d..aaef1af 100644 --- a/server/resolvers/users.go +++ b/server/resolvers/users.go @@ -32,7 +32,6 @@ func Users(ctx context.Context) ([]*model.User, error) { SignupMethod: user.SignupMethod, FirstName: &user.FirstName, LastName: &user.LastName, - Password: &user.Password, EmailVerifiedAt: &user.EmailVerifiedAt, CreatedAt: &user.CreatedAt, UpdatedAt: &user.UpdatedAt,