# 第三轮审计整改 · R3 恢复组(R3-10 / R3-3 / R3-2)改动说明 ## ① 头部 | 项 | 值 | |---|---| | 对照网址 | http://39.97.59.228:8013/hrx/mky-vent-base/compare/master...fix/audit-r3-20260921 | | 依据文档 | `代码审核-第三轮-mky-vent-base-20260921.md`(该报告 A 组 A-1/A-2/A-3,对应本文档 R3-2/R3-3/R3-10) | | 分支 | `fix/audit-r3-20260921`(本组原施工分支 `fix/audit-r3-restore-20260921`,已按提交 cherry-pick 汇入最终分支) | | 基线 | `upstream/master` = `4e311cb6`(behind=0,分支起点) | | 日期 | 2026-09-21(Asia/Shanghai) | | 交付版本 | `fix/audit-r3-20260921`(7 个提交:bug 组 3 + 恢复组 4) | | 状态 | 已推 fork(`origin` = lizuo/mky-vent-base);**未推 upstream、未推 master、未部署**,待人工审核 | > **总原则**:本分支只恢复「地址配置化 / 凭据外置」两类**形态**,**不动自动登录/免密流程**。 > 恢复来源为 09-14 已被人工审核"采纳"、但被团队 `7e9858ec`(回滚 13 文件)/`c913dbf9` 回退的 > `4b94efbd`、`dd5e7d80`、`8f87ade5` 三个提交的内容。 > 红线文件 `src/hooks/vent/useAutoLogin.ts`、`src/router/guard/permissionGuard.ts`、`src/store/modules/user.ts` > 及 `fireBD.vue`/`fire-green.vue` 的 `?mock-login=1` 链接**均未改动**(`git diff` 可证)。 ## ② 提交清单 | # | 标题 | |---|---| | 1 | [Fix R3-10] 恢复 /modelreq 相对路径与 glob.wsUrl(去硬编码 IP:端口) | | 2 | [Fix R3-3] autoLoginToken 回空值(凭据外置,部署注入) | | 3 | [Fix R3-2] .env 删除 mock 免密凭据默认值(外置部署注入) | | 4 | [Docs] 第三轮审计 R3 恢复组改动说明 | > **只列提交标题、不写死 hash**:本文件的这几条提交在汇入最终分支时被 cherry-pick,hash 会变 > (旧稿写死的 3 个施工提交 hash 在最终分支上已不可达)。**hash 一律以本分支 `git log --oneline` 为准。** ## ③ 改动面 7 个代码文件 + 本说明(`git diff --stat` 实测:35 插入 / 13 删除): | 文件 | 改动 | |---|---| | `public/mxcad/mxServerConfig.json` | `saveDwgUrl` 硬编码 IP:端口 → 站点相对路径 `/modelreq/...`;`?saveDwgUrl` 说明注释写清来历 | | `src/views/vent/home/configurable/configurable.data.ts` | 3 处 mp4 `link`(mainFan/fanLocal/gate)硬编码 IP:端口 → 相对路径,各加说明注释 | | `src/layouts/default/header/components/VoiceBroadcast.vue` | WS 端点恢复读 `glob.wsUrl` + 加固(见 ④-3) | | `src/layouts/default/header/components/VoiceBroadcastGsd.vue` | 同上 | | `public/fileEdit.html` | OnlyOffice `api.js` 硬编码公网地址 → 运行时配置 `onlyOfficeUrl` 下发(见 ⑦-1) | | `public/js/config.js` | `autoLoginToken: 'MTIzNDU2'` → `''`(空 = 不携带该头) | | `.env` | 删除 `VITE_MOCK_LOGIN_USERNAME/PASSWORD_CHAR_CODE` 两个 mock 免密凭据键(原值 autoAdmin/autoAdmin123) | ## ④ 逐项说明 ### R3-10 硬编码地址回退(恢复 4b94efbd) 1. **mxServerConfig.json / configurable.data.ts(4 处)** - 原行为:CAD 转 DWG 地址与 3 个看板视频写死旧云环境 `IP:8092`,换部署环境必须改代码。 - 现行为:恢复为站点相对路径 `/modelreq/...`,同源经 nginx `/modelreq` 反代至网关(团队既有部署约定)。 - 为什么:该改动 09-14 人工审核已采纳,被 `7e9858ec` 一并回退;属"敏感信息硬编码"口径。 - 差别:仅地址形态变化,无逻辑变化。 2. **fileEdit.html(见 ⑦-1,超出 4 文件清单)**:同上原则,恢复运行时配置下发。 3. **VoiceBroadcast.vue / VoiceBroadcastGsd.vue(加固点)** - 原行为(回退后):`'http://' + hostname + ':9999'?.replace('https://','wss://').replace('http://','ws://') + ...`。 这里 `?.` 优先级使 replace 只作用于 `':9999'` 字面量,返回仍是 `':9999'`——**协议改写从未生效**, 实际拼出的是 `http://:9999/websocket/...`(WS 构造器收到 http 协议头,行为依赖浏览器容错)。 - 现行为:恢复 `useGlobSetting().wsUrl`(`public/js/config.js` 单点配置,当前值 `window.location.origin + '/modelreq'`),并把 `https://→wss://`、`http://→ws://` 替换**锚定在完整 URL 的协议头** (`/ ^https:\/\//`、`/^http:\/\//`,避免误改 URL 体内出现的 "http://" 子串); `glob.wsUrl` 缺失时回退 `window.location.origin + '/modelreq'`(协议取自 `location.protocol`, replace 后即正确推导 ws/wss)。 - 为什么:既恢复运行期配置(去 :9999 硬编码直连),又修复从未生效的协议改写。 - 差别:WS 端点由"网关端口 http 直连"变为"同源 /modelreq 反代(wss)"。前提:nginx 已把 `/modelreq` 的 WS 升级到网关——与 `config.js` 里 `wsUrl` 的既有约定一致,非新引入依赖。 ### R3-3 autoLoginToken 回空值(撤销 c913dbf9,恢复 dd5e7d80) - 原行为:`c913dbf9` 在仓库里写死 `autoLoginToken: 'MTIzNDU2'`(=123456,公开弱票据), 且部署 6 条 `config.js` 补丁不含该键 → 生产永远携带该弱票据。 - 现行为:回 `''`。`src/api/sys/user.ts:76` 已实现 `headers: VUE_APP_URL.autoLoginToken ? { token: ... } : {}`——**空 = 不携带该头**, 服务端按"未配置自动登录令牌"明确拒绝(fail-closed)。 - 为什么:`autoLoginToken` 是**可选语义**——空值即不携带该头,**不能改成强制登录**; 凭据应由部署环境注入(与服务端 `SDJT_AUTO_LOGIN_TOKEN` 配套),**不应在仓库写死默认值**。 - 差别:仅凭据形态(仓库内无默认票据)。**未改动** `src/api/sys/user.ts` 的读取逻辑与任何免密流程。 ### R3-2 .env mock 免密凭据外置(恢复 8f87ade5 做法) - 原行为:`.env` 里 `VITE_MOCK_LOGIN_USERNAME_CHAR_CODE/PASSWORD_CHAR_CODE` = autoAdmin/autoAdmin123, 随构建注入产物(`.env` 的 `VITE_*` 必进 dist)。 - 现行为:删除两个键(8f87ade5 的原始做法即删键;已验证删键不破坏构建)。 缺失时 `src/store/constant.ts` → `fromEnvCharCodes(undefined)` → 返回 `''`,**不抛错**。 - 为什么:mock 免密凭据属"前端硬编码敏感信息"口径(§7.2 口径 1 明确"凭据仍按口径 1 审"), 流程本身不审(冻结项)。 - 差别:仅删凭据默认值;`user.ts`/`permissionGuard.ts` 代码一行未动。 ## ⑤ 验收证据 1. **WS URL 拼接逻辑实测**(node 复现改后代码,4 个用例全对): - `glob.wsUrl='http://a.b/modelreq'` → `ws://a.b/modelreq/websocket/u1` ✅ - `glob.wsUrl='https://a.b/modelreq'` → `wss://a.b/modelreq/websocket/u1` ✅ - 缺失 + `http:` → `ws://a.b/modelreq/websocket/u1` ✅(回退推导正确) - 缺失 + `https:` → `wss://a.b/modelreq/websocket/u1` ✅ 2. **`public/js/config.js` 的 `wsUrl` 键确认存在**:`grep -n wsUrl public/js/config.js` → 第 4 行 `wsUrl: window.location.origin + '/modelreq'`(`types/global.d.ts:8` 类型声明、`src/hooks/setting/index.ts:87` 读取均在)。 3. **`.env` 空值安全性验证结论(R3-2 前置验证,全部通过)**: - `src/store/constant.ts:3-4` 经 `fromEnvCharCodes` 读取,其实现(`src/utils/env.ts`)首行 `if (!charCodeStr) return '';`——**缺失/空串安全,返回空串,不抛错**。 - 使用点全量排查(`grep -rn "MOCK_LOGIN_UESRNAME\|MOCK_LOGIN_PASSWORD" src/`): `user.ts:93`(`getIsMockLogin`,空串与真实用户名比对恒 false,无副作用)、 `user.ts:378-379`(`mockLogin` 参数,空串 → 免密请求带空凭据被服务端拒绝 = 预期行为)、 `CADModal.vue` 两处均已注释掉。`build/`、`vite.config.ts` **无**对这两个键的强制校验。 - 除"凭据为空导致免密请求失败"外**无**其它行为变化:无类型错误(参数声明即 `string | undefined` 兼容)、 无构建失败、无 NPE(`undefined === ''` 为 false)。 - 残余理论边角:`getIsMockLogin` 在"服务端返回的用户名恰为空串"时恒真,进而 401 时触发 `redoMockLogin` 重试—— 前提是真实用户名不可能为空串,判定为可接受风险,仅记录。 4. **红线核对**:`git diff 4e311cb6..HEAD --name-only` 不含 `useAutoLogin.ts`/`permissionGuard.ts`/`user.ts`/ `fireBD.vue`/`fire-green.vue`/`tools/`。 ## ⑥ 静态检查 ``` # Babel 语法检查(worktree node_modules 软链,@babel/parser 走 .pnpm 路径) node -e "...parse(VoiceBroadcast.vue / VoiceBroadcastGsd.vue script / configurable.data.ts)..." → OK × 3 node --check public/js/config.js → config.js syntax OK node -e "JSON.parse(...mxServerConfig.json)" → JSON OK(该文件 "?key" 注释风格键名是合法 JSON 键,可严格解析) # 残留复核(必须零命中) grep -rn "182\.92\.126\.35\|47\.94\.222\.6" src public → 0 命中(exit 1) grep -rn ":9999" src/layouts → 0 命中(exit 1) ``` 说明:改动处的说明注释**刻意不写 IP/端口字面量**(原值在 git 历史 4b94efbd/7e9858ec 可查), 以保证"残留 grep 零命中"这一验收口径本身可作为持续检查手段。未跑构建(按任务要求)。 ## ⑦ 已知取舍 1. **`public/fileEdit.html` 超出任务所列 4 文件清单**:任务验收要求"残留 grep 零命中", 而 `fileEdit.html` 的 `47.94.222.6:9050` 同属 `7e9858ec` 回退的 R3-10 范畴(`4b94efbd` 已含该文件), 故一并恢复并在本节显式声明;如审核认为应拆分,可单独 revert「[Fix R3-10] 恢复 /modelreq 相对路径与 glob.wsUrl」那个提交中的该文件。 2. **部署注入由父方处理**:8092 的 6 条 `config.js` 补丁扩为 7 条(含 `autoLoginToken`)由父方在 `tools/deploy/lib.sh` 完成,本分支未触碰 `tools/`。 3. **免密/自动登录流程未动**:`?mock-login=1` 链接、`useAutoLogin.ts`、`permissionGuard.ts`、`user.ts` 保持仓库现状;本分支只恢复"地址/凭据形态"。 4. 说明注释中"原硬编码值"一律指向 git 历史而非直接书写,便于 grep 口径持续生效。 5. **同文件另有两处硬编码地址,本轮未动(已立案、下一批处理)**:`public/fileEdit.html:24` 的 `document.url` 与 `:38` 的 `callbackUrl` 仍写死 `http://192.168.187.1:9999/ventanaly-sharefile/fileServer/onlyOffice/{read,save}`。 - 事实:这两处**在基线 `4e311cb6` 就存在**(`git show 4e311cb6:public/fileEdit.html | grep -n 192.168.187.1` 可证), 不是本轮引入;也不属第三轮审计条目 R3-10 的范围(该条目只针对 `api.js` 的 `47.94.222.6:9050`)。 - 为什么不顺手改:它们指向 **sharefile 服务**(不是 Document Server 的 `api.js` 前缀),且该文件含 `[[${id}]]` 模板占位、可能由后端另行渲染——改法需先确认调用链与 OnlyOffice 集成,属"需单独验证的改动",按规矩不夹带。 - 处置:父方在 8092 **产物验收**中发现并立案(`tools/verify/第三轮-独立复核与交叉检索-20260921.md` P-13), 建议下一批与构建配置类改动(如 `VITE_PROXY` 内联,见 P-12)一并施工。 6. **⚠️ R3-10 的 3 处 mp4 修复在现网"不改变行为"(2026-09-21 于 88 实测)**:首页背景视频的**实际生效地址来自后端数据**,不是本文件: ``` GET /modelreq/safety/configurationData/getConfigurationDataList?pageType=vent_182_realtime → background.link = "http://182.92.126.35:8092/modelreq/sys/common/static/webfile/gate.mp4" ``` 即 `configurable.data.ts` 里的这三条只是**默认值**。本分支把默认值改为相对路径(口径 1 的"仓库不留硬编码"目标是达成的), 但**要真正消除旧云地址需更新后端配置数据**(另见 `/modelreq/sys/login` 返回的 `ip/port` 记录、`/monitor/device` 的 `cameras[].addr`)—— 已作为团队问题清单 **Q15** 提出;建议下一批同时给前端加"相对路径规范化"兜底。 证据与截图:`tools/verify/页面验收-第三轮88-20260921.md` §3(P-14)。 ## ⑧ 交付状态与上游同步 - 本组 4 个提交(R3-10 / R3-3 / R3-2 + 本文档)已 cherry-pick 汇入最终分支 `fix/audit-r3-20260921`,并**已推 fork**(`origin` = lizuo/mky-vent-base);**未推 upstream、未推 master**; - 未部署、未触碰生产; - 基线 `4e311cb6` = 当前 `upstream/master`,behind=0; - 待人工审核后由人工决定推送/合并。