fix(app): OTA 信任链加固、引擎背压与协议正确性
OTA(update/):
- 解压前校验 7z 条目清单:sevenz-rust 0.6.1 的 decompress_file 直接 dest.join(entry.name()),不校验 ".."、绝对路径与盘符,恶意归档可越界写文件;现在要求恰好一个条目且名字与约定二进制一致(fail-closed)
- 无 .sha256 侧车时拒绝安装,不再静默跳过校验而 UI 仍宣称已校验
- 安装前重算暂存文件哈希;同意标记从仅版本号改为绑定「版本 + 哈希」
- 跨卷 rename 失败回退「复制 + fsync + 删源」(暂存在 APPDATA、exe 在安装目录,不同卷时必失败且报错误导)
- .old 回滚备份保留 7 天:原实现新版本首启即删,新版本一旦崩溃用户无任何回退路径
- 新增安装互斥锁:两实例同时安装会互删暂存包、争抢同一个 .old
- platform_triple 用 std::env::consts::ARCH:写死 x86_64 让 ARM 客户端永远挑不到产物
- pick_assets 按命名约定精确后缀匹配:非 Windows 下 ends_with("") 恒真,.tar.gz/.deb 会被当成可执行文件下载并替换自身
引擎(mqtt/):
- 事件通道改有界并分级:高频事件(消息/日志)满即丢并计数、每 1000 条提示一次;状态/订阅结果/发布回执异步补投。原无界通道在到达速率超过消费速率时内存无上界(单条最长 128KB)
- 重连改指数退避(1s→30s 封顶)+ 0~500ms 抖动,替代固定 2 秒的惊群式重试
- 测试连接的建连(读证书,阻塞 IO)移入 spawn_blocking,与 connect 一致
正确性与性能:
- session_params_changed 补齐 4 个 v5 CONNECT 属性(会话过期/接收上限/最大报文/主题别名),漏掉会让"重连后生效"提示静默失效;测试改逐字段防漏式断言
- ConnectionConfig / AliyunPreset 手写脱敏 Debug:password 与 AccessKeySecret/DeviceSecret 输出 <redacted>,杜绝一次 {:?} 把凭据送进 stderr 与 Sentry
- MqttRecord.user_properties 改 Arc<[(String,String)]>、应用日志改 Arc<LogEntry>:消息面板每帧 300 条、日志面板每帧 3000 条的深拷贝降为引用计数
- 阿里云 DeviceName 空值校验,避免拼出非法 clientId 后服务端报错难懂
This commit is contained in:
@@ -23,26 +23,24 @@ pub(super) fn http_get_json(url: &str) -> Result<serde_json::Value, String> {
|
||||
|
||||
pub fn pick_assets(rel: &serde_json::Value) -> Option<(String, String, u64, Option<String>)> {
|
||||
let assets = rel.get("assets")?.as_array()?;
|
||||
let want_ext = if cfg!(windows) { ".exe" } else { "" };
|
||||
let triple = platform_triple();
|
||||
// 产物命名约定:`mqttx-v<ver>-<triple>-mqttx[.exe]`(压缩包再加 `.7z`)。
|
||||
// 必须按固定后缀精确匹配:非 Windows 下扩展名为空串时 `ends_with("")` 恒真,
|
||||
// 任何含三元组的附件(.tar.gz/.deb/.txt)都会被当成可执行文件下载并替换自身。
|
||||
let bin_name = if cfg!(windows) { "mqttx.exe" } else { "mqttx" };
|
||||
|
||||
// (后缀过滤器, 说明):第一轮 7z,第二轮裸二进制
|
||||
for suffix in [".7z", want_ext] {
|
||||
// 第一轮 7z 压缩包,第二轮裸二进制
|
||||
for suffix in [".7z", ""] {
|
||||
for a in assets {
|
||||
let Some(name) = a.get("name").and_then(|n| n.as_str()) else {
|
||||
continue;
|
||||
};
|
||||
if !name.contains(triple)
|
||||
|| !name.ends_with(suffix)
|
||||
if !name.contains(triple.as_str())
|
||||
|| !name.ends_with(&format!("{bin_name}{suffix}"))
|
||||
|| name.ends_with(".sha256")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 7z 轮要排除裸二进制(windows 裸 exe 不以 .7z 结尾,天然互斥)
|
||||
if suffix == ".7z" && !name.ends_with(&format!("{want_ext}.7z")) && !want_ext.is_empty()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let Some(url) = a.get("browser_download_url").and_then(|u| u.as_str()) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user