fix(push): session_id 非空时必须是合法 UUID —— 它此前静默接受任意字符串,真 bug 就是这么活下来的
dsh(f07daac1 之后的 5fab8734)报:客户端一度把这个字段填成**服务器地址** (`AccountInfo.server` = `https://…/api/v1`),而这里只 TrimSpace、不看格式 ⇒ 不 400、不影响收信、不进日志;而**投递路径也不看它**(通知里的 session_id 来自 邮件自己,见 notify/mail.go;dispatch 只用 token 的 Provider/Token)。 两条路都不看 ⇒ 存了假值没有任何机制会报警,可它存在的唯一目的就是 「点通知回到那条会话」。 改动只有一条校验(非空才校验,空串仍合法 —— 契约允许"客户端还没进任何会话"), 400 文案自带药方(写明"要么 UUID、要么留空")。 判据 `TestPushTokenSessionIDMustBeUUID` 四个用例:服务器地址顶替 / 随便一个词 / 空串 / 真 UUID。**变体验证两个方向**: · 去掉校验(连 import 一起去)⇒ 「非法」两条当场红(实际 200); · 把判断写反(`err == nil` 才报错)⇒ 合法的真 UUID 也红 ⇒ 证明它不是"恒 400"。 恢复后 `go test ./...` 全绿、`go vet` 干净。 取舍:老客户端带旧值上报会吃 400,按契约 400 归静默 ⇒ 不打扰用户、只是那次不上报。 `push_tokens` 现为 0 行,**没有历史脏值要清**。
This commit is contained in:
@ -9,6 +9,7 @@ import (
|
||||
"github.com/agentmail/gateway/internal/middleware"
|
||||
"github.com/agentmail/gateway/internal/push"
|
||||
"github.com/agentmail/gateway/internal/repo"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -75,6 +76,28 @@ func RegisterPushToken(w http.ResponseWriter, r *http.Request) {
|
||||
Error(w, http.StatusBadRequest, "token 非法(不能为空,最长 512 字符)")
|
||||
return
|
||||
}
|
||||
/*
|
||||
* session_id 非空时必须是**合法 UUID**(dsh 2026-09-17 报的真 bug)。
|
||||
*
|
||||
* 为什么这个校验值得加(那个 bug 无声地活了很久):
|
||||
* 客户端一度把这个字段填成了**服务器地址**(`https://…/api/v1`),而这里只 TrimSpace、
|
||||
* 允许任何字符串 ⇒ 不报错、不影响收信、不进日志。而**投递路径不看这个字段**
|
||||
* (发通知用的是邮件自己的 `m.SessionID`,见 notify/mail.go;dispatch 只用 token 的
|
||||
* Provider/Token),所以它错了也**没有任何机制会报警**。
|
||||
* 可这个字段存在的唯一目的就是“点通知回到那条会话”—— 等哪天真按它路由,
|
||||
* 人会被送到别的会话,而根因在一个看起来“存进去了”的字段上。
|
||||
*
|
||||
* 代价与取舍:老客户端(上报过错值的)下次上报会吃 **400**;按契约 400 归静默,
|
||||
* 所以不打扰用户、只是那一次不上报(下次带对值就恢复)。用一次静默重试换掉
|
||||
* “静默存错值”,值。
|
||||
* 注意:这里**只校验非空值**——空串是契约允许的(“客户端还没进任何会话”)。
|
||||
*/
|
||||
if sid := strings.TrimSpace(req.SessionID); sid != "" {
|
||||
if _, err := uuid.Parse(sid); err != nil {
|
||||
Error(w, http.StatusBadRequest, "session_id 非法(必须是会话 UUID,或留空表示“还没有当前会话”)")
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := repo.UpsertPushToken(r.Context(), req.Provider, req.Token, user.Username,
|
||||
strings.TrimSpace(req.SessionID), strings.TrimSpace(req.DeviceName)); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "登记推送地址失败")
|
||||
|
||||
Reference in New Issue
Block a user