diff --git a/TASKLIST.md b/TASKLIST.md index b47ac50..e5e793c 100644 --- a/TASKLIST.md +++ b/TASKLIST.md @@ -536,6 +536,9 @@ --- ### YNX-0603 实现 Discord DM 配对通知 +**状态** +- [x] 骨架已完成,真实 DM 需外部依赖(2026-04-08) + **目标** - Server 通过 `notifyBotToken` 向 `adminUserId` 发送 pairing code @@ -551,7 +554,9 @@ **进展说明** - 已新增 `Yonexus.Server/plugin/notifications/discord.ts` 作为通知服务骨架 -- 当前为日志输出 stub,仍需接入真实 Discord DM 发送逻辑 +- 已实现 `formatPairingMessage()` 格式化 DM 内容 +- 已实现 mock/stub 实现用于测试 +- **待完成**:接入真实 Discord DM 发送需要 `discord.js` 依赖和 Bot Token 配置 - runtime 已在 pairing 创建后调用通知服务并记录 sent/failed 元数据 --- @@ -939,6 +944,9 @@ --- ### YNX-1003 实现单 identifier 单活跃连接策略 +**状态** +- [x] 已完成(2026-04-08) + **目标** - 同一 client identifier 只允许一个活跃认证连接 @@ -950,9 +958,23 @@ **验收标准** - 任意时刻同一 identifier 只有一个有效 session +**已完成内容** +- 已重构 `YonexusServerTransport`: + - `tempConnections` 改为 Map 结构,跟踪未认证连接 + - 新增 `assignIdentifierToTemp()`:hello 时仅分配 identifier,不进入认证注册表 + - 新增 `promoteToAuthenticated()`:认证成功后晋升为正式连接,此时才关闭旧连接 + - 新增 `removeTempConnection()`:认证失败时清理临时连接 +- 已更新 `runtime.ts`: + - hello 处理使用 `assignIdentifierToTemp()` 代替 `registerConnection()` + - auth_success 后调用 `promoteToAuthenticated()` 完成连接晋升 +- **安全改进**:未认证连接无法踢掉已认证连接,防止连接劫持攻击 + --- ### YNX-1004 实现重启恢复策略 +**状态** +- [x] 已完成(2026-04-08) + **目标** - 重启后行为可预期且文档一致 @@ -965,6 +987,17 @@ **验收标准** - 重启后的认证/配对行为稳定可解释 +**已完成内容** +- **持久化恢复**:`YonexusServerRuntime.start()` 加载持久化记录,恢复所有 client records +- **allowlist 同步**:对配置中的 `followerIdentifiers` 自动创建缺失的初始记录 +- **rolling windows 清理**:`deserializeClientRecord()` 明确清空 `recentNonces` 和 `recentHandshakeAttempts` + - v1 设计:安全窗口仅内存驻留,重启后重建,防止旧 nonce 积压 +- **pending pairing 恢复**:保留 `pairingStatus=pending` 和 `pairingCode`,支持重启后继续配对流程 +- **连接状态重建**: + - 所有连接状态标记为 `offline`(WebSocket 连接不可恢复) + - `lastHeartbeatAt` 保留,liveness sweep 会根据其判断状态转移 +- **已文档化**:在 `persistence.ts` 和 `types.ts` 中以 JSDoc 注释明确重启语义 + --- ## Phase 11 — 测试与联调 diff --git a/Yonexus.Server b/Yonexus.Server index 4f20ec3..988170d 160000 --- a/Yonexus.Server +++ b/Yonexus.Server @@ -1 +1 @@ -Subproject commit 4f20ec3fd725b3b097afdd226bce6b21e3957839 +Subproject commit 988170dcf6df315f56b627d992e61005618ba739