# TamaBox-v4 P0/P1 修复报告(2026-09-01) 第三轮审计的全部 P0×2 + P1×6 已修复,并在验证过程中额外发现并修复了一处 被 webp 屏障遮蔽的**隐藏编译回归**(见「额外发现」)。全模块构建/vet/测试全绿。 ## 🔴 P0 修复 ### P0-1 profile.go 导出函数编译错误 - `route/user/profile.go`:`personalData` 是 `[][]interface{}`,原代码把 `interface{}` 直接传给 `sanitizeCell(string)` 导致编译失败。 - 改为逐单元格类型断言:字符串净化防公式注入,非字符串(`time.Time` 等)原样写入。 ### P0-2 history-template 复合游标未同步(翻页损坏) - 采用更彻底的方案:`route/question/page.go` 的 `ListAPI` 响应改为 `{data: [...], next_cursor: "..."}`,由**服务端直接下发** `EncodePinCursor` 编码的复合游标。 - 前端 JS 不再用 `new Date().getTime()*1e6` 自行拼游标——JS 双精度浮点无法精确表示纳秒级 UnixNano(毫秒以下精度丢失),时间戳相同的提问会在翻页边界被跳过。 - JS 层已适配 `ctx.JSON` 的统一包装 `{code, data, message}`(内层才是分页负载)。 ## 🟠 P1 修复 ### P1-1 upload_images.go 级联删除查询不存在的列 - `DeleteByQuestionID` 重写:先查 `upload_image_questions` 关联行拿 imageID, 再事务内软删 `UploadImage` 主体并删除关联行(原代码直接在错误表上 `WHERE question_id`)。 ### P1-2 conversation.go 重复删除二次回退配额 - `MarkDeletedByOwner` 增加幂等守卫:`conv.IsDeletedByOwner == true` 直接返回, 不再重复 `IncrementQuota(-1)`。 ### P1-3 questions.go 非 PinFirst 游标 PG 报错 + ASC 方向反 - 游标改用 `strconv.ParseUint` 校验(原 `id < ?` 传 string,PG 下 `integer < text` 无操作符)。 - 排序方向规范化提前,ASC 用 `id > ?`、DESC 用 `id < ?`;解析失败忽略游标(与 PinFirst 一致)。 ### P1-4 home.html 供应链 XSS - 远程公告改 `x-text` 纯文本渲染,移除 `x-html`;meta 行与正文拆成两个元素分别渲染。 ### P1-5 tracing span 泄露 query string - span 名从 `RequestURI` 改为 `URL.Path`,`?t=`、`?code=` 等不再落入 trace。 ### P1-6 password.go(第一轮遗留项) - legacy HMAC-SHA1 比较改用 `crypto/subtle.ConstantTimeCompare`(常量时间,防时序侧信道)。 - `encodePasswordBcrypt` 失败不再静默降级为 HMAC-SHA1 弱哈希:密码超 72 字节按 bcrypt 原生语义截断;bcrypt 生成失败记日志并返回空串(账号校验失败比弱哈希安全,且 `users.go:390` 的 `newHash != ""` 守卫保证空串不会被写库)。 ## ⚠️ 额外发现:internal/route 隐藏编译回归(P0 级) P1-8 批次(autoban 重构)引入、一直被 webp 屏障遮蔽的编译错误,本次通过 `go build -overlay` 全模块类型检查暴露: - `internal/route/route.go`:使用 `autoban` / `mail` / `shared` 三个标识符但缺少 import; - `internal/route/autoban.go`:`autoban.Autoban` 类型不存在,应为 `autoban.Banner`。 **若不修复,Linux 上的完整构建同样会失败。** 两处已修复。 ## 验证方式(重要) Windows 沙箱缺 libwebp,`internal/storage` 及其依赖包无法正常编译,导致其中的类型错误 (P0-1、internal/route 回归)在常规 `go build` 下被遮蔽。本次引入 **overlay 桩验证法**: - `dev/webpstub/`:chai2010/webp 的签名兼容桩(仅 `Encode`/`Options`),保留在仓库供复用; - `go build -overlay=<临时 overlay.json> ./route/... ./internal/... .` 将 `internal/storage/s3.go` 的 import 临时替换为桩包,实现全模块完整类型检查。 验证结果: - 全模块 `go build`(overlay)✅ - 全模块 `go vet`(overlay)✅ - 全部可运行测试通过(templates/form/i18n/cache/autoban/censor 等,`go test` sweep)✅ - 含 `TestTemplatesParse` / `TestRenderPublicQuestionList` / `TestRenderPublicQuestionItem` / `TestRenderUserQuestionList` / `TestTemplateCrossReferences` - `internal/db` 测试需 `DB_TYPE` 环境变量 + 真实数据库,属既有环境限制,非回归。 ## 待办提醒 1. **Linux/CI 环境跑一次 `go build ./...` + `go test ./...` 最终确认**(overlay 桩只覆盖类型检查, webp CGO 真实编译仍需 libwebp 环境)。 2. P2 9 项(mail header、上传后缀白名单、孤儿文件、dbutil pageSize 上限等)尚未处理。