feat: add testing & ui for forgot password with mobile
This commit is contained in:
@@ -6,9 +6,11 @@ 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"
|
||||
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||
@@ -16,18 +18,17 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
// 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)
|
||||
@@ -37,7 +38,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
}
|
||||
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
|
||||
if err != nil {
|
||||
log.Debug("Error getting basic auth disabled: ", err)
|
||||
log.Debug("Error getting email verification disabled: ", err)
|
||||
isEmailVerificationDisabled = true
|
||||
}
|
||||
|
||||
@@ -48,7 +49,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
}
|
||||
isMobileVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
|
||||
if err != nil {
|
||||
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||
log.Debug("Error getting mobile verification disabled: ", err)
|
||||
isMobileVerificationDisabled = true
|
||||
}
|
||||
|
||||
@@ -56,7 +57,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
phoneNumber := refs.StringValue(params.PhoneNumber)
|
||||
if email == "" && phoneNumber == "" {
|
||||
log.Debug("Email or phone number is required")
|
||||
return res, fmt.Errorf(`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),
|
||||
@@ -66,11 +67,11 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
isMobileLogin := phoneNumber != ""
|
||||
if isBasicAuthDisabled && isEmailLogin && !isEmailVerificationDisabled {
|
||||
log.Debug("Basic authentication is disabled.")
|
||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||
return nil, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||
}
|
||||
if isMobileBasicAuthDisabled && isMobileLogin && !isMobileVerificationDisabled {
|
||||
log.Debug("Mobile basic authentication is disabled.")
|
||||
return res, fmt.Errorf(`mobile basic authentication is disabled for this instance`)
|
||||
return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`)
|
||||
}
|
||||
var user *models.User
|
||||
if isEmailLogin {
|
||||
@@ -80,17 +81,17 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user: ", err)
|
||||
return res, fmt.Errorf(`bad user credentials`)
|
||||
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
|
||||
}
|
||||
if user.RevokedTimestamp != nil {
|
||||
log.Debug("User access is revoked")
|
||||
return res, fmt.Errorf(`user access has been revoked`)
|
||||
return nil, fmt.Errorf(`user access has been revoked`)
|
||||
}
|
||||
if isEmailLogin {
|
||||
redirectURI := ""
|
||||
@@ -108,7 +109,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create verification token", err)
|
||||
return res, err
|
||||
return nil, err
|
||||
}
|
||||
_, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{
|
||||
Token: verificationToken,
|
||||
@@ -120,7 +121,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add verification request", err)
|
||||
return res, 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{}{
|
||||
@@ -128,13 +129,42 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
"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
|
||||
}
|
||||
if isMobileLogin {
|
||||
// TODO: send sms
|
||||
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
|
||||
}
|
||||
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`)
|
||||
}
|
||||
|
Reference in New Issue
Block a user