Files
MailUI4Agents/client/electron
JianFeeeee 9404f98bde 跨端: fix(推送客户端) session_id 传的是**服务器地址** —— 一个"不报错"的假数据
这条不是别人报的 bug,是我自己在做上一封收尾时写下的,今天读自己的代码才发现。

## 错在哪

`reportToken` 里:

    const sessionId: string = this.account.getActiveAccount() === null
      ? ''
      : this.account.getActiveAccount()!.server;      ← AccountInfo.server = **服务器地址**

`AccountInfo.server` 的值长这样:`https://mail.jianfgit.xyz/api/v1`。
而服务端对这个字段的语义是「客户端**当前所在的会话**:点通知要回到那条会话里的那封信」
(`server/internal/handler/push.go`),类型上是会话 UUID(`push_tokens.session_id`)。

## ★ 为什么它能一路活到今天:因为它**不报错**

两件事叠在一起,让它完全无声:

1. 服务端对这个字段**不做格式校验**(只 `TrimSpace`,并且明确允许为空);
2. 服务端当前**只写不读** —— 投递时用的是**邮件自己的** `n.SessionID`
   (`notify/mail.go` 构造 `push.NewMail{SessionID: m.SessionID}`),
   `dispatch` 只用 `Provider`/`Token` 两个字段。

⇒ 它不会 400、不会影响收信、不会出现在任何日志里,
只会在 `push_tokens` 里静静存一条**假的**会话 id。
等哪天真按这个字段路由(它存在的**唯一目的**就是那个),
人会莫名其妙被送到别的会话去 —— 而那时没人会想到根因在这个字段。
**"不会立刻炸"正是这类错最危险的地方:它不报错,它让数据开始说谎。**

## 修法:如实传空,不编一个

这一步的时机**决定了它必然为空**:`reportToken` 只在**登录成功**与**换账号**时跑,
那时用户还没打开任何会话;客户端也**根本没有"当前会话"这个状态**可读
(我确认过:`MainPage` 不记当前会话,全仓没有 `currentSession` 之类的东西)。

而服务端对这个字段**明确允许空**:"客户端还没进任何会话,此时通知只带 mail_id"。
⇒ **传空是准确的,传 URL 是错的。** 等客户端真有了"当前会话",再回来补真实 id。

## 判据(19 → 20 条)

新增「session_id 不许拿服务器地址顶替」,钉的是**值的来源**而不是"有没有传",
所以既能挡住"再塞个别的字段顶替",也不妨碍将来补报真实 id(那时这条要改成钉真实 id)。

变异验证两个方向都做了:
- 还原成原 bug(传 `.server`)⇒ `not ok 9` 红;
- 换成 `.username` 顶替(换汤不换药)⇒ 同样红;
- 恢复 ⇒ 20/20 绿,文件逐字还原。

编译侧反向对照照旧:在新代码那行植入必然类型错误 ⇒
`ArkTS Compiler Error: Type 'number' is not assignable to type 'string'.
At File: …/PushService.ets:255:11` ⇒ `BUILD FAILED`(证明这个模块真被编译,
不是"改了没接线所以通过")。

真机:装新包后行为不变仍是静默失败(`push token 取不到(静默,属正常):Illegal application identity.`),
`jscrash`/`FaultLogger` 计数 0 ⇒ 这个修复没有改变失败路径的形状,只改了不再写假数据。
2026-09-17 19:38:15 +08:00
..