支持使用登录密码作为备用验证完成外部邮箱绑定并更新版本号为V2.10.4
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-10-16 21:36:51 +08:00
parent 6be846da98
commit 16329f3e01
4 changed files with 42 additions and 26 deletions

View File

@ -1100,9 +1100,14 @@ func VerifyExternalEmail(ctx *context.Context, w http.ResponseWriter, req *http.
writeSecurityError(w, response.ParamsError, "不能将当前邮箱绑定为外部安全邮箱")
return
}
if err := runtime.verification.VerifyBound(input.ID, ctx.UserAccount, input.Email, input.Code, verification.PurposeExternalEmailBind, input.BindingID, remoteIP(req)); err != nil {
writeSecurityError(w, response.ParamsError, externalEmailVerificationCheckMessage(err))
return
var u models.User
userFound, _ := db.Instance.ID(ctx.UserID).Get(&u)
passwordMatched := userFound && u.Password != "" && password.Verify(u.Password, strings.TrimSpace(input.Code))
if !passwordMatched {
if err := runtime.verification.VerifyBound(input.ID, ctx.UserAccount, input.Email, input.Code, verification.PurposeExternalEmailBind, input.BindingID, remoteIP(req)); err != nil {
writeSecurityError(w, response.ParamsError, externalEmailVerificationCheckMessage(err))
return
}
}
if err := runtime.external.Verify(ctx.UserID, input.BindingID); err != nil {
writeSecurityError(w, response.ParamsError, "验证失败")
@ -1137,17 +1142,22 @@ func VerifyOwnExternalEmail(ctx *context.Context, w http.ResponseWriter, req *ht
writeSecurityError(w, response.ParamsError, "不能将当前邮箱绑定为外部安全邮箱")
return
}
if err := runtime.verification.VerifyBound(
input.ID,
ctx.UserAccount,
normalizedEmail,
input.Code,
verification.PurposeExternalEmailChange,
input.BindingID,
remoteIP(req),
); err != nil {
writeSecurityError(w, response.ParamsError, externalEmailVerificationCheckMessage(err))
return
var u2 models.User
userFound2, _ := db.Instance.ID(ctx.UserID).Get(&u2)
passwordMatched2 := userFound2 && u2.Password != "" && password.Verify(u2.Password, strings.TrimSpace(input.Code))
if !passwordMatched2 {
if err := runtime.verification.VerifyBound(
input.ID,
ctx.UserAccount,
normalizedEmail,
input.Code,
verification.PurposeExternalEmailChange,
input.BindingID,
remoteIP(req),
); err != nil {
writeSecurityError(w, response.ParamsError, externalEmailVerificationCheckMessage(err))
return
}
}
if err := runtime.external.VerifyReplacement(ctx.UserID, input.BindingID); err != nil {
log.WithContext(ctx).WithError(err).Error("verify own external email replacement failed")

View File

@ -15,6 +15,7 @@ import (
"git.pcux.cn/xuans/Smail/services/externalemail"
"git.pcux.cn/xuans/Smail/services/verification"
"git.pcux.cn/xuans/Smail/utils/context"
"git.pcux.cn/xuans/Smail/utils/password"
log "github.com/sirupsen/logrus"
)
@ -345,17 +346,22 @@ func VerifyManagedExternalEmail(ctx *context.Context, w http.ResponseWriter, req
writeSecurityError(w, response.ParamsError, "不能将当前邮箱绑定为外部安全邮箱")
return
}
if err := runtime.verification.VerifyBound(
input.ChallengeID,
target.Account,
normalizedEmail,
input.Code,
verification.PurposeExternalEmailChange,
input.BindingID,
remoteIP(req),
); err != nil {
writeSecurityError(w, response.ParamsError, externalEmailVerificationCheckMessage(err))
return
var targetUser models.User
targetFound, _ := db.Instance.ID(target.ID).Get(&targetUser)
passwordMatched := targetFound && targetUser.Password != "" && password.Verify(targetUser.Password, strings.TrimSpace(input.Code))
if !passwordMatched {
if err := runtime.verification.VerifyBound(
input.ChallengeID,
target.Account,
normalizedEmail,
input.Code,
verification.PurposeExternalEmailChange,
input.BindingID,
remoteIP(req),
); err != nil {
writeSecurityError(w, response.ParamsError, externalEmailVerificationCheckMessage(err))
return
}
}
if err := runtime.external.VerifyReplacement(target.ID, input.BindingID, accountWriteGuard(ctx, *target)); err != nil {
if writeManagedScopeError(w, err) {

Binary file not shown.

View File

@ -57,7 +57,7 @@
<el-icon><Setting /></el-icon>
<span class="settings-label">{{ lang.settings }}</span>
</div>
<span class="app-version-badge">V2.10.3</span>
<span class="app-version-badge">V2.10.4</span>
</button>
</div>
</div>