--- id: T-685 title: 阶段一设备登记与会话观测 phase: 8 deps: [] status: TODO created: 2026-07-21 --- # T-685 阶段一设备登记与会话观测 ## 问题 / 背景 商业授权方案的当前权威实施顺序要求先验证“哪个桌面安装实例正在为哪个 cmhub 账号使用”,再启用套餐强制。当前桌面端只保存普通 cmhub API Key;所有请求没有设备会话,无法统计设备稳定性、旧版本占比、复制配置或换机风险。 阶段一是观测与兼容阶段:已有 API Key 继续承担 cmhub 身份和点数计费;设备会话只提供设备上下文。设备登记、会话刷新或心跳失败不得中断当前生文、生图、商品套图、轮询和下载,也不得要求用户输入卡密或账号密码。 cmhub 需先提供并冻结以下产品接口契约后才可实施: - `POST /api/v1/client/devices/register` - `POST /api/v1/client/devices/heartbeat` - `X-Device-Session` 的有效期、刷新条件、错误码和产品接口接受范围 ## 方案 ### 1. 本机设备状态 - 新增桌面端设备身份与安全存储模块。首次运行生成高熵随机 `install_id`,以 `product_code + install_id` 派生版本化设备摘要 `v1:`;不上报、记录或展示原始 `install_id`。 - 使用 Windows DPAPI 按当前 Windows 用户保护 `install_id`、`device_session_token` 和会话过期时间。敏感状态存入独立受保护文件,不混入 `config.json`、`cmhub.json`、SQLite 普通字段、任务快照或日志。 - 不读取或上传原始 MachineGuid、MAC、磁盘序列号。MachineGuid 风控摘要属于服务端后续可选能力,不是本任务的桌面端认证依据。 - DPAPI 只支持 Windows;测试环境通过可 mock 的适配层验证。无法读取或写入受保护状态时按“未登记旧客户端”继续运行,写入脱敏诊断并采用退避重试,不生成临时不稳定 device_id。 ### 2. 注册、会话与心跳 - 应用启动后异步执行设备登记,不阻塞数据目录检查、强制升级、Chrome 检测、数据库初始化或主窗口显示。 - 登记请求沿用当前 Bearer cmhub API Key 身份,提交 `product_code`、版本化设备摘要、`device_id_version`、`client_version`、平台;不得提交用户 ID、原始机器标识、API Key 到请求体或 URL。 - 成功后安全保存短期 `device_session_token` 与过期信息;会话临期、应用启动和每日首次使用时后台刷新。心跳/刷新需节流,同一安装实例 24 小时内不得为普通生成高频重复写 `last_seen`。 - 当有有效会话时,cmshopee 产品相关 cmhub 请求统一附加 `X-Device-Session` 与 `X-Client-Version`;没有会话或服务端尚未开放设备接口时保留现有请求方式并标记 `legacy_client` 观测路径。 - 请求头组装必须集中在 cmhub 客户端边界,覆盖标题、封面 submit/poll、AI帮写、商品套图 submit/poll/继续查询、模型目录和余额查询;图片 CDN 下载不携带设备会话。不得通过散落的各 worker 手工拼接。 ### 3. 用户体验、诊断与安全 - 阶段一不新增卡密激活弹窗、不阻断按钮、不显示“无授权”错误;必要时仅在状态栏以低干扰中文提示“正在登记本机设备”或“设备登记稍后重试”。 - 不在设置页、运行日志、SQLite、诊断日志、异常回包或 URL 中展示设备摘要、会话令牌、旧 API Key、DPAPI 密文或本地文件路径。 - 把可聚合事件写入脱敏诊断:登记成功/失败分类、会话刷新、使用旧兼容路径;不记录原始响应。阶段一不新增本地设备管理、解绑、套餐、卡密、网页支付或权益展示 UI。 ## 验收要点 - [ ] 首次启动生成稳定的版本化设备摘要并以 DPAPI 保存本机状态;同一 Windows 用户重启后摘要稳定,复制数据目录到另一用户/设备不能直接读取敏感状态。 - [ ] 登记、会话刷新与每日心跳均在后台执行;成功请求包含所需产品字段,正常 cmhub 调用带 `X-Device-Session` 和 `X-Client-Version`。 - [ ] 设备服务不可用、网络抖动、会话过期、DPAPI 失败和旧 cmhub 服务返回未知接口时,现有托管生成、已有异步任务轮询/下载与本地功能不中断。 - [ ] 标题、封面、AI帮写、商品套图、模型目录和余额的产品请求不会遗漏有效设备会话;图片 CDN 下载不携带该头。 - [ ] 所有设备相关日志、状态和错误均为中文且不含会话令牌、API Key、原始设备标识或 DPAPI 密文。 - [ ] 当前 direct 自定义网关路径在阶段一保持现状,不被误改为授权强制;正式 BYOK 代理与 direct 移除留给后续任务。 ## 测试与文档 - 新增 `tests/test_device_identity.py`、`tests/test_device_session.py`:DPAPI 适配 mock、稳定身份、无法解密降级、登记幂等、会话刷新/心跳节流、无服务兼容和日志脱敏。 - 扩展 `tests/test_ai.py`、`tests/test_image_studio_generation.py`、`tests/test_gui.py`:统一请求头覆盖、图片下载排除、启动非阻塞与用户可见中文状态。 - 更新 `docs/04-architecture.md`、`docs/routes.md` 的设备会话边界、受保护本地状态、阶段一兼容策略与接口契约;同步 Obsidian 方案的接口实测结果。 ## 验证 ```bash py -3.10 -m unittest tests.test_device_identity tests.test_device_session tests.test_ai tests.test_image_studio_generation tests.test_gui py -3.10 -m unittest discover -s tests py -3.10 -m ruff check app tests main.py py -3.10 -m compileall app main.py git diff --check ``` ## 边界(不改什么) - 不实现卡密、激活、套餐、权益、设备席位、解绑、续费、支付、离线权益令牌或服务端授权强制。 - 不把 `DeviceSession` 当作用户身份或计费身份;Bearer API Key 和既有点数账本保持原职责。 - 不修改 cmhub 通用 API 的全局鉴权,不阻断未升级客户端,不要求用户重新填写 API Key。 - 不改变 direct 自定义网关、BYOK 代理、图片异步协议、Chrome/CDP、采集或更新蝦皮逻辑。 ## 关联 - Obsidian《卡密设备绑定与套餐授权方案》§6.3、§6.9:阶段一设备观测及最终身份边界。 - T-544:既有启动升级检查;设备登记不得阻塞该流程。 - T-678/T-679:现有自定义网关与商品套图来源;阶段一只观测,不提前改变其执行路径。 ## 执行记录 - 待 cmhub 设备接口契约冻结后实施。