Files
Nexus/docs/audit/2026-06-01-files-page-inspection.md
T

4.5 KiB
Raw Blame History

审计记录:文件管理页全面巡检(面包屑 + 路径 + 浏览契约)

审计信息

  • 日期: 2026-06-01
  • 审计人: Claude (AI)
  • 触发原因: 用户反馈 #/files 面包屑不可用,要求全面巡检

审计范围(实际改动文件清单)

文件 行数 状态
frontend/src/pages/FilesPage.vue 615 ☑ 已审(全文)
frontend/src/utils/remotePath.ts 72 ☑ 已审(全文)
frontend/src/utils/fileBrowse.ts 51 ☑ 已审(全文)
frontend/src/types/api.ts BrowseResponse 段 ☑ 已审
server/api/sync_v2.py browse_directory L142-216 ☑ 已审

巡检结论摘要

问题 根因 处置
面包屑点击无效 Vuetify 4 不消费 props.onClick #item 槽 + onBreadcrumbClick(index)
路径栏与列表路径不一致 未规范化 //、无尾斜杠 normalizeRemotePath 统一
空目录不显示 items?.length 误判 Array.isArray(body.items)
无法返回上级 列表过滤 .. 工具栏「上级」+ 面包屑
批量删除失败无反馈 catch 统计成功/失败条数

审计8步结果

Step 1: 登记

变更主题:文件管理 SPA 路径导航与 browse API 契约修复。

Step 2: 全文 Read

  • FilesPage.vue:模板 + script 全文 Read
  • remotePath.tsfileBrowse.ts:全文 Read
  • sync_v2.pybrowse_directory 及相邻 file-ops 对照 Read

Step 3: 规则扫描 H

H# 规则 文件:行号 说明
PY-03 SSH 命令拼接 sync_v2.py:166 ls -la + shlex.quote(path) → 扫描
PY-05 JWT sync_v2.py:146 Depends(get_current_admin) → 扫描
PY-09 静默吞错 FilesPage.vue:427-435(改前) 批量删除空 catch → 已改为计数
FE-01 XSS FilesPage.vue:83 {{ item.name }} 文本插值 → 扫描
FE-04 裸 fetch FilesPage.vue 均经 http 封装 → 无命中

Step 4: Closure 表

文件 行号 规则 判定 严重度 理由
sync_v2.py 166 PY-03 SAFE path 经 Pydantic + shlex.quote,不经 shell 拼接用户片段
sync_v2.py 146 PY-05 SAFE JWT 管理员鉴权 + 审计 browse_directory
FilesPage.vue 83 FE-01 SAFE Vue 默认转义;文件名来自 SSH ls 输出
FilesPage.vue 427-438 PY-09 SAFE 批量删除逐条 try/catch 并汇总 fail 计数
FilesPage.vue 293-301(旧) UX/BUG FINDING→已修复 P2 props.onClick 在 Vuetify 4 无效;已用 #item

Step 5: 入口表

方法 路径 鉴权 说明
POST /api/sync/browse JWT get_current_admin 远程目录列表(本次契约 items
POST /api/sync/file-ops JWT 删/改名/建目录
POST /api/sync/read-file JWT 读文件(预览/编辑)
POST /api/sync/upload JWT 上传
POST /api/sync/download JWT 下载
POST /api/sync/chmod JWT 改权限

Step 6: 输入→Sink

输入 Sink 防护
currentPath(路径栏/面包屑) POST /sync/browse body.path 前端 normalizeRemotePath;后端 shlex.quote
item.name(行点击) joinRemotePath → browse 单段拼接,不含 /
mkdirName file-ops mkdir joinRemotePath + 后端 shlex.quote
上传 FormData /sync/upload JWT + 既有上传校验(未改)

Step 7: 归类

frontend/src/pages/FilesPage.vue     615行  5H扫描  1FINDING(已修复)
frontend/src/utils/remotePath.ts    72行  2H扫描  0FINDING
frontend/src/utils/fileBrowse.ts    51行  1H扫描  0FINDING
server/api/sync_v2.py (browse段)      75行  2H扫描  0FINDING
────────────────────────────────────────────────────────
总计                                 0 未关闭 FINDING

Step 8: DoD

  • 面包屑可点击跳转且当前层级 disabled
  • 路径栏 Enter/箭头与列表目录进入使用同一 normalizeRemotePath
  • 空目录 items: [] 正常展示
  • ruff check server/api/sync_v2.py 通过
  • npm run type-check 通过
  • changelog 已更新

FINDING 列表

无未关闭 FINDING(面包屑 P2 已在本次提交中修复)。

结论

☑ 审计通过,0 未关闭 FINDING,可部署前端构建产物至 web/app/