feat: 设备端应用商店(平台侧)—— Agent 直连拉清单/下载/安装,绕开 MIUI 的 USB 安装拦截

背景:`adb install` 在 MIUI 上被「USB 安装」拦下(USER_RESTRICTED),必须人工点确认;
而**由设备上的 App 自己调系统安装器**走的是普通应用安装流程,不触发那道拦截。

平台侧实现(设备端 Agent APK 在另一个仓库,契约见 doc/DEVICE_AGENT.md):

- web/device_agent_api.py(新):
  * 设备侧 `/api/device/agent/{bootstrap,apk/<id>,report}` —— 无登录会话,靠
    `X-Device-Token`(常量时间比对)鉴权;`X-Device-Fingerprint` 让平台认出是哪台设备
    (换 IP 也认得出,并把平台分配的名称回给它);**默认关闭,关闭时统一 404**,
    不暴露接口存在性;只读清单与文件,不返回任何配置/密钥
  * 管理侧 `/api/agent-store/{config,logs}` —— 登录 + 应用管理权限;启用时自动生成令牌,
    可一键重置(旧令牌立即失效)
- core/models.py:新增 `device_install_log`(下载/安装记录,自动裁剪保留 500 条)
- 应用管理页新增「📱 设备端应用商店」面板:开关 / 接入地址 / 令牌(复制·重置)/ 安装记录;
  面板里写明它与「平台批量推送」的分工
- doc/DEVICE_AGENT.md(新):**两个仓库共享的接口契约** —— 接入流程、三个设备接口的
  完整规格与错误码、adb 指令协议(剪贴板/身份显示/配置下发)、版本兼容约定、安全须知;
  API.md、DATA_MODEL.md、doc/README.md 索引同步

验证:
- 后端 9 组用例:默认关闭 404、无/错令牌 401、指纹认出设备名、清单、下载、上报与失败
  原因落库、关闭后重新 404、重置令牌后旧令牌立即失效、未登录管理端被拒 —— 全通过
- 真实浏览器:面板渲染、点开关 → 自动生成令牌 → 设备端带令牌拉到清单且 device.name=A08、
  无 JS 报错;测试后已把开关还原为关闭
- 全量回归 105 项通过(42 GET + 62 写探测 + 7 关键业务)
This commit is contained in:
2026-09-13 14:40:38 +08:00
parent 66632bb7d6
commit dad1af8b0b
11 changed files with 668 additions and 3 deletions
+4
View File
@@ -43,6 +43,7 @@
| 10 | `agent_experience` | 经验库(任务级配方) |
| 11 | `experience_audit` | 经验巡检结论 |
| 12 | `agent_action` | 动作库(命名动作) |
| 13 | `device_install_log` | 设备端应用商店的下载/安装记录(设备上报,见 [DEVICE_AGENT.md](DEVICE_AGENT.md)) |
> 2026-09-13 之前,`app_meta` 与 4 张 `agent_*` 表是各模块里的裸 `CREATE TABLE`
> (不进模型层)。迁 MySQL 时那批 SQL 的 `AUTOINCREMENT`/`TEXT DEFAULT ''`/`TEXT PRIMARY KEY`
@@ -232,6 +233,9 @@ UTF-8 等价于字节序)。
| `discovery_interval` | 扫描周期秒(10-3600) | 同上 |
| `discovery_port` | adb 探测端口(1-65535) | 同上 |
| `discovery_auto_claim` | 指纹匹配时自动认领(`"1"`/`"0"`,默认关) | 同上 |
| `agent_store_enabled` | 设备端应用商店开关(`"1"`/`"0"`,默认关) | 应用管理页 |
| `agent_device_token` | **设备端令牌**(Agent 调设备接口用;属凭据) | 同上(启用时自动生成,可重置) |
| `agent_device_token_at` | 令牌生成/重置时间 | 同上 |
| `deployment_env` | **库环境标签**(`dev`/`prod`),启动时与 `.env` 比对 | `core/db_config.py`(首次连接)/ 迁移脚本 |
| `deployment_id` | 库唯一标识(uuid),用于识别"这份备份来自哪个库" | 同上 |
| `deployment_claimed_at` | 标签写入时间 | 同上 |