Safe Haven 版本提交与自动批准,presigned URL 十五分钟过期
完整提交流程
开发者提交一个新版本 APK 的完整路径:
1. 管理门户点"上传新版本"
2. 后端生成 presigned PUT URL(AWS Signature v4,15 分钟有效)
3. 用 PUT 请求把 APK 上传到 URL 指向的 staging 路径
4. 文件到达 staging → 条目自动从 pending_upload → pending_scan
5. 扫描器拉取 APK → scanning → 跑完整管线
6. 通过扫描 → pending_review(等自动批准定时器)
7. 定时任务检查 pending_review 条目 → 超过一定时间无错误 → 自动批准 → live
8. 复制 APK 到 production 目录 → 更新全局索引 → 客户端下次同步可见
什么是 presigned URL
presigned URL 是 AWS S3(和兼容 S3 的对象存储)提供的一个安全上传机制:
- 后端生成一个带签名的临时 URL
- 签名里包含:上传者身份、目标路径、过期时间、HTTP 方法(PUT)
- 客户端(开发者)拿着这个 URL,用 PUT 请求直接上传
- 存储桶的 AWS 访问密钥只在后端生成签名时用到,开发者永远看不到
Safe Haven 用 presigned URL 的原因:
- 安全:开发者不需要 AWS 账号,上传权限被严格限制(只能传指定路径、只能 PUT、过了 15 分钟就失效)
- 解耦:上传和处理分离——APK 先到 staging 临时目录,扫描通过后才复制到 production
- 防攻击:开发者不能直接往 production 目录写文件,必须先过扫描管线
不同资源的 URL 有效期
| URL 类型 | 有效期 | 说明 |
|---|---|---|
| 上传(PUT staging) | 15 分钟 | 开发者上传 APK |
| 下载(GET production) | 5 分钟 | 客户端下载 APK(可配置重定向模式) |
| 图片读取(GET images) | 7 天 | 图标和截图的读取 URL |
上传用什么工具
任何支持自定义 HTTP Header 的工具都能发 PUT 请求。几个常见选择:
curl
curl -X PUT -T ./release.apk "<把 Safe Haven 后台生成的 presigned URL 粘贴到这里>"
PowerShell (Windows)
Invoke-WebRequest -Method PUT -InFile .\release.apk -Uri "<把 presigned URL 粘贴到这里>"
Postman / Insomnia
创建一个 PUT 请求,Body 选 "Binary",选择 APK 文件,URI 填 presigned URL。
上传时不需要额外的鉴权 Header——URL 里的签名就是鉴权。
pending_review 自动批准机制
扫描通过后,条目进入 pending_review 状态。这个状态不是等人手动审核——Safe Haven 有一个 cron 定时任务在后台跑:
- 周期性检查所有
pending_review状态的条目 - 如果一个条目在 review 状态停留超过一定时间且没有产生错误 → 自动批准 →
live - 如果停留期间有新错误 → 保持在 review 或退回扫描
Safe Haven 自己的客户端有特权
Safe Haven 客户端(com.colourswift.safehaven)的提交完全跳过 pending_review——扫描通过后立即进入 live。这是一个硬编码的特殊处理,目的是让客户端自己的更新能最快触达用户(v2.0.7+ 的 lag 修复等 bugfix 版本可以快速发布)。
失败了怎么办
提交失败 → 条目进 rejected 状态,Safe Haven 会记录哪个规则触发了拒绝:
| 触发规则 | 含义 | 修正 |
|---|---|---|
| SHA-256 重复 | APK 和已有版本一模一样 | 换一个 APK(加时间戳、改版本号重新构建) |
| versionCode 重复 | manifest versionCode 和已有版本撞了 | 递增 versionCode 后重新构建 |
| 包名不匹配 | APK 的包名和条目记录的不一样 | 检查是不是传错了条目 |
提交前自检清单
提交新版本前检查:
- [ ] versionCode 比已有的所有版本都大
- [ ] versionName 格式正确(可选,但用户会看到)
- [ ] APK SHA-256 确实是新的(不是重新打包同一个文件)
- [ ] APK 体积 ≤ 100 MB
- [ ] 架构是 arm64-v8a 或 armeabi-v7a(不要只有 x86)
- [ ] 包名和条目记录的一致
生产目录 vs staging 目录
Safe Haven 的 S3 存储桶按路径区分:
staging/ ← 上传临时目录,扫描通过前用户看不到
└── com.example.app/
└── 42/
└── app.apk ← presigned PUT 到这里
apps/ ← 生产目录,扫描通过后才复制进来
└── com.example.app/
└── 42/
└── app.apk ← 复制过来的,客户端下载的就是这个
staging 目录对客户端完全不可见——它只是一个"待处理区",扫描没过的 APK 会一直留在 staging 里直到清理脚本删除。