Skip to content

Commit

Permalink
fix cannot build docker image when using gitea action
Browse files Browse the repository at this point in the history
  • Loading branch information
mayswind committed Sep 4, 2023
1 parent c38b277 commit 3505ec5
Show file tree
Hide file tree
Showing 35 changed files with 931 additions and 35 deletions.
33 changes: 33 additions & 0 deletions cmd/user_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ var UserData = &cli.Command{
},
},
},
{
Name: "user-resend-verify-email",
Usage: "Resend user verify email",
Action: resendUserVerifyEmail,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "username",
Aliases: []string{"n"},
Required: true,
Usage: "Specific user name",
},
},
},
{
Name: "user-set-email-verified",
Usage: "Set user email address verified",
Expand Down Expand Up @@ -364,6 +377,26 @@ func disableUser(c *cli.Context) error {
return nil
}

func resendUserVerifyEmail(c *cli.Context) error {
_, err := initializeSystem(c)

if err != nil {
return err
}

username := c.String("username")
err = clis.UserData.ResendVerifyEmail(c, username)

if err != nil {
log.BootErrorf("[user_data.resendUserVerifyEmail] error occurs when resending user verify email")
return err
}

log.BootInfof("[user_data.resendUserVerifyEmail] verify email for user \"%s\" has been resent", username)

return nil
}

func setUserEmailVerified(c *cli.Context) error {
_, err := initializeSystem(c)

Expand Down
14 changes: 14 additions & 0 deletions cmd/webserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,16 @@ func startWebServer(c *cli.Context) error {
apiRoute.POST("/register.json", bindApiWithTokenUpdate(api.Users.UserRegisterHandler, config))
}

if config.EnableUserVerifyEmail {
apiRoute.POST("/verify_email/resend.json", bindApi(api.Users.UserSendVerifyEmailByUnloginUserHandler))

emailVerifyRoute := apiRoute.Group("/verify_email")
emailVerifyRoute.Use(bindMiddleware(middlewares.JWTEmailVerifyAuthorization))
{
emailVerifyRoute.POST("/by_token.json", bindApi(api.Users.UserEmailVerifyHandler))
}
}

if config.EnableUserForgetPassword {
apiRoute.POST("/forget_password/request.json", bindApi(api.ForgetPasswords.UserForgetPasswordRequestHandler))

Expand All @@ -226,6 +236,10 @@ func startWebServer(c *cli.Context) error {
apiV1Route.GET("/users/profile/get.json", bindApi(api.Users.UserProfileHandler))
apiV1Route.POST("/users/profile/update.json", bindApiWithTokenUpdate(api.Users.UserUpdateProfileHandler, config))

if config.EnableUserVerifyEmail {
apiV1Route.POST("/users/verify_email/resend.json", bindApi(api.Users.UserSendVerifyEmailByLoginedUserHandler))
}

// Two Factor Authorization
if config.EnableTwoFactor {
apiV1Route.GET("/users/2fa/status.json", bindApi(api.TwoFactorAuthorizations.TwoFactorStatusHandler))
Expand Down
12 changes: 12 additions & 0 deletions conf/ezbookkeeping.ini
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ token_expired_time = 2592000
# Temporary token expired seconds (0 - 4294967295), default is 300 (5 minutes)
temporary_token_expired_time = 300

# Email verify token expired seconds (0 - 4294967295), default is 3600 (60 minutes)
email_verify_token_expired_time = 3600

# Password reset token expired seconds (0 - 4294967295), default is 3600 (60 minutes)
password_reset_token_expired_time = 3600

Expand All @@ -122,9 +125,18 @@ request_id_header = true
# Set to true to allow users to register account by themselves
enable_register = true

# Set to true to allow users to verify email address
enable_email_verify = false

# Set to true to require email must be verified when login
enable_force_email_verify = false

# Set to true to allow users to reset password
enable_forget_password = true

# Set to true to require email must be verified when use forget password
forget_password_require_email_verify = false

# User avatar provider, supports the following types:
# "gravatar": https://gravatar.com
# Leave blank if you want to disable user avatar
Expand Down
35 changes: 32 additions & 3 deletions pkg/api/authorizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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(),
}
}
5 changes: 3 additions & 2 deletions pkg/api/forget_passwords.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
154 changes: 152 additions & 2 deletions pkg/api/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand Down Expand Up @@ -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
}
Loading

0 comments on commit 3505ec5

Please sign in to comment.