feat: 添加 WireGuard 设备管理并完善客户端分流
实现独立加密设备身份、网关 agent、持久生命周期任务和 Surge/FlClash 专属订阅凭证。 完善 Shadowrocket 规则转换与 Clash AI DNS,增加 Surge FFSB 适配、规则快照、运维工具及验收文档。
This commit is contained in:
171
docs/design/wireguard-devices/DESIGN.md
Normal file
171
docs/design/wireguard-devices/DESIGN.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# WireGuard 设备管理与 Surge 按设备订阅
|
||||
|
||||
状态:已确认产品设计与原型,2026-11-02。已完成本地实现,具体接口、迁移和验收见 [实现记录](../../WIREGUARD-DEVICES.md);现已部署 LA 应用与 njcq agent,未切换活动客户端;原有设备只读纳管与凭证端点已通过,用户同日随后已确认 macOS/iPadOS/iOS 的 Surge + WireGuard 全面实测可工作,停止 Shadowrocket WG 下发兼容;生命周期与长期网络场景不据此外推。
|
||||
|
||||
开始开发请先读 [实现交接](HANDOFF.md),其中列出已有代码、实现缺口、真实配置位置与历史验证边界。
|
||||
|
||||
## 产品决策
|
||||
|
||||
设备页独立管理 WireGuard 身份、固定 IP、状态和网络生命周期。设备模型不记录“使用客户端”,创建和导出时也不要求选择客户端。当前个人设备统一使用支持 WireGuard 与入站的 Surge,仍保留标准 WireGuard 独立配置导出。
|
||||
|
||||
订阅页选择 Surge 格式后,提供“附加设备 WireGuard(可选)”下拉框,数据来自设备管理列表:
|
||||
|
||||
| 选择 | 下发配置 | 链接行为 |
|
||||
|---|---|---|
|
||||
| 不附加设备 | 干净的代理节点、策略组与规则,无设备 WG 身份 | 使用原默认 Surge URL,逐字保持不变 |
|
||||
| 选择某台设备 | 原代理内容 + 此设备独立 WG 身份、私网规则和入站设置 | 基于原入口生成带设备凭证的派生 URL |
|
||||
| 清除选择 | 恢复纯代理配置 | 恢复原默认 URL |
|
||||
|
||||
**选择状态必须体现在生成链接的凭证中,不能保存在服务端的全局“当前设备”变量。** 否则 Mac 选择设备后会改变 iPad 下次刷新所得到的身份。
|
||||
|
||||
本方案统一的是订阅入口与节点、策略、规则来源,不承诺包含不同私钥的各设备使用逐字相同的完整 URL。设备专属链接需在对应设备导入一次,之后每次更新仍包含同一设备身份。不再需要额外身份模块、客户端选择或复制私钥。
|
||||
|
||||
## 信息架构
|
||||
|
||||
主导航沿用:节点 / 策略组 / 规则 / **设备** / **订阅** / 设置。
|
||||
|
||||
设备页保留现有列表与操作:名称、系统、固定私网 IP、状态、最后活动、上行/下行、详情、暂停/恢复、重置身份与移除。显示方向以设备为准,上行为设备到网关,下行为网关到设备。窄屏沿用设备条目布局。
|
||||
|
||||
设备详情增加两个清晰入口:“用于 Surge 订阅”和“导出独立 WireGuard 配置”。前者打开订阅页并预选此设备,后者打开独立导出页。两种方式引用同一设备身份,不另分配 IP 或密钥。
|
||||
|
||||
设备信息中删除客户端名称与兼容性分支。系统字段继续用于识别设备,不作为私钥领取认证凭据。
|
||||
|
||||
## 添加设备
|
||||
|
||||
1. 填写名称、系统。网关、网络、MTU、IP 和密钥自动处理。创建前展示默认设备互访范围。
|
||||
2. 事务内预留唯一 IP 和独立 keypair/PSK,创建幂等网关任务。只有网关确认运行配置和持久配置生效后,才显示“待接入”。失败保留同一设备和 IP,重试不重复创建。
|
||||
3. 创建完成后可选“前往 Surge 订阅”或“导出独立 WireGuard 配置”。也可稍后从设备列表继续。
|
||||
4. 导入后单独检查首次握手。生成、复制链接、下载配置或点击导入均不直接变为在线。
|
||||
|
||||
第一版使用现有 njcq 网关、10.203.0.0/24、MTU 1280,保留现有 iPad .2 与 Mac .3。网关只转发个人私网互访,不新增 Internet 出口或 NAT。
|
||||
|
||||
## 订阅交互
|
||||
|
||||
订阅卡片保留当前节点范围与启用状态。选择格式为 Surge 后显示设备下拉框,默认“不附加设备 · 纯代理订阅”。选项包含名称、私网 IP 和当前状态;离线设备可以选择,首次未握手但网关已生效的设备也可以选择。
|
||||
|
||||
已暂停、正在撤销、正在恢复、配置中、配置异常的设备仍在列表显示,但不可新选择生成接入链接。采集失联不等于身份被暂停,不因遥测未知就错误撤销既有权限。
|
||||
|
||||
选择设备后,页面就地更新:
|
||||
|
||||
- 明确显示所选设备和 IP,以及该链接仅供此设备使用。
|
||||
- 链接包含对应的受控设备凭证;“复制链接”和“导入 Surge”使用相同的当前 URL。
|
||||
- 保留“清除设备选择”,随时返回原默认 URL。
|
||||
- 提供配置结构预览,私钥/PSK 始终遮蔽,不把真实密钥放进普通 DOM、浏览器持久化状态或原型。
|
||||
- 提供“检查设备连接”,回到所选设备的真实握手验证。
|
||||
|
||||
切换其他订阅格式时清除设备附加选择;其他格式保持原行为,不静默继承 Surge 的个人身份。清除选择只改变当前导出的链接,不撤销设备,不修改其他设备已导入的链接,也不覆盖同一订阅 token 的默认设置。
|
||||
|
||||
如果选择的设备随后被暂停或移除,界面明确显示不可下发,禁用复制/导入。旧设备 URL 在服务端也应拒绝,不能默默返回纯代理配置,更不能换成另一台设备身份。
|
||||
|
||||
## 链接、授权与生成规则
|
||||
|
||||
示意入口:
|
||||
|
||||
```text
|
||||
纯代理:/sub/<原订阅 token>/surge
|
||||
附加设备:/sub/<原订阅 token>/surge?wg=<不可枚举的设备分发凭证>
|
||||
```
|
||||
|
||||
`wg` 不是裸设备 ID、名称或 IP。共享代理订阅 token 的持有者不能通过枚举 `?device=1/2/3` 获取任意设备私钥。
|
||||
|
||||
管理员在订阅页选择设备后,由已认证的管理 API 签发或复用绑定“订阅 + 设备 + 导出用途”的高熵分发凭证。数据库保存凭证哈希及作用域,可单独撤销。服务端校验原订阅 token 和设备凭证,确认二者绑定关系、设备仍存在且允许接入,再附加身份。
|
||||
|
||||
此凭证是能读取该设备私密配置的长期能力凭证,不能作为无敏感性的普通分享链接。网页不必展示内部 token 管理细节,但要说明链接只能用于所选设备。导入地址和凭证不写入公开日志、统计或 Referer;敏感响应 no-store,缓存不得跨设备串用。
|
||||
|
||||
首次跨设备分享可使用短期领取票据,兑换后获取该设备长期订阅链接。短期票据不直接充当托管配置的长期更新 URL,避免过期后自动刷新失效。GET 预览不消耗领取会话,由显式确认的 POST 原子绑定;并发最多一个会话成功,允许同一领取会话短时重试。
|
||||
|
||||
**带设备配置的 `#!MANAGED-CONFIG` 必须写入完整的带 `wg` URL。** 如果仍写原纯代理 URL,下次自动更新就会丢掉 WG 身份。原默认纯代理配置的 header 继续写原 URL。
|
||||
|
||||
生成流水线遵循:原订阅节点权限 → 原代理 IR → 通过授权的一个设备身份 → Surge 完整配置。用户原有公网代理选择与策略名称尽量保持不变;设备 WG 节点不进入 Automatic、All Nodes、AI 等公网代理池,只供专用私网策略引用。
|
||||
|
||||
纯代理响应不包含 `[WireGuard ...]`、WG 代理声明、WG 私网路由、设备地址、私钥或 PSK。附加响应只包含被授权的一台设备,不包含设备列表或其他设备身份。入站按用户当前 Surge 能力启用,具体字段与平台行为须通过目标版本验收。
|
||||
|
||||
## 独立 WireGuard 导出
|
||||
|
||||
设备详情继续提供二维码与 `.conf` 下载。配置引用同一 device keypair、PSK 和地址;导出不创建另一个 peer,不修改代理订阅,也不因生成配置就标记在线。
|
||||
|
||||
普通列表 DTO 不返回私钥、PSK、完整配置或长期分发凭证。导出/领取使用独立授权接口,正式二维码在本地或受控服务生成,不调用在线二维码服务。暂停或网关任务未确认时不继续签发接入配置。
|
||||
|
||||
原型二维码为无密钥的演示载荷,下载与导入仅显示模拟结果。
|
||||
|
||||
## 状态与操作
|
||||
|
||||
状态仍由期望生命周期、网关应用回执、连接遥测三部分计算。
|
||||
|
||||
| 状态 | 判定与行为 |
|
||||
|---|---|
|
||||
| 配置中 | 已创建身份,网关尚未确认 |
|
||||
| 待接入 | peer 已生效,从未出现有效握手 |
|
||||
| 近期在线 | 新鲜采样且 180 秒内有握手或流量增长 |
|
||||
| 离线 | 采集正常,已连接过,但超出活跃阈值;不代表设备电源关闭 |
|
||||
| 状态未知 | 采集超过 45 秒未更新,展示最后采集时间并隐藏实时速率 |
|
||||
| 正在暂停 | 已请求移除 peer,尚未收到确认,可能仍可通信 |
|
||||
| 已暂停 | 网关运行配置与持久配置均确认移除 peer,记录与 IP 保留 |
|
||||
| 配置异常 | 网关应用失败或配置冲突,保留幂等任务重试 |
|
||||
|
||||
网关每 15 秒上报,页面 15 秒刷新;使用相对握手年龄和中心接收时间处理时钟偏差。计数周期重置时重新建立速率基线,不显示负流量;累计用量按纳管后的有效增量持久记录。
|
||||
|
||||
WireGuard 数据不直接证明 VNC 健康、端到端画面延迟或媒体丢包。地址漫游也不直接判定身份被盗用。
|
||||
|
||||
- 改名只修改元数据;设备凭证绑定 ID,不随名称变化失效。
|
||||
- 暂停必须在网关移除 peer 并持久化;仅停用订阅链接不能撤销已导入的网络身份。
|
||||
- 恢复在网关确认 peer 重新生效后允许连接。
|
||||
- 重置身份先撤销旧 key 再生效新 key,IP 保留。既有未泄露的设备订阅可以继续通过刷新获取新身份,独立 `.conf` 需重新导入。若泄露的是分发链接,另行撤销并重新签发其凭证。
|
||||
- 移除先撤销 peer,确认后归档、撤销所有绑定凭证。IP 不立即复用。被移除设备的旧 URL 拒绝下发,不能指向后续设备。
|
||||
|
||||
## 数据模型与接口
|
||||
|
||||
复用上一版设备生命周期实体:`wg_networks`、`wg_gateways`、`wg_devices`、`wg_jobs`、`wg_observations`、用量聚合、`wg_events`、短期 `wg_enrollments`。
|
||||
|
||||
设备实体包含名称、系统、固定 IP、公钥、加密存储的私钥/PSK、期望状态和应用版本,**不包含客户端选择**。增加 `wg_subscription_bindings`,保存订阅 ID、设备 ID、分发凭证哈希、用途、创建/访问/撤销时间。它是订阅与设备的受控关系,不是把个人身份写回公共订阅。
|
||||
|
||||
建议管理接口:
|
||||
|
||||
- `GET/POST /api/wg/devices`、`GET/PATCH /api/wg/devices/:id`。
|
||||
- `POST /api/wg/devices/:id/actions`、`GET /api/wg/jobs/:id`。
|
||||
- `GET /api/wg/gateways`。
|
||||
- `POST /api/tokens/:id/wg-bindings`:沿用现有 `/api/tokens` 资源命名,校验设备权限,签发/复用当前组合凭证;选择变化时不改默认订阅。接口已部署,生产验证见实现记录。
|
||||
- `POST /api/wg/devices/:id/exports`:授权领取标准配置或生成短期接入票据。
|
||||
- 公开受凭证保护的拉取入口为原 `/sub/:token/surge` 加可选 `wg`;签名错误、跨订阅使用、暂停或归档明确拒绝,不降级泄露或换身份。
|
||||
|
||||
默认托管模式由服务端生成独立密钥、加密保存,再通过授权的 HTTPS 分发。不能声称私钥永不离开设备;若未来增加设备端生成,需要单独实现客户端公钥登记流程。
|
||||
|
||||
网关 agent 使用独立认证主动 HTTPS 上报,不持有全站管理员 token。受限 helper 只操作固定 WG 接口,不接受任意 shell。配置更新原子持久化、幂等重试、合并受管 peer,避免重启隧道或删除非受管设备。
|
||||
|
||||
## 迁移与验收
|
||||
|
||||
先备份,再按网关公钥与客户端公钥纳管现有 Mac/iPad,保留 key、PSK、IP、MTU 和现有连接。只读采集先行,不因平台迁移重建 peer。
|
||||
|
||||
现有独立 WG token/旧导出 URL 保留明确的兼容映射,避免立即中断已安装设备;默认共享 URL 保持纯代理。迁移到新方式时,在同一个订阅页选择对应设备,导入带凭证的派生 URL。默认公共地址不失效,但需要 WG 身份的设备托管地址会增加设备参数,这是本设计的明确行为。
|
||||
|
||||
实施顺序:只读纳管与采集 → 新增/暂停/恢复/独立导出 → 订阅设备绑定与 Surge 生成 → 三端更新、入站与跨 ISP 远程桌面验收。不因原型完成而声称全部客户端媒体能力已验收。
|
||||
|
||||
关键验收:
|
||||
|
||||
1. 未选设备时响应完全无 WG,原默认 URL 保持不变。
|
||||
2. Mac、iPad、iPhone 的派生 URL 各只包含本机身份;选择 B 不改变已生成的 A 链接。
|
||||
3. 没有私密设备凭证、篡改设备 ID、跨订阅复用凭证均不能读到私钥。
|
||||
4. 托管 header 保留完整设备 URL,更新/重启后不丢 WG;清除网页选择不撤销已有设备链接。
|
||||
5. 网关确认前不假成功,失败重试不重复创建,暂停后真实网络不可达,采集失联不显示旧在线/速率。
|
||||
6. 独立导出与 Surge 引用同一身份;设备暂停、移除、重置与失效链接行为一致。
|
||||
7. 现有设备不断线纳管;原公网分流行为不因附加 WG 扩大或改变。
|
||||
|
||||
## 可点击原型与验证
|
||||
|
||||
交互源文件:[wg-device-management.html](wg-device-management.html)。默认打开订阅页,可进入设备列表和详情。所有 URL、设备状态、导出、导入和握手为演示,不发生产请求。
|
||||
|
||||
主要体验路径:Surge 订阅 → 选择设备 → 查看带身份链接及结构 → 清除选择恢复纯代理。设备页可新增、详情查看、复制 IP、暂停/恢复、重置/移除及导出独立 WG 配置。
|
||||
|
||||
本次浏览器实际检查通过:
|
||||
|
||||
- 未选设备、选择 Mac、选择 iPad、清除选择,以及切换非 Surge 格式后的链接与配置结构变化。
|
||||
- 选中 Mac 的结构仅包含 .3,选中 iPad 仅包含 .2;托管更新 header 保留当前带设备凭证的完整 URL。
|
||||
- 新增设备不再出现客户端选择;创建后即出现在订阅下拉中,未握手仍为待接入;模拟握手后才显示在线。
|
||||
- 从设备详情导出独立 WG 配置保留同一 IP;暂停后禁止继续生成接入链接。
|
||||
- 移除已选设备后旧链接保持明确不可用,清除选择才回到纯代理;没有自动切换身份或静默降级。
|
||||
- 订阅页与独立导出页在 320、360、736、1024 宽度均无横向溢出,深色外观可用。
|
||||
- JavaScript 语法、片段结构与无网络请求检查通过;最终浏览器检查无控制台错误。
|
||||
|
||||
以上仅验证原型交互与演示结构。真实凭证授权、网关生命周期和三端订阅结果属于实施验收。
|
||||
|
||||
参考:[Surge WireGuard](https://manual.nssurge.com/policies/wireguard.html)、[托管配置更新](https://manual.nssurge.com/profile/managed-profile.html)、[WireGuard 工具与状态](https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8)、[现有组网记录](../../WIREGUARD-LAN.md)。
|
||||
Reference in New Issue
Block a user