质量优化

This commit is contained in:
ryan
2026-06-10 13:42:15 +08:00
parent 3ed4dec4a3
commit 57944398e6
27 changed files with 155 additions and 111 deletions
+10 -2
View File
@@ -118,7 +118,11 @@ func getSQLiteOverview(gormDB *gorm.DB) (DBOverviewResponse, error) {
var sizeStr string
if fi, err := os.Stat(name); err == nil {
sizeStr = formatBytes(uint64(fi.Size()))
size := fi.Size()
if size < 0 {
size = 0
}
sizeStr = formatBytes(uint64(size))
} else {
sizeStr = "0 B"
}
@@ -160,7 +164,11 @@ func getPostgresOverview(gormDB *gorm.DB) (DBOverviewResponse, error) {
var sizeStr string
var sizeBytes sql.NullInt64
if err := gormDB.Raw("SELECT pg_database_size(current_database())").Scan(&sizeBytes).Error; err == nil && sizeBytes.Valid {
sizeStr = formatBytes(uint64(sizeBytes.Int64))
size := sizeBytes.Int64
if size < 0 {
size = 0
}
sizeStr = formatBytes(uint64(size))
} else {
sizeStr = "0 B"
}
+7 -4
View File
@@ -147,9 +147,12 @@ func GetSystemStatus(c *gin.Context) {
numGoroutine := runtime.NumGoroutine()
var lastGCTime string
if m.LastGC > 0 {
switch {
case m.LastGC > 0 && m.LastGC <= math.MaxInt64:
lastGCTime = formatDuration(time.Since(time.Unix(0, int64(m.LastGC))))
} else {
case m.LastGC > 0:
lastGCTime = "未知"
default:
lastGCTime = "无"
}
@@ -286,7 +289,7 @@ func exportSQLite(c *gin.Context) {
path = "./data/wavelet.db"
}
f, err := os.Open(path)
f, err := os.Open(path) //nolint:gosec // path is loaded from server startup configuration, not user input
if err != nil {
c.JSON(http.StatusInternalServerError, util.Err("无法打开数据库文件: "+err.Error()))
return
@@ -329,7 +332,7 @@ func exportPostgres(c *gin.Context) {
dbCfg.Database,
}
cmd := exec.CommandContext(c.Request.Context(), pgDumpPath, args...)
cmd := exec.CommandContext(c.Request.Context(), pgDumpPath, args...) //nolint:gosec // pgDumpPath is a looked up command path, args are from database configuration
if dbCfg.Password != "" {
cmd.Env = append(os.Environ(), "PGPASSWORD="+dbCfg.Password)
} else {
+1 -1
View File
@@ -275,7 +275,7 @@ func TestSMTP(c *gin.Context) {
<p>If you received this message, your SMTP configuration is correct and mail sending is working properly.</p>
<p>Sent from Wavelet.</p>`
logs, err := mail.SendMailWithLog(cfg, req.To, subject, body)
logs, err := mail.SendMailWithLog(c.Request.Context(), cfg, req.To, subject, body)
resp := TestSMTPResponse{
Success: err == nil,
Log: logs,
+1 -1
View File
@@ -14,6 +14,6 @@ const (
deleteUserFailed = "删除用户失败"
usernameExists = "用户名已存在"
usernameRequired = "用户名不能为空"
passwordTooShort = "密码长度不能少于 8 位"
passwordTooShort = "密码长度不能少于 8 位" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
createUserFailed = "创建用户失败"
)
+2 -2
View File
@@ -5,6 +5,6 @@
package cap
const (
errCapTokenMissing = "验证码验证失败,缺少验证码凭证"
errCapTokenInvalidOrExpired = "验证码校验失败或已过期,请重试"
errCapTokenMissing = "验证码验证失败,缺少验证码凭证" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errCapTokenInvalidOrExpired = "验证码校验失败或已过期,请重试" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
)
+1 -1
View File
@@ -7,7 +7,7 @@ package oauth
// OAuth 认证相关错误消息
const (
InvalidState = "非法登录请求"
IDTokenVerifyFailed = "ID Token 验证失败"
IDTokenVerifyFailed = "ID Token 验证失败" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
IDTokenVerifyFailedFormat = "%s: %w"
NonceMismatch = "nonce 不匹配,可能存在重放攻击"
NoActiveAuthSource = "未配置可用认证源"
+3 -3
View File
@@ -469,7 +469,7 @@ func handleCallbackBind(ctx context.Context, c *gin.Context, source *model.AuthS
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
return
}
if err := model.BindExternalAccount(&model.ExternalAccount{
if err := model.BindExternalAccount(ctx, &model.ExternalAccount{
AuthSourceID: source.ID,
UserID: user.ID,
ExternalID: userInfo.Sub,
@@ -488,7 +488,7 @@ func handleCallbackBind(ctx context.Context, c *gin.Context, source *model.AuthS
func handleCallbackLogin(ctx context.Context, c *gin.Context, source *model.AuthSource, userInfo *model.OAuthUserInfo) {
var user model.User
account, err := model.FindExternalAccount(source.ID, userInfo.Sub)
account, err := model.FindExternalAccount(ctx, source.ID, userInfo.Sub)
switch {
case err == nil:
if err := db.DB(ctx).First(&user, "id = ?", account.UserID).Error; err != nil {
@@ -549,7 +549,7 @@ func handleCallbackRegister(ctx context.Context, c *gin.Context, source *model.A
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
return model.User{}, false
}
if err := model.BindExternalAccount(&model.ExternalAccount{
if err := model.BindExternalAccount(ctx, &model.ExternalAccount{
AuthSourceID: source.ID,
UserID: user.ID,
ExternalID: userInfo.Sub,
+9 -1
View File
@@ -60,6 +60,14 @@ func RiskControlMiddleware() gin.HandlerFunc {
}
}
const maxHTTPStatus = 999
status := c.Writer.Status()
if status < 0 {
status = 0
} else if status > maxHTTPStatus {
status = maxHTTPStatus
}
logItem := &UserAccessLog{
ID: idgen.NextUint64ID(),
UserID: userObj.ID, // 直接从 Context 获取已登录用户ID,避免数据库查询
@@ -68,7 +76,7 @@ func RiskControlMiddleware() gin.HandlerFunc {
IP: c.ClientIP(),
UserAgent: c.Request.UserAgent(),
Headers: headersStr,
Status: int32(c.Writer.Status()),
Status: int32(status),
Latency: latency,
CreatedAt: time.Now(),
}
+1 -1
View File
@@ -499,7 +499,7 @@ func tryInstantUpload(ctx context.Context, c *gin.Context, currUser *model.User,
if err := db.DB(ctx).Create(&newUpload).Error; err != nil {
c.JSON(http.StatusOK, util.Err(ErrSaveUploadRecordFailed))
return true, nil
return true, err
}
logger.InfoF(ctx, "文件触发秒传成功! ID: %d, Path: %s", id, existing.FilePath)
+12 -12
View File
@@ -7,21 +7,21 @@ package user
const (
errBindParamsFailed = "参数绑定失败"
errInvalidParams = "无效的参数"
errPasswordLoginDisabled = "管理员关闭了密码登录"
errUsernameOrPasswordWrong = "用户名或密码错误"
errPasswordLoginDisabled = "管理员关闭了密码登录" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errUsernameOrPasswordWrong = "用户名或密码错误" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errLoginEmailMissing = "该账号未绑定邮箱,请联系管理员绑定邮箱后再登录"
errNeedEmailCodePrefix = "need_email_code:"
errEmailCodeInvalidOrExpired = "验证码错误或已过期"
errPasswordUpgradeFailed = "升级密码安全算法失败,请重试"
errPasswordUpgradeFailed = "升级密码安全算法失败,请重试" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errSaveSessionFailed = "无法保存会话信息,请重试"
errRegistrationDisabled = "管理员关闭了注册"
errPasswordTooShort = "密码长度不能少于 8 位"
errPasswordTooShort = "密码长度不能少于 8 位" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errEmailOrCodeRequired = "邮箱或验证码未填写"
errNewPasswordTooShort = "新密码长度不能少于 8 位"
errNewPasswordTooShort = "新密码长度不能少于 8 位" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errLoginRequired = "请先登录"
errUserNotFound = "未找到该用户"
errOldPasswordIncorrect = "原密码不正确"
errPasswordEncryptFailed = "密码加密失败,请重试"
errOldPasswordIncorrect = "原密码不正确" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errPasswordEncryptFailed = "密码加密失败,请重试" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errEmailRequired = "邮箱地址不能为空"
errUnsupportedEmailScene = "不支持的验证场景"
errEmailAlreadyRegistered = "该邮箱已被注册"
@@ -31,11 +31,11 @@ const (
errRenderEmailTemplateFailed = "渲染验证邮件模板失败:%w"
errGenerateEmailCodeFailed = "生成验证码失败,请重试"
errDispatchEmailTaskFailed = "投递验证邮件发送任务失败,请重试"
errTokenNameRequired = "令牌名称不能为空"
errAccessTokenLimitReached = "已达到访问令牌最大创建数量限制"
errGenerateTokenFailed = "生成令牌失败"
errInvalidTokenID = "无效的令牌ID"
errTokenNotFoundOrForbidden = "令牌不存在或无权操作"
errTokenNameRequired = "令牌名称不能为空" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errAccessTokenLimitReached = "已达到访问令牌最大创建数量限制" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errGenerateTokenFailed = "生成令牌失败" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errInvalidTokenID = "无效的令牌ID" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errTokenNotFoundOrForbidden = "令牌不存在或无权操作" //nolint:gosec // false positive: this is an error message, not hardcoded credentials
errTaskPayloadRequired = "任务参数不能为空"
errInvalidJSONFormat = "无效的 JSON 格式: %w"
errEmailTaskFieldsRequired = "to、subject、body 不能为空"
+13 -9
View File
@@ -28,16 +28,16 @@ type sendEmailCodeRequest struct {
Scene string `json:"scene" binding:"required"`
}
func isEmailLoginVerificationEnabled() bool {
enabled, err := model.GetBoolByKey(context.Background(), model.ConfigKeyEmailLoginVerificationEnabled)
func isEmailLoginVerificationEnabled(ctx context.Context) bool {
enabled, err := model.GetBoolByKey(ctx, model.ConfigKeyEmailLoginVerificationEnabled)
if err != nil {
return false
}
return enabled
}
func isEmailRegisterVerificationEnabled() bool {
enabled, err := model.GetBoolByKey(context.Background(), model.ConfigKeyEmailRegisterVerificationEnabled)
func isEmailRegisterVerificationEnabled(ctx context.Context) bool {
enabled, err := model.GetBoolByKey(ctx, model.ConfigKeyEmailRegisterVerificationEnabled)
if err != nil {
return false
}
@@ -215,7 +215,7 @@ func SendEmailCode(c *gin.Context) {
}
func validateRegisterEmailVerification(ctx context.Context, req *registerRequest) error {
if !isEmailRegisterVerificationEnabled() {
if !isEmailRegisterVerificationEnabled(ctx) {
return nil
}
if req.Email == "" || req.Code == "" {
@@ -228,7 +228,7 @@ func validateRegisterEmailVerification(ctx context.Context, req *registerRequest
}
// completePendingOAuthBinding 完成登录后的 OAuth 待绑定绑定流程
func completePendingOAuthBinding(session sessions.Session, user *model.User) {
func completePendingOAuthBinding(ctx context.Context, session sessions.Session, user *model.User) {
pendingSourceID := session.Get(oauth.PendingOAuthSourceIDKey)
pendingExternalID := session.Get(oauth.PendingOAuthExternalIDKey)
pendingExternalUsername := session.Get(oauth.PendingOAuthExternalUsernameKey)
@@ -243,16 +243,20 @@ func completePendingOAuthBinding(session sessions.Session, user *model.User) {
case uint64:
sourceID = v
case int:
sourceID = uint64(v)
if v >= 0 {
sourceID = uint64(v)
}
case float64:
sourceID = uint64(v)
if v >= 0 && v <= 18446744073709551615.0 {
sourceID = uint64(v)
}
}
externalID, _ := pendingExternalID.(string)
externalUsername, _ := pendingExternalUsername.(string)
email, _ := pendingEmail.(string)
if sourceID != 0 && externalID != "" {
_ = model.BindExternalAccount(&model.ExternalAccount{
_ = model.BindExternalAccount(ctx, &model.ExternalAccount{
AuthSourceID: sourceID,
UserID: user.ID,
ExternalID: externalID,
+2 -2
View File
@@ -114,7 +114,7 @@ func Login(c *gin.Context) {
return
}
if isEmailLoginVerificationEnabled() {
if isEmailLoginVerificationEnabled(ctx) {
if emailErr := handleLoginEmailVerification(ctx, c, &req, &user); emailErr != nil {
return
}
@@ -140,7 +140,7 @@ func Login(c *gin.Context) {
}
// 检查是否有未完成 of OAuth/OIDC 绑定
completePendingOAuthBinding(session, &user)
completePendingOAuthBinding(ctx, session, &user)
c.JSON(http.StatusOK, util.OK(oauth.BuildBasicUserInfo(&user, needChangePassword)))
}
+1 -1
View File
@@ -101,7 +101,7 @@ func (h *SendEmailHandler) Execute(ctx context.Context, payload []byte) (*task.T
task.AppendLog(ctx, "连接 SMTP 服务器: %s:%d, 用户名: %s", smtpHost, smtpPort, smtpUsername)
// 调用 SendMailHTML 执行邮件发送,这里会有 5s 拨号超时和 10s 读写限制
err = mail.SendMailHTML(cfg, req.To, req.Subject, req.Body)
err = mail.SendMailHTML(ctx, cfg, req.To, req.Subject, req.Body)
if err != nil {
task.AppendLog(ctx, "邮件发送失败: %v", err)
return nil, fmt.Errorf(errSendMailFailed, err)