安全与可靠性: 修复配额并发、投票事务、密码授权与导出完整性

This commit is contained in:
tamakyi
2026-11-05 12:17:05 +08:00
parent 7636456d4e
commit 25aee35030
18 changed files with 1002 additions and 194 deletions
+24
View File
@@ -7,6 +7,7 @@ package question
import (
"crypto/subtle"
"encoding/json"
"fmt"
"net/http"
"strings"
@@ -101,6 +102,29 @@ func AskStatusAPI(ctx context.Context) error {
return ctx.ServerError()
}
// SEC-06:与 ListAPI(route/question/page.go)对齐,补上 L4 和页面密码检查。
// 否则持有正确问题 token 的请求者可以绕过页面访问边界,取得回答状态、
// 创建时间和前 60 字摘要。
// 两者都返回「用户不存在」以隐藏真实原因(不暴露处置状态与密码设置)。
if level, _, err := db.Restrictions.ActiveLevel(ctx.Request().Context(), owner.ID); err == nil && level == db.RestrictionL4 {
out := make([]askStatusResult, 0, len(req.Items))
for _, it := range req.Items {
out = append(out, askStatusResult{ID: it.ID})
}
return ctx.JSON(map[string]interface{}{"items": out})
}
if owner.PagePassword != "" && !(ctx.IsLogged && ctx.User.ID == owner.ID) {
passKey := fmt.Sprintf("page_pass_%d", owner.ID)
sessionVer, _ := ctx.Session.Get(passKey).(uint)
if sessionVer != owner.PagePasswordVer {
out := make([]askStatusResult, 0, len(req.Items))
for _, it := range req.Items {
out = append(out, askStatusResult{ID: it.ID})
}
return ctx.JSON(map[string]interface{}{"items": out})
}
}
// 收集合法 ID 并一次查回(IN 查询,避免逐条 N+1)。
ids := make([]uint, 0, len(req.Items))
for _, it := range req.Items {