From 0daa9782c9144762a23a4d9a06165467f74de5c1 Mon Sep 17 00:00:00 2001 From: Qiufeng Date: Thu, 20 Aug 2026 20:39:25 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E4=BB=A3=E7=A0=81=20review=20=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=EF=BC=88=E4=BF=AE=E5=A4=8D=E9=A1=B9=20+=20=E9=81=97?= =?UTF-8?q?=E7=95=99=E9=A1=B9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/code-review-2026-08-20.md | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/code-review-2026-08-20.md diff --git a/docs/code-review-2026-08-20.md b/docs/code-review-2026-08-20.md new file mode 100644 index 0000000..419625b --- /dev/null +++ b/docs/code-review-2026-08-20.md @@ -0,0 +1,40 @@ +# 代码 Review 记录(2026-08-20,推送 git.awaioi.com 前) + +> 范围:server/(Go)、client/core/(Go)、apps/web(React)、client/ui+desktop(WinUI3/Electron,静态)。 +> 结论:基线全绿(go build/vet/test -race、tsc --noEmit、pnpm build、desktop JS 语法)。本次修复 7 处,均在提交前落地。 + +## 验证基线(全绿) + +- server:`go build ./...` ✓ · `go vet ./...` ✓ · `go test -race ./...` ✓(api/auth/task/ws) +- client/core:`go build/vet/test -race ./...` ✓(device/exec/bilibili/cdp/localserver/vault/wsclient) +- apps/web:`tsc --noEmit` ✓(0 错误)· `pnpm build` ✓(仅 >500KiB chunk 告警,非错误) +- client/desktop:`node --check` 3 文件语法 ✓ + +## 已修复(本次) + +| 级别 | 位置 | 问题 | 修复 | +|---|---|---|---| +| HIGH | server/internal/ws/hub.go | `send on closed channel` panic:连接注销时 `close(send)` 与 `SendToAgent`/广播并发竞态 | Conn 增加 mu+closed 标记,统一经 `sendRaw` 发送并在关闭前检查;加回归测试(含 -race) | +| MED | server/internal/ws/dispatcher.go | 轮询 WHERE 缺括号:`status=? AND schedule_at is null OR schedule_at<=?` 优先级错误 | 显式括号 `(schedule_at is null or schedule_at <= ?)` | +| MED | server/internal/api/handlers/agent.go | 配对码非原子占用:并发可配出多台设备 | 事务内 `UPDATE ... WHERE used=false` 并以 RowsAffected==1 判定占用 | +| MED | server/internal/api/handlers/material.go | 上传无体积上限(磁盘 DoS) | http.MaxBytesReader + 配置 MAX_UPLOAD_BYTES(默认 2GiB) | +| MED | server/internal/ws/hub.go | RegisterAgent 在 hub 锁内做网络 Close | 关闭动作移出锁外;旧连接 ws 关闭加 nil 保护 | +| CRIT | server/internal/config/config.go | JWT_SECRET 默认值可被伪造令牌(admin 提权) | 默认/过短密钥时打印醒目安全告警 | +| LOW | client/core/internal/localserver/localserver.go | token 比较非常数时间 + 支持 URL query 传递 | 仅接受请求头 + subtle.ConstantTimeCompare | + +## 审查确认无问题的关键点 + +- 认证:Argon2id(OWASP 基线参数)+ 常数时间比较;JWT HS256 + 签名方法校验(拒绝 alg 混淆)+ refresh 轮换(Redis jti 吊销)。 +- 密码/保险库:client/core vault 用 AES-256-GCM,随机 nonce、GCM 认证、master.key/vault.enc 0600、目录 0700。 +- 设备握手:Ed25519 hello 验签、坏签名/未知设备/已吊销设备均拒绝。 +- 素材直链:签名 token 一次性 + 10min 过期 + path 前缀校验(storageKey 服务端生成)。 +- 前端:无 dangerouslySetInnerHTML / innerHTML(无 XSS 注入点);401 刷新单飞;WS 重连;登出清理令牌。 +- 任务状态机:转移表完整(草稿→审核→排队→下发→执行→成功/失败→重试/取消/挂起)。 + +## 遗留(低优先级,未阻塞) + +- 前端 JWT 存 localStorage(当下无 XSS 向量可接受;二期可改 httpOnly Cookie)。 +- WSS `InsecureSkipVerify: true`(内网部署 + token 鉴权下可接受;公网需收紧 Origin 校验)。 +- buildPush 每次下发失败会遗留未清理的 TransferToken(10min 过期自愈)。 +- 素材 Delete 先删文件再删库,DB 失败会留悬空行(极小概率)。 +- 前端 bundle 单 chunk >500KiB(可 code-split 优化)。