feat: 配对管理端点与中继侧设备注册上报
- agent --pair:临时监听 :3001 仅开放 /provision 与 /destroy,以节点密码为共享秘密; 窗口由三个独立条件关闭(首次成功配对 / 失败尝试 10 次 / 10 分钟超时),配对成功后 管理监听即关(设计 §7 第 4 步) - agent 为每台配对手机生成中继 bearer(config.Save 0600 原子写;启动时为手写条目补发) - transport.PushDevices:握手成功后全量上报本节点受信设备集;空集是吊销声明而非无操作 - relay /v1/agent/devices:agent 会话后鉴权的设备注册;全量替换本节点条目; 操作员 MSA_DEVICES 为 static 不可被覆盖;跨节点 id 不可抢占 - 中继设备注册替代了 §11 第 6 项的一部分:节点 destroy + 重握手即可在路由层吊销 - 配置:provisionSecret 字段(无密码保护节点需显式设置才可配对);Validate(pairMode) - 测试:pair 流程 8 项、设备注册 6 项、transport 1 项;文档 §7 实现修订注记与 README 状态
This commit is contained in:
@@ -27,9 +27,10 @@ import (
|
||||
|
||||
// Paths on the relay. Versioned, because an agent and a relay will not be upgraded on the same day.
|
||||
const (
|
||||
PathHello = "/v1/agent/hello"
|
||||
PathPoll = "/v1/agent/poll"
|
||||
PathResult = "/v1/agent/result"
|
||||
PathHello = "/v1/agent/hello"
|
||||
PathPoll = "/v1/agent/poll"
|
||||
PathResult = "/v1/agent/result"
|
||||
PathDevices = "/v1/agent/devices"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -196,6 +197,25 @@ func (c *Client) Result(ctx context.Context, envelope json.RawMessage) error {
|
||||
|
||||
func (c *Client) session() string { return c.token }
|
||||
|
||||
// DeviceRegistration is one paired phone as the relay needs to know it: the bearer token the phone
|
||||
// presents, minted by the agent at pairing time and never seen by the relay before that moment.
|
||||
type DeviceRegistration struct {
|
||||
App string `json:"app"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// PushDevices reports the node's complete paired-device set after the handshake.
|
||||
//
|
||||
// Full set, not a delta: the relay replaces everything it holds for this node, which is what makes
|
||||
// revocation work without a second channel. Destroying the device list (or re-pairing) and letting
|
||||
// the next hello carry the smaller set removes the revoked bearer from the relay's routing, and an
|
||||
// agent that never reconnects cannot revoke anything but is also unable to command itself.
|
||||
func (c *Client) PushDevices(ctx context.Context, devices []DeviceRegistration) error {
|
||||
return c.post(ctx, PathDevices, map[string]any{
|
||||
"node": c.nodeID, "devices": devices,
|
||||
}, &json.RawMessage{}, c.session(), false)
|
||||
}
|
||||
|
||||
// post is the single place a relay request is made, so authentication, size limits, status mapping
|
||||
// and body draining cannot drift between the three endpoints.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user