feat: otp resolvers updated

This commit is contained in:
anik-ghosh-au7 2022-07-29 13:49:46 +05:30
parent e3c58ffbb0
commit 4e3d73e767
7 changed files with 195 additions and 3 deletions

View File

@ -159,6 +159,7 @@ type ComplexityRoot struct {
Login func(childComplexity int, params model.LoginInput) int Login func(childComplexity int, params model.LoginInput) int
Logout func(childComplexity int) int Logout func(childComplexity int) int
MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int MagicLinkLogin func(childComplexity int, params model.MagicLinkLoginInput) int
ResendOtp func(childComplexity int, params model.ResendOTPRequest) int
ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int
ResetPassword func(childComplexity int, params model.ResetPasswordInput) int ResetPassword func(childComplexity int, params model.ResetPasswordInput) int
Revoke func(childComplexity int, params model.OAuthRevokeInput) int Revoke func(childComplexity int, params model.OAuthRevokeInput) int
@ -296,6 +297,7 @@ type MutationResolver interface {
ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error)
Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error) Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error)
VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error) VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error)
ResendOtp(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error)
DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error)
UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error)
AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error)
@ -1067,6 +1069,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true return e.complexity.Mutation.MagicLinkLogin(childComplexity, args["params"].(model.MagicLinkLoginInput)), true
case "Mutation.resend_otp":
if e.complexity.Mutation.ResendOtp == nil {
break
}
args, err := ec.field_Mutation_resend_otp_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.ResendOtp(childComplexity, args["params"].(model.ResendOTPRequest)), true
case "Mutation.resend_verify_email": case "Mutation.resend_verify_email":
if e.complexity.Mutation.ResendVerifyEmail == nil { if e.complexity.Mutation.ResendVerifyEmail == nil {
break break
@ -2246,6 +2260,10 @@ input VerifyOTPRequest {
otp: String! otp: String!
} }
input ResendOTPRequest {
email: String!
}
type Mutation { type Mutation {
signup(params: SignUpInput!): AuthResponse! signup(params: SignUpInput!): AuthResponse!
login(params: LoginInput!): AuthResponse! login(params: LoginInput!): AuthResponse!
@ -2258,6 +2276,7 @@ type Mutation {
reset_password(params: ResetPasswordInput!): Response! reset_password(params: ResetPasswordInput!): Response!
revoke(params: OAuthRevokeInput!): Response! revoke(params: OAuthRevokeInput!): Response!
verify_otp(params: VerifyOTPRequest!): AuthResponse! verify_otp(params: VerifyOTPRequest!): AuthResponse!
resend_otp(params: ResendOTPRequest!): Response!
# admin only apis # admin only apis
_delete_user(params: DeleteUserInput!): Response! _delete_user(params: DeleteUserInput!): Response!
_update_user(params: UpdateUserInput!): User! _update_user(params: UpdateUserInput!): User!
@ -2586,6 +2605,21 @@ func (ec *executionContext) field_Mutation_magic_link_login_args(ctx context.Con
return args, nil return args, nil
} }
func (ec *executionContext) field_Mutation_resend_otp_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 model.ResendOTPRequest
if tmp, ok := rawArgs["params"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params"))
arg0, err = ec.unmarshalNResendOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendOTPRequest(ctx, tmp)
if err != nil {
return nil, err
}
}
args["params"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_resend_verify_email_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { func (ec *executionContext) field_Mutation_resend_verify_email_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error var err error
args := map[string]interface{}{} args := map[string]interface{}{}
@ -5934,6 +5968,48 @@ func (ec *executionContext) _Mutation_verify_otp(ctx context.Context, field grap
return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res)
} }
func (ec *executionContext) _Mutation_resend_otp(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_resend_otp_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().ResendOtp(rctx, args["params"].(model.ResendOTPRequest))
})
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ᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation__delete_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Mutation__delete_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -10705,6 +10781,29 @@ func (ec *executionContext) unmarshalInputPaginationInput(ctx context.Context, o
return it, nil return it, nil
} }
func (ec *executionContext) unmarshalInputResendOTPRequest(ctx context.Context, obj interface{}) (model.ResendOTPRequest, error) {
var it model.ResendOTPRequest
asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
asMap[k] = v
}
for k, v := range asMap {
switch k {
case "email":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
it.Email, err = ec.unmarshalNString2string(ctx, v)
if err != nil {
return it, err
}
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Context, obj interface{}) (model.ResendVerifyEmailInput, error) { func (ec *executionContext) unmarshalInputResendVerifyEmailInput(ctx context.Context, obj interface{}) (model.ResendVerifyEmailInput, error) {
var it model.ResendVerifyEmailInput var it model.ResendVerifyEmailInput
asMap := map[string]interface{}{} asMap := map[string]interface{}{}
@ -12255,6 +12354,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
invalids++ invalids++
} }
case "resend_otp":
out.Values[i] = ec._Mutation_resend_otp(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}
case "_delete_user": case "_delete_user":
out.Values[i] = ec._Mutation__delete_user(ctx, field) out.Values[i] = ec._Mutation__delete_user(ctx, field)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
@ -13484,6 +13588,11 @@ func (ec *executionContext) marshalNPagination2ᚖgithubᚗcomᚋauthorizerdev
return ec._Pagination(ctx, sel, v) return ec._Pagination(ctx, sel, v)
} }
func (ec *executionContext) unmarshalNResendOTPRequest2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendOTPRequest(ctx context.Context, v interface{}) (model.ResendOTPRequest, error) {
res, err := ec.unmarshalInputResendOTPRequest(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalNResendVerifyEmailInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendVerifyEmailInput(ctx context.Context, v interface{}) (model.ResendVerifyEmailInput, error) { func (ec *executionContext) unmarshalNResendVerifyEmailInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResendVerifyEmailInput(ctx context.Context, v interface{}) (model.ResendVerifyEmailInput, error) {
res, err := ec.unmarshalInputResendVerifyEmailInput(ctx, v) res, err := ec.unmarshalInputResendVerifyEmailInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)

View File

@ -185,6 +185,10 @@ type PaginationInput struct {
Page *int64 `json:"page"` Page *int64 `json:"page"`
} }
type ResendOTPRequest struct {
Email string `json:"email"`
}
type ResendVerifyEmailInput struct { type ResendVerifyEmailInput struct {
Email string `json:"email"` Email string `json:"email"`
Identifier string `json:"identifier"` Identifier string `json:"identifier"`

View File

@ -427,6 +427,10 @@ input VerifyOTPRequest {
otp: String! otp: String!
} }
input ResendOTPRequest {
email: String!
}
type Mutation { type Mutation {
signup(params: SignUpInput!): AuthResponse! signup(params: SignUpInput!): AuthResponse!
login(params: LoginInput!): AuthResponse! login(params: LoginInput!): AuthResponse!
@ -439,6 +443,7 @@ type Mutation {
reset_password(params: ResetPasswordInput!): Response! reset_password(params: ResetPasswordInput!): Response!
revoke(params: OAuthRevokeInput!): Response! revoke(params: OAuthRevokeInput!): Response!
verify_otp(params: VerifyOTPRequest!): AuthResponse! verify_otp(params: VerifyOTPRequest!): AuthResponse!
resend_otp(params: ResendOTPRequest!): Response!
# admin only apis # admin only apis
_delete_user(params: DeleteUserInput!): Response! _delete_user(params: DeleteUserInput!): Response!
_update_user(params: UpdateUserInput!): User! _update_user(params: UpdateUserInput!): User!

View File

@ -55,6 +55,10 @@ func (r *mutationResolver) VerifyOtp(ctx context.Context, params model.VerifyOTP
return resolvers.VerifyOtpResolver(ctx, params) return resolvers.VerifyOtpResolver(ctx, params)
} }
func (r *mutationResolver) ResendOtp(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) {
return resolvers.ResendOTPResolver(ctx, params)
}
func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) { func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) {
return resolvers.DeleteUserResolver(ctx, params) return resolvers.DeleteUserResolver(ctx, params)
} }

View File

@ -99,6 +99,12 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
} }
if refs.BoolValue(user.IsMultiFactorAuthEnabled) { if refs.BoolValue(user.IsMultiFactorAuthEnabled) {
//TODO - send email based on email config
db.Provider.UpsertOTP(ctx, &models.OTP{
Email: user.Email,
Otp: utils.GenerateOTP(),
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
})
return &model.AuthResponse{ return &model.AuthResponse{
Message: "Please check the OTP in your inbox", Message: "Please check the OTP in your inbox",
ShouldShowOtpScreen: refs.NewBoolRef(true), ShouldShowOtpScreen: refs.NewBoolRef(true),

View File

@ -0,0 +1,59 @@
package resolvers
import (
"context"
"fmt"
"strings"
"time"
log "github.com/sirupsen/logrus"
"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/refs"
"github.com/authorizerdev/authorizer/server/utils"
)
// ResendOTPResolver is a resolver for resend otp mutation
func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) {
var res *model.Response
log := log.WithFields(log.Fields{
"email": params.Email,
})
params.Email = strings.ToLower(params.Email)
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
if err != nil {
log.Debug("Failed to get user by email: ", err)
return res, fmt.Errorf(`user with this email not found`)
}
if user.RevokedTimestamp != nil {
log.Debug("User access is revoked")
return res, fmt.Errorf(`user access has been revoked`)
}
if user.EmailVerifiedAt == nil {
log.Debug("User email is not verified")
return res, fmt.Errorf(`email not verified`)
}
if !refs.BoolValue(user.IsMultiFactorAuthEnabled) {
log.Debug("User multi factor authentication is not enabled")
return res, fmt.Errorf(`multi factor authentication not enabled`)
}
//TODO - send email based on email config
db.Provider.UpsertOTP(ctx, &models.OTP{
Email: user.Email,
Otp: utils.GenerateOTP(),
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
})
res = &model.Response{
Message: `OTP has been sent. Please check your inbox`,
}
return res, nil
}

View File

@ -32,11 +32,16 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
return res, fmt.Errorf(`invalid email: %s`, err.Error()) return res, fmt.Errorf(`invalid email: %s`, err.Error())
} }
if params.Otp != otp.Otp {
log.Debug("Failed to verify otp request: Incorrect value")
return res, fmt.Errorf(`invalid otp`)
}
expiresIn := otp.ExpiresAt - time.Now().Unix() expiresIn := otp.ExpiresAt - time.Now().Unix()
if params.Otp != otp.Otp || expiresIn < 0 { if expiresIn < 0 {
log.Debug("Failed to verify otp request: ", err) log.Debug("Failed to verify otp request: Timeout")
return res, fmt.Errorf(`invalid otp: %s`, err.Error()) return res, fmt.Errorf("otp expired")
} }
user, err := db.Provider.GetUserByEmail(ctx, params.Email) user, err := db.Provider.GetUserByEmail(ctx, params.Email)