add email verification
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/mayswind/ezbookkeeping/pkg/log"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/services"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||
)
|
||||
|
||||
// AuthorizationsApi represents authorization api
|
||||
@@ -48,6 +49,13 @@ func (a *AuthorizationsApi) AuthorizeHandler(c *core.Context) (interface{}, *err
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if settings.Container.Current.EnableUserForceVerifyEmail && !user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[authorizations.AuthorizeHandler] login failed for user \"%s\", because user has not verified email", credential.LoginName)
|
||||
return nil, errs.NewErrorWithContext(errs.ErrEmailIsNotVerified, map[string]string{
|
||||
"email": user.Email,
|
||||
})
|
||||
}
|
||||
|
||||
err = a.users.UpdateUserLastLoginTime(c, user.Uid)
|
||||
|
||||
if err != nil {
|
||||
@@ -121,6 +129,16 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeHandler(c *core.Context) (interfac
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.Disabled {
|
||||
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] user \"uid:%d\" is disabled", user.Uid)
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if settings.Container.Current.EnableUserForceVerifyEmail && !user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||
return nil, errs.ErrEmailIsNotVerified
|
||||
}
|
||||
|
||||
oldTokenClaims := c.GetTokenClaims()
|
||||
err = a.tokens.DeleteTokenByClaims(c, oldTokenClaims)
|
||||
|
||||
@@ -173,6 +191,16 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.Disabled {
|
||||
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" is disabled", user.Uid)
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if settings.Container.Current.EnableUserForceVerifyEmail && !user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||
return nil, errs.ErrEmailIsNotVerified
|
||||
}
|
||||
|
||||
err = a.twoFactorAuthorizations.GetAndUseUserTwoFactorRecoveryCode(c, uid, credential.RecoveryCode, user.Salt)
|
||||
|
||||
if err != nil {
|
||||
@@ -205,8 +233,9 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
|
||||
|
||||
func (a *AuthorizationsApi) getAuthResponse(token string, need2FA bool, user *models.User) *models.AuthResponse {
|
||||
return &models.AuthResponse{
|
||||
Token: token,
|
||||
Need2FA: need2FA,
|
||||
User: user.ToUserBasicInfo(),
|
||||
Token: token,
|
||||
Need2FA: need2FA,
|
||||
NeedVerifyEmail: false,
|
||||
User: user.ToUserBasicInfo(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/mayswind/ezbookkeeping/pkg/log"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/services"
|
||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||
)
|
||||
|
||||
// ForgetPasswordsApi represents user forget password api
|
||||
@@ -51,7 +52,7 @@ func (a *ForgetPasswordsApi) UserForgetPasswordRequestHandler(c *core.Context) (
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if !user.EmailVerified {
|
||||
if settings.Container.Current.ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[forget_passwords.UserForgetPasswordRequestHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||
return nil, errs.ErrEmailIsNotVerified
|
||||
}
|
||||
@@ -99,7 +100,7 @@ func (a *ForgetPasswordsApi) UserResetPasswordHandler(c *core.Context) (interfac
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if !user.EmailVerified {
|
||||
if settings.Container.Current.ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[forget_passwords.UserResetPasswordHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||
return nil, errs.ErrEmailIsNotVerified
|
||||
}
|
||||
|
||||
+152
-2
@@ -73,8 +73,13 @@ func (a *UsersApi) UserRegisterHandler(c *core.Context) (interface{}, *errs.Erro
|
||||
log.InfofWithRequestId(c, "[users.UserRegisterHandler] user \"%s\" has registered successfully, uid is %d", user.Username, user.Uid)
|
||||
|
||||
authResp := &models.AuthResponse{
|
||||
Need2FA: false,
|
||||
User: user.ToUserBasicInfo(),
|
||||
Need2FA: false,
|
||||
NeedVerifyEmail: settings.Container.Current.EnableUserForceVerifyEmail,
|
||||
User: user.ToUserBasicInfo(),
|
||||
}
|
||||
|
||||
if authResp.NeedVerifyEmail {
|
||||
return authResp, nil
|
||||
}
|
||||
|
||||
token, claims, err := a.tokens.CreateToken(c, user)
|
||||
@@ -93,6 +98,69 @@ func (a *UsersApi) UserRegisterHandler(c *core.Context) (interface{}, *errs.Erro
|
||||
return authResp, nil
|
||||
}
|
||||
|
||||
// UserEmailVerifyHandler sets user email address verified
|
||||
func (a *UsersApi) UserEmailVerifyHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||
var userVerifyEmailReq models.UserVerifyEmailRequest
|
||||
err := c.ShouldBindJSON(&userVerifyEmailReq)
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
user, err := a.users.GetUserById(c, uid)
|
||||
|
||||
if err != nil {
|
||||
if !errs.IsCustomError(err) {
|
||||
log.ErrorfWithRequestId(c, "[users.UserEmailVerifyHandler] failed to get user, because %s", err.Error())
|
||||
}
|
||||
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.Disabled {
|
||||
log.WarnfWithRequestId(c, "[users.UserEmailVerifyHandler] user \"uid:%d\" is disabled", user.Uid)
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[users.UserEmailVerifyHandler] user \"uid:%d\" email has been verified", user.Uid)
|
||||
return nil, errs.ErrEmailIsVerified
|
||||
}
|
||||
|
||||
err = a.users.SetUserEmailVerified(c, user.Username)
|
||||
|
||||
if err != nil {
|
||||
log.ErrorfWithRequestId(c, "[users.UserEmailVerifyHandler] failed to update user \"uid:%d\" email address verified, because %s", user.Uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
err = a.tokens.DeleteTokensByTypeBeforeTime(c, uid, core.USER_TOKEN_TYPE_EMAIL_VERIFY, now)
|
||||
|
||||
if err == nil {
|
||||
log.InfofWithRequestId(c, "[users.UserEmailVerifyHandler] revoke old email verify tokens before unix time \"%d\" for user \"uid:%d\"", now, user.Uid)
|
||||
} else {
|
||||
log.WarnfWithRequestId(c, "[users.UserEmailVerifyHandler] failed to revoke old email verify tokens for user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||
}
|
||||
|
||||
resp := &models.UserVerifyEmailResponse{}
|
||||
|
||||
if userVerifyEmailReq.RequestNewToken {
|
||||
token, claims, err := a.tokens.CreateToken(c, user)
|
||||
|
||||
if err != nil {
|
||||
log.WarnfWithRequestId(c, "[users.UserEmailVerifyHandler] failed to create token for user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
resp.NewToken = token
|
||||
resp.User = user.ToUserBasicInfo()
|
||||
c.SetTextualToken(token)
|
||||
c.SetTokenClaims(claims)
|
||||
|
||||
log.InfofWithRequestId(c, "[users.UserEmailVerifyHandler] user \"uid:%d\" token created, new token will be expired at %d", user.Uid, claims.ExpiresAt)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// UserProfileHandler returns user profile of current user
|
||||
func (a *UsersApi) UserProfileHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||
uid := c.GetCurrentUid()
|
||||
@@ -283,3 +351,85 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (interface{}, *errs
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// UserSendVerifyEmailByUnloginUserHandler sends unlogin user verify email
|
||||
func (a *UsersApi) UserSendVerifyEmailByUnloginUserHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||
var userResendVerifyEmailReq models.UserResendVerifyEmailRequest
|
||||
err := c.ShouldBindJSON(&userResendVerifyEmailReq)
|
||||
|
||||
user, err := a.users.GetUserByEmail(c, userResendVerifyEmailReq.Email)
|
||||
|
||||
if err != nil {
|
||||
if !errs.IsCustomError(err) {
|
||||
log.ErrorfWithRequestId(c, "[users.UserSendVerifyEmailByUnloginUserHandler] failed to get user, because %s", err.Error())
|
||||
}
|
||||
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if !a.users.IsPasswordEqualsUserPassword(userResendVerifyEmailReq.Password, user) {
|
||||
log.WarnfWithRequestId(c, "[users.UserSendVerifyEmailByUnloginUserHandler] request password not equals to the user password")
|
||||
return nil, errs.ErrUserPasswordWrong
|
||||
}
|
||||
|
||||
if user.Disabled {
|
||||
log.WarnfWithRequestId(c, "[users.UserSendVerifyEmailByUnloginUserHandler] user \"uid:%d\" is disabled", user.Uid)
|
||||
return nil, errs.ErrUserIsDisabled
|
||||
}
|
||||
|
||||
if user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[users.UserSendVerifyEmailByUnloginUserHandler] user \"uid:%d\" email has been verified", user.Uid)
|
||||
return nil, errs.ErrEmailIsVerified
|
||||
}
|
||||
|
||||
token, _, err := a.tokens.CreateEmailVerifyToken(c, user)
|
||||
|
||||
if err != nil {
|
||||
log.ErrorfWithRequestId(c, "[users.UserSendVerifyEmailByUnloginUserHandler] failed to create token for user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||
return nil, errs.ErrTokenGenerating
|
||||
}
|
||||
|
||||
err = a.users.SendVerifyEmail(user, token, c.GetClientLocale())
|
||||
|
||||
if err != nil {
|
||||
log.WarnfWithRequestId(c, "[users.UserSendVerifyEmailByUnloginUserHandler] cannot send email to \"%s\", because %s", user.Email, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// UserSendVerifyEmailByLoginedUserHandler sends logined user verify email
|
||||
func (a *UsersApi) UserSendVerifyEmailByLoginedUserHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||
uid := c.GetCurrentUid()
|
||||
user, err := a.users.GetUserById(c, uid)
|
||||
|
||||
if err != nil {
|
||||
if !errs.IsCustomError(err) {
|
||||
log.ErrorfWithRequestId(c, "[users.UserSendVerifyEmailByLoginedUserHandler] failed to get user, because %s", err.Error())
|
||||
}
|
||||
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
if user.EmailVerified {
|
||||
log.WarnfWithRequestId(c, "[users.UserSendVerifyEmailByLoginedUserHandler] user \"uid:%d\" email has been verified", user.Uid)
|
||||
return nil, errs.ErrEmailIsVerified
|
||||
}
|
||||
|
||||
token, _, err := a.tokens.CreateEmailVerifyToken(c, user)
|
||||
|
||||
if err != nil {
|
||||
log.ErrorfWithRequestId(c, "[users.UserSendVerifyEmailByLoginedUserHandler] failed to create token for user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||
return nil, errs.ErrTokenGenerating
|
||||
}
|
||||
|
||||
err = a.users.SendVerifyEmail(user, token, c.GetClientLocale())
|
||||
|
||||
if err != nil {
|
||||
log.WarnfWithRequestId(c, "[users.UserSendVerifyEmailByLoginedUserHandler] cannot send email to \"%s\", because %s", user.Email, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user