i18n: captcha, reset password
This commit is contained in:
parent
4fe79859a9
commit
c9eefcb946
7 changed files with 42 additions and 23 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 2d20892994d041953cecaba1ecc2d8be7abd5a4a
|
Subproject commit 47493d67d7b08192a406f68cf2e9a31a46f37104
|
|
@ -24,6 +24,11 @@ type req struct {
|
||||||
Randstr string `json:"randstr"`
|
Randstr string `json:"randstr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
captchaNotMatch = "CAPTCHA not match."
|
||||||
|
captchaRefresh = "Verification failed, please refresh the page and retry."
|
||||||
|
)
|
||||||
|
|
||||||
// CaptchaRequired 验证请求签名
|
// CaptchaRequired 验证请求签名
|
||||||
func CaptchaRequired(configName string) gin.HandlerFunc {
|
func CaptchaRequired(configName string) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
@ -43,7 +48,7 @@ func CaptchaRequired(configName string) gin.HandlerFunc {
|
||||||
bodyCopy := new(bytes.Buffer)
|
bodyCopy := new(bytes.Buffer)
|
||||||
_, err := io.Copy(bodyCopy, c.Request.Body)
|
_, err := io.Copy(bodyCopy, c.Request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.ParamErr("验证码错误", err))
|
c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -51,7 +56,7 @@ func CaptchaRequired(configName string) gin.HandlerFunc {
|
||||||
bodyData := bodyCopy.Bytes()
|
bodyData := bodyCopy.Bytes()
|
||||||
err = json.Unmarshal(bodyData, &service)
|
err = json.Unmarshal(bodyData, &service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.ParamErr("验证码错误", err))
|
c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -62,7 +67,7 @@ func CaptchaRequired(configName string) gin.HandlerFunc {
|
||||||
captchaID := util.GetSession(c, "captchaID")
|
captchaID := util.GetSession(c, "captchaID")
|
||||||
util.DeleteSession(c, "captchaID")
|
util.DeleteSession(c, "captchaID")
|
||||||
if captchaID == nil || !base64Captcha.VerifyCaptcha(captchaID.(string), service.CaptchaCode) {
|
if captchaID == nil || !base64Captcha.VerifyCaptcha(captchaID.(string), service.CaptchaCode) {
|
||||||
c.JSON(200, serializer.ParamErr("验证码错误", nil))
|
c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -71,15 +76,15 @@ func CaptchaRequired(configName string) gin.HandlerFunc {
|
||||||
case "recaptcha":
|
case "recaptcha":
|
||||||
reCAPTCHA, err := recaptcha.NewReCAPTCHA(options["captcha_ReCaptchaSecret"], recaptcha.V2, 10*time.Second)
|
reCAPTCHA, err := recaptcha.NewReCAPTCHA(options["captcha_ReCaptchaSecret"], recaptcha.V2, 10*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.Log().Warning("reCAPTCHA 验证错误, %s", err)
|
util.Log().Warning("reCAPTCHA verification failed, %s", err)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reCAPTCHA.Verify(service.CaptchaCode)
|
err = reCAPTCHA.Verify(service.CaptchaCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.Log().Warning("reCAPTCHA 验证错误, %s", err)
|
util.Log().Warning("reCAPTCHA verification failed, %s", err)
|
||||||
c.JSON(200, serializer.ParamErr("验证失败,请刷新网页后再次验证", nil))
|
c.JSON(200, serializer.Err(serializer.CodeCaptchaRefreshNeeded, captchaRefresh, nil))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -103,13 +108,13 @@ func CaptchaRequired(configName string) gin.HandlerFunc {
|
||||||
request.UserIp = common.StringPtr(c.ClientIP())
|
request.UserIp = common.StringPtr(c.ClientIP())
|
||||||
response, err := client.DescribeCaptchaResult(request)
|
response, err := client.DescribeCaptchaResult(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.Log().Warning("TCaptcha 验证错误, %s", err)
|
util.Log().Warning("TCaptcha verification failed, %s", err)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if *response.Response.CaptchaCode != int64(1) {
|
if *response.Response.CaptchaCode != int64(1) {
|
||||||
c.JSON(200, serializer.ParamErr("验证失败,请刷新网页后再次验证", nil))
|
c.JSON(200, serializer.Err(serializer.CodeCaptchaRefreshNeeded, captchaRefresh, nil))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ func HashID(IDType int) gin.HandlerFunc {
|
||||||
func IsFunctionEnabled(key string) gin.HandlerFunc {
|
func IsFunctionEnabled(key string) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
if !model.IsTrueVal(model.GetSettingByName(key)) {
|
if !model.IsTrueVal(model.GetSettingByName(key)) {
|
||||||
c.JSON(200, serializer.Err(serializer.CodeNoPermissionErr, "未开启此功能", nil))
|
c.JSON(200, serializer.Err(serializer.CodeFeatureNotEnabled, "This feature is not enabled", nil))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,20 @@ const (
|
||||||
Code2FACodeErr = 40022
|
Code2FACodeErr = 40022
|
||||||
// CodeLoginSessionNotExist 登录会话不存在
|
// CodeLoginSessionNotExist 登录会话不存在
|
||||||
CodeLoginSessionNotExist = 40023
|
CodeLoginSessionNotExist = 40023
|
||||||
|
// CodeInitializeAuthn 无法初始化 WebAuthn
|
||||||
|
CodeInitializeAuthn = 40024
|
||||||
|
// CodeWebAuthnCredentialError WebAuthn 凭证无效
|
||||||
|
CodeWebAuthnCredentialError = 40025
|
||||||
|
// CodeCaptchaError 验证码错误
|
||||||
|
CodeCaptchaError = 40026
|
||||||
|
// CodeCaptchaRefreshNeeded 验证码需要刷新
|
||||||
|
CodeCaptchaRefreshNeeded = 40027
|
||||||
|
// CodeFailedSendEmail 邮件发送失败
|
||||||
|
CodeFailedSendEmail = 40028
|
||||||
|
// CodeInvalidTempLink 临时链接无效
|
||||||
|
CodeInvalidTempLink = 40029
|
||||||
|
// CodeTempLinkExpired 临时链接过期
|
||||||
|
CodeTempLinkExpired = 40030
|
||||||
// CodeDBError 数据库操作失败
|
// CodeDBError 数据库操作失败
|
||||||
CodeDBError = 50001
|
CodeDBError = 50001
|
||||||
// CodeEncryptError 加密失败
|
// CodeEncryptError 加密失败
|
||||||
|
|
|
@ -34,7 +34,7 @@ func ParamErrorMsg(filed string, tag string) string {
|
||||||
tagVal, findTag := tagMap[tag]
|
tagVal, findTag := tagMap[tag]
|
||||||
if findTag {
|
if findTag {
|
||||||
// 返回拼接出来的错误信息
|
// 返回拼接出来的错误信息
|
||||||
return fieldVal + tagVal
|
return fieldVal + " " + tagVal
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,13 @@ func StartLoginAuthn(c *gin.Context) {
|
||||||
userName := c.Param("username")
|
userName := c.Param("username")
|
||||||
expectedUser, err := model.GetActiveUserByEmail(userName)
|
expectedUser, err := model.GetActiveUserByEmail(userName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.Err(serializer.CodeNotFound, "用户不存在", err))
|
c.JSON(200, serializer.Err(serializer.CodeUserNotFound, "User not exist", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
instance, err := authn.NewAuthnInstance()
|
instance, err := authn.NewAuthnInstance()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.Err(serializer.CodeInternalSetting, "无法初始化Authn", err))
|
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func FinishLoginAuthn(c *gin.Context) {
|
||||||
userName := c.Param("username")
|
userName := c.Param("username")
|
||||||
expectedUser, err := model.GetActiveUserByEmail(userName)
|
expectedUser, err := model.GetActiveUserByEmail(userName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.Err(serializer.CodeCredentialInvalid, "用户邮箱或密码错误", err))
|
c.JSON(200, serializer.Err(serializer.CodeUserNotFound, "User not exist", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,14 +65,14 @@ func FinishLoginAuthn(c *gin.Context) {
|
||||||
|
|
||||||
instance, err := authn.NewAuthnInstance()
|
instance, err := authn.NewAuthnInstance()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.Err(serializer.CodeInternalSetting, "无法初始化Authn", err))
|
c.JSON(200, serializer.Err(serializer.CodeInitializeAuthn, "Cannot initialize authn", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = instance.FinishLogin(expectedUser, sessionData, c.Request)
|
_, err = instance.FinishLogin(expectedUser, sessionData, c.Request)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.Err(serializer.CodeCredentialInvalid, "登录验证失败", err))
|
c.JSON(200, serializer.Err(serializer.CodeWebAuthnCredentialError, "Verification failed", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,24 +37,24 @@ func (service *UserResetService) Reset(c *gin.Context) serializer.Response {
|
||||||
// 取得原始用户ID
|
// 取得原始用户ID
|
||||||
uid, err := hashid.DecodeHashID(service.ID, hashid.UserID)
|
uid, err := hashid.DecodeHashID(service.ID, hashid.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return serializer.Err(serializer.CodeNotFound, "重设链接无效", err)
|
return serializer.Err(serializer.CodeInvalidTempLink, "Invalid link", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查重设会话
|
// 检查重设会话
|
||||||
resetSession, exist := cache.Get(fmt.Sprintf("user_reset_%d", uid))
|
resetSession, exist := cache.Get(fmt.Sprintf("user_reset_%d", uid))
|
||||||
if !exist || resetSession.(string) != service.Secret {
|
if !exist || resetSession.(string) != service.Secret {
|
||||||
return serializer.Err(serializer.CodeNotFound, "链接已过期", err)
|
return serializer.Err(serializer.CodeTempLinkExpired, "Link is expired", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重设用户密码
|
// 重设用户密码
|
||||||
user, err := model.GetActiveUserByID(uid)
|
user, err := model.GetActiveUserByID(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return serializer.Err(serializer.CodeNotFound, "用户不存在", err)
|
return serializer.Err(serializer.CodeUserNotFound, "User not found", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.SetPassword(service.Password)
|
user.SetPassword(service.Password)
|
||||||
if err := user.Update(map[string]interface{}{"password": user.Password}); err != nil {
|
if err := user.Update(map[string]interface{}{"password": user.Password}); err != nil {
|
||||||
return serializer.DBErr("无法重设密码", err)
|
return serializer.DBErr("Failed to reset password", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.Deletes([]string{fmt.Sprintf("%d", uid)}, "user_reset_")
|
cache.Deletes([]string{fmt.Sprintf("%d", uid)}, "user_reset_")
|
||||||
|
@ -67,10 +67,10 @@ func (service *UserResetEmailService) Reset(c *gin.Context) serializer.Response
|
||||||
if user, err := model.GetUserByEmail(service.UserName); err == nil {
|
if user, err := model.GetUserByEmail(service.UserName); err == nil {
|
||||||
|
|
||||||
if user.Status == model.Baned || user.Status == model.OveruseBaned {
|
if user.Status == model.Baned || user.Status == model.OveruseBaned {
|
||||||
return serializer.Err(403, "该账号已被封禁", nil)
|
return serializer.Err(serializer.CodeUserBaned, "This user is banned", nil)
|
||||||
}
|
}
|
||||||
if user.Status == model.NotActivicated {
|
if user.Status == model.NotActivicated {
|
||||||
return serializer.Err(403, "该账号未激活", nil)
|
return serializer.Err(serializer.CodeUserNotActivated, "This user is not activated", nil)
|
||||||
}
|
}
|
||||||
// 创建密码重设会话
|
// 创建密码重设会话
|
||||||
secret := util.RandStringRunes(32)
|
secret := util.RandStringRunes(32)
|
||||||
|
@ -87,7 +87,7 @@ func (service *UserResetEmailService) Reset(c *gin.Context) serializer.Response
|
||||||
// 发送密码重设邮件
|
// 发送密码重设邮件
|
||||||
title, body := email.NewResetEmail(user.Nick, finalURL.String())
|
title, body := email.NewResetEmail(user.Nick, finalURL.String())
|
||||||
if err := email.Send(user.Email, title, body); err != nil {
|
if err := email.Send(user.Email, title, body); err != nil {
|
||||||
return serializer.Err(serializer.CodeInternalSetting, "无法发送密码重设邮件", err)
|
return serializer.Err(serializer.CodeFailedSendEmail, "Failed to send email", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue