Files
cmshoppe/docs/tasks/T-616.md
T

3.4 KiB

id, title, phase, deps, status, created
id title phase deps status created
T-616 自动升级安全下载校验与同盘暂存 8
T-615
TODO 2026-07-13

问题 / 背景

自动升级不能把远程zip直接交给更新器。客户端必须先完成可信地址限制、流式下载、大小/hash校验、防zip路径穿越、安全解压、包内版本与manifest逐文件校验;任何一步失败都不能碰当前程序文件。

更新临时文件不能混进用户业务数据 data/。本任务使用安装目录同级管理区 <安装目录>/.cmshopee-update/,既与程序在同一磁盘便于后续目录切换,也与账号、SQLite、图片和密钥完全隔离。

方案

  1. 新增 app/update_installer.py 纯逻辑模块,定义自动安装元数据、下载结果、暂存结果和中文错误类型;不得依赖Qt控件。
  2. 只接受HTTPS下载地址。下载主机采用客户端受信任域名白名单;重定向只能落在同一白名单内,禁止降级HTTP、file://、内网地址和任意第三方跳转。
  3. 流式下载到 .cmshopee-update/downloads/<version>.zip.part,持续校验累计字节数,完成后要求与 size_bytes 完全一致、SHA-256严格一致,再原子改名为 .zip。包大小硬上限建议512 MiB;超限、磁盘不足、中断或取消时保留当前版本,清理不完整part文件。
  4. 安全解压到 .cmshopee-update/staging/<version>-<随机值>/。解压前逐项拒绝绝对路径、盘符/UNC、..、符号链接、Windows保留名、NTFS ADS冒号、尾随点/空格、大小写不敏感重复目标;限制文件数不超过20000、解压总量不超过2 GiB,并限制异常压缩比。
  5. 解压后严格验证 version.txt、package-manifest.json、cmshopee.exe 和 _internal/;版本、包格式、更新器协议必须与服务端元数据一致。按manifest逐文件复算大小和SHA-256,拒绝manifest未声明的程序文件和缺失文件。
  6. 本地写入 pending.json 只记录版本、安装根、暂存根、hash和阶段,不记录URL查询参数、密钥或用户数据路径。下一次启动可识别已经完整校验的暂存包,避免重复下载;无效/不完整pending必须清理后重新下载。
  7. 失败消息对用户保持中文概述,远程URL、内部路径、堆栈写入脱敏诊断日志,不直接展示。

验收要点

  • 正常zip能下载、校验并暂存,当前 cmshopee.exe、_internal/ 和 data/ 完全不变。
  • hash为空、格式错误、不匹配,大小不匹配,HTTP/非白名单地址和越权重定向均拒绝安装。
  • zip slip、符号链接、大小写重复、保留名、ADS、zip bomb和manifest缺失/篡改均被自动化测试阻断。
  • 下载中断后不会把 .part 当完整包;已验证pending可在重启后复用,不重复下载。
  • 更新目录始终位于 .cmshopee-update/,不创建 data/updates,不读取用户业务数据。

测试要求

  • 新增 tests/test_update_installer.py,使用临时目录和本地可控响应覆盖成功、取消、网络失败、所有安全拒绝路径及pending恢复。
  • 运行ruff、compileall、完整unittest和 git diff --check;不依赖真实线上下载地址。

边界(不改什么)

  • 不启动独立更新器,不替换程序,不自动重启。
  • 不修改当前T-544强制升级GUI;GUI接入由T-618完成。
  • 不读取、移动、覆盖或清理 data/。

执行记录

(完成后记录实现、验证命令与结果。)