@mebular/fleet 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/agentdir.d.ts +43 -0
  2. package/dist/agentdir.d.ts.map +1 -0
  3. package/dist/agentdir.js +107 -0
  4. package/dist/agentdir.js.map +1 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +1135 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/collab/chatter.d.ts +54 -0
  10. package/dist/collab/chatter.d.ts.map +1 -0
  11. package/dist/collab/chatter.js +94 -0
  12. package/dist/collab/chatter.js.map +1 -0
  13. package/dist/collab/dag.d.ts +27 -0
  14. package/dist/collab/dag.d.ts.map +1 -0
  15. package/dist/collab/dag.js +107 -0
  16. package/dist/collab/dag.js.map +1 -0
  17. package/dist/collab/negotiation.d.ts +60 -0
  18. package/dist/collab/negotiation.d.ts.map +1 -0
  19. package/dist/collab/negotiation.js +90 -0
  20. package/dist/collab/negotiation.js.map +1 -0
  21. package/dist/collab/tree.d.ts +39 -0
  22. package/dist/collab/tree.d.ts.map +1 -0
  23. package/dist/collab/tree.js +177 -0
  24. package/dist/collab/tree.js.map +1 -0
  25. package/dist/config.d.ts +123 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/config.js +206 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/index.d.ts +33 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +40 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/join.d.ts +50 -0
  34. package/dist/join.d.ts.map +1 -0
  35. package/dist/join.js +167 -0
  36. package/dist/join.js.map +1 -0
  37. package/dist/jointoken.d.ts +144 -0
  38. package/dist/jointoken.d.ts.map +1 -0
  39. package/dist/jointoken.js +472 -0
  40. package/dist/jointoken.js.map +1 -0
  41. package/dist/model.d.ts +64 -0
  42. package/dist/model.d.ts.map +1 -0
  43. package/dist/model.js +158 -0
  44. package/dist/model.js.map +1 -0
  45. package/dist/onboard.d.ts +90 -0
  46. package/dist/onboard.d.ts.map +1 -0
  47. package/dist/onboard.js +510 -0
  48. package/dist/onboard.js.map +1 -0
  49. package/dist/protocol/envelope.d.ts +94 -0
  50. package/dist/protocol/envelope.d.ts.map +1 -0
  51. package/dist/protocol/envelope.js +169 -0
  52. package/dist/protocol/envelope.js.map +1 -0
  53. package/dist/protocol/events.d.ts +51 -0
  54. package/dist/protocol/events.d.ts.map +1 -0
  55. package/dist/protocol/events.js +87 -0
  56. package/dist/protocol/events.js.map +1 -0
  57. package/dist/qr.d.ts +15 -0
  58. package/dist/qr.d.ts.map +1 -0
  59. package/dist/qr.js +52 -0
  60. package/dist/qr.js.map +1 -0
  61. package/dist/quickstart.d.ts +167 -0
  62. package/dist/quickstart.d.ts.map +1 -0
  63. package/dist/quickstart.js +482 -0
  64. package/dist/quickstart.js.map +1 -0
  65. package/dist/quota.d.ts +41 -0
  66. package/dist/quota.d.ts.map +1 -0
  67. package/dist/quota.js +84 -0
  68. package/dist/quota.js.map +1 -0
  69. package/dist/runtime/agent.d.ts +100 -0
  70. package/dist/runtime/agent.d.ts.map +1 -0
  71. package/dist/runtime/agent.js +260 -0
  72. package/dist/runtime/agent.js.map +1 -0
  73. package/dist/runtime/executor.d.ts +42 -0
  74. package/dist/runtime/executor.d.ts.map +1 -0
  75. package/dist/runtime/executor.js +87 -0
  76. package/dist/runtime/executor.js.map +1 -0
  77. package/dist/runtime/fairness.d.ts +25 -0
  78. package/dist/runtime/fairness.d.ts.map +1 -0
  79. package/dist/runtime/fairness.js +79 -0
  80. package/dist/runtime/fairness.js.map +1 -0
  81. package/dist/runtime/node.d.ts +91 -0
  82. package/dist/runtime/node.d.ts.map +1 -0
  83. package/dist/runtime/node.js +203 -0
  84. package/dist/runtime/node.js.map +1 -0
  85. package/dist/runtime/openchamber-http.d.ts +27 -0
  86. package/dist/runtime/openchamber-http.d.ts.map +1 -0
  87. package/dist/runtime/openchamber-http.js +118 -0
  88. package/dist/runtime/openchamber-http.js.map +1 -0
  89. package/dist/runtime/openchamber.d.ts +38 -0
  90. package/dist/runtime/openchamber.d.ts.map +1 -0
  91. package/dist/runtime/openchamber.js +43 -0
  92. package/dist/runtime/openchamber.js.map +1 -0
  93. package/dist/runtime/planner.d.ts +23 -0
  94. package/dist/runtime/planner.d.ts.map +1 -0
  95. package/dist/runtime/planner.js +17 -0
  96. package/dist/runtime/planner.js.map +1 -0
  97. package/dist/runtime/worker.d.ts +96 -0
  98. package/dist/runtime/worker.d.ts.map +1 -0
  99. package/dist/runtime/worker.js +296 -0
  100. package/dist/runtime/worker.js.map +1 -0
  101. package/dist/security.d.ts +462 -0
  102. package/dist/security.d.ts.map +1 -0
  103. package/dist/security.js +1197 -0
  104. package/dist/security.js.map +1 -0
  105. package/dist/store/daemon-store.d.ts +33 -0
  106. package/dist/store/daemon-store.d.ts.map +1 -0
  107. package/dist/store/daemon-store.js +115 -0
  108. package/dist/store/daemon-store.js.map +1 -0
  109. package/dist/store/file-store.d.ts +22 -0
  110. package/dist/store/file-store.d.ts.map +1 -0
  111. package/dist/store/file-store.js +63 -0
  112. package/dist/store/file-store.js.map +1 -0
  113. package/dist/store/mebular-store.d.ts +22 -0
  114. package/dist/store/mebular-store.d.ts.map +1 -0
  115. package/dist/store/mebular-store.js +53 -0
  116. package/dist/store/mebular-store.js.map +1 -0
  117. package/dist/store/message-store.d.ts +26 -0
  118. package/dist/store/message-store.d.ts.map +1 -0
  119. package/dist/store/message-store.js +51 -0
  120. package/dist/store/message-store.js.map +1 -0
  121. package/dist/surface.d.ts +43 -0
  122. package/dist/surface.d.ts.map +1 -0
  123. package/dist/surface.js +515 -0
  124. package/dist/surface.js.map +1 -0
  125. package/dist/transport/null.d.ts +7 -0
  126. package/dist/transport/null.d.ts.map +1 -0
  127. package/dist/transport/null.js +16 -0
  128. package/dist/transport/null.js.map +1 -0
  129. package/dist/transport/spool.d.ts +12 -0
  130. package/dist/transport/spool.d.ts.map +1 -0
  131. package/dist/transport/spool.js +54 -0
  132. package/dist/transport/spool.js.map +1 -0
  133. package/dist/transport/types.d.ts +21 -0
  134. package/dist/transport/types.d.ts.map +1 -0
  135. package/dist/transport/types.js +6 -0
  136. package/dist/transport/types.js.map +1 -0
  137. package/dist/version.json +6 -0
  138. package/package.json +37 -4
  139. package/protocol/collab.example.json +23 -0
  140. package/protocol/daemon-home.example.json +66 -0
  141. package/protocol/envelope.example.json +12 -0
  142. package/protocol/state-machine.json +14 -0
  143. package/protocol/task-tree.example.json +72 -0
  144. package/src/agentdir.ts +138 -0
  145. package/src/cli.ts +1192 -0
  146. package/src/collab/chatter.ts +116 -0
  147. package/src/collab/dag.ts +124 -0
  148. package/src/collab/negotiation.ts +130 -0
  149. package/src/collab/tree.ts +184 -0
  150. package/src/config.ts +286 -0
  151. package/src/index.ts +39 -0
  152. package/src/join.ts +227 -0
  153. package/src/jointoken.ts +609 -0
  154. package/src/model.ts +203 -0
  155. package/src/onboard.ts +601 -0
  156. package/src/protocol/envelope.ts +228 -0
  157. package/src/protocol/events.ts +135 -0
  158. package/src/qr.ts +68 -0
  159. package/src/quickstart.ts +632 -0
  160. package/src/quota.ts +112 -0
  161. package/src/runtime/agent.ts +313 -0
  162. package/src/runtime/executor.ts +114 -0
  163. package/src/runtime/fairness.ts +90 -0
  164. package/src/runtime/node.ts +250 -0
  165. package/src/runtime/openchamber-http.ts +137 -0
  166. package/src/runtime/openchamber.ts +66 -0
  167. package/src/runtime/planner.ts +36 -0
  168. package/src/runtime/worker.ts +354 -0
  169. package/src/security.ts +1660 -0
  170. package/src/store/daemon-store.ts +144 -0
  171. package/src/store/file-store.ts +75 -0
  172. package/src/store/mebular-store.ts +66 -0
  173. package/src/store/message-store.ts +62 -0
  174. package/src/surface.ts +535 -0
  175. package/src/transport/null.ts +20 -0
  176. package/src/transport/spool.ts +62 -0
  177. package/src/transport/types.ts +27 -0
  178. package/README.md +0 -3
@@ -0,0 +1,472 @@
1
+ // 信任模型 v2(T2):加入令牌 + join 请求-签发(**embedded / test-only**)。
2
+ //
3
+ // W2 起:**生产 join 由守护托管**(`mebular serve` 的 `/mebular/join`,见 packages/mcp/src/jointoken.mjs);
4
+ // F-UNI:本文件是**唯一实现**——守护(`mebular serve` 的 join 服务)经 `@mebular/mcp` 薄 re-export 直接使用;
5
+ // `fleet` CLI 的 embedded 自托管路径(`fleet node --join-serve`)仅供测试/CI。
6
+ //
7
+ // 设计(含用户修正:去中心化):
8
+ // - **任意**在册设备都可作 inviter(无“指定主设备/CA”);令牌由**inviter 设备私钥**签名。
9
+ // - 令牌只含**授权信息**(inviter 身份/证书链、用户主公钥、命名空间、nonce、TTL、endpoint),
10
+ // **绝不含主密钥私钥**;主密钥可完全离线。
11
+ // - 过期(TTL)/ 一次性(nonce 已用)/ 被撕(显式撤销)三种吊销与**设备证书吊销**(`device_revoke` 级联)
12
+ // 分开:前者是准入凭据,后者是身份失效。
13
+ // - 服务端验令牌后,用 inviter 设备私钥为请求设备签发**委派证书**(1 跳;链上界由 core 强制)。
14
+ import { chmod, mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from 'node:fs/promises';
15
+ import http, { createServer } from 'node:http';
16
+ import https from 'node:https';
17
+ import { createHash, randomBytes } from 'node:crypto';
18
+ import { dirname } from 'node:path';
19
+ import { bytesToBase64, bytesToHex, hexToBytes, base64ToBytes, canonicalCertificateData, verifyCertificateChain, } from '@mebular/core';
20
+ /** 令牌规范化签名内容(固定键序,排除 signature)。 */
21
+ export function canonicalJoinTokenData(token) {
22
+ // 注意:键序固定;C2 可选 hints 仅在存在时进入签名体 → 旧令牌(无 hints)签名不变,向后兼容。
23
+ return JSON.stringify({
24
+ v: token.v,
25
+ kind: token.kind,
26
+ inviterDeviceId: token.inviterDeviceId,
27
+ inviterPublicKey: token.inviterPublicKey,
28
+ inviterChain: token.inviterChain,
29
+ masterPublicKey: token.masterPublicKey,
30
+ namespace: token.namespace,
31
+ nonce: token.nonce,
32
+ issuedAt: token.issuedAt,
33
+ expiresAt: token.expiresAt,
34
+ endpoint: token.endpoint,
35
+ ...(token.endpoints !== undefined ? { endpoints: token.endpoints } : {}),
36
+ ...(token.relaySeeds !== undefined ? { relaySeeds: token.relaySeeds } : {}),
37
+ ...(token.pubReachable !== undefined ? { pubReachable: token.pubReachable } : {}),
38
+ ...(token.securityApproval !== undefined ? { securityApproval: token.securityApproval } : {}),
39
+ });
40
+ }
41
+ export function encodeJoinToken(token) {
42
+ return Buffer.from(JSON.stringify(token), 'utf-8').toString('base64');
43
+ }
44
+ export function decodeJoinToken(text) {
45
+ const trimmed = text.trim();
46
+ if (trimmed.length === 0)
47
+ throw new Error('令牌为空');
48
+ const json = trimmed.startsWith('{') ? trimmed : Buffer.from(trimmed, 'base64').toString('utf-8');
49
+ let parsed;
50
+ try {
51
+ parsed = JSON.parse(json);
52
+ }
53
+ catch {
54
+ throw new Error('令牌无法解析(既非 base64 也非 JSON)');
55
+ }
56
+ const t = parsed;
57
+ if (t.v !== 1 || t.kind !== 'mebular-fleet-join-token')
58
+ throw new Error('令牌版本/类型不受支持');
59
+ for (const key of ['inviterDeviceId', 'inviterPublicKey', 'masterPublicKey', 'namespace', 'nonce', 'endpoint', 'signature']) {
60
+ if (typeof t[key] !== 'string')
61
+ throw new Error(`令牌缺少字段:${key}`);
62
+ }
63
+ if (typeof t.issuedAt !== 'number' || typeof t.expiresAt !== 'number')
64
+ throw new Error('令牌时间字段非法');
65
+ if (!Array.isArray(t.inviterChain) || t.inviterChain.length === 0)
66
+ throw new Error('令牌缺少 inviter 证书链');
67
+ // C2:可选 hints 的形状校验(缺省合法;非法即拒,避免半截数据流入地址簿)
68
+ if (t.endpoints !== undefined && (!Array.isArray(t.endpoints) || t.endpoints.some((e) => typeof e !== 'string'))) {
69
+ throw new Error('令牌 endpoints 形状非法(应为字符串数组)');
70
+ }
71
+ if (t.relaySeeds !== undefined && (!Array.isArray(t.relaySeeds) || t.relaySeeds.some((e) => typeof e !== 'string'))) {
72
+ throw new Error('令牌 relaySeeds 形状非法(应为字符串数组)');
73
+ }
74
+ if (t.pubReachable !== undefined && typeof t.pubReachable !== 'boolean') {
75
+ throw new Error('令牌 pubReachable 形状非法(应为布尔)');
76
+ }
77
+ if (t.securityApproval !== undefined) {
78
+ const approval = t.securityApproval;
79
+ if (approval === null || typeof approval !== 'object'
80
+ || typeof approval.approvalId !== 'string' || typeof approval.nonce !== 'string') {
81
+ throw new Error('令牌 securityApproval 形状非法');
82
+ }
83
+ }
84
+ return t;
85
+ }
86
+ /** 脱敏描述:**不含签名**,供日志/报告。 */
87
+ export function describeJoinToken(token) {
88
+ return {
89
+ v: token.v,
90
+ kind: token.kind,
91
+ inviterDeviceId: token.inviterDeviceId,
92
+ namespace: token.namespace,
93
+ nonce: token.nonce,
94
+ issuedAt: token.issuedAt,
95
+ expiresAt: token.expiresAt,
96
+ endpoint: token.endpoint,
97
+ chainLen: token.inviterChain.length,
98
+ hasMasterPrivateKey: false,
99
+ };
100
+ }
101
+ export function joinNonceStatePath(storagePath) {
102
+ return `${storagePath}.join-tokens.json`;
103
+ }
104
+ export async function readJoinNonceState(storagePath) {
105
+ try {
106
+ const parsed = JSON.parse(await readFile(joinNonceStatePath(storagePath), 'utf-8'));
107
+ return {
108
+ used: Array.isArray(parsed.used) ? parsed.used : [],
109
+ revoked: Array.isArray(parsed.revoked) ? parsed.revoked : [],
110
+ ...(typeof parsed.active === 'string' ? { active: parsed.active } : {}),
111
+ };
112
+ }
113
+ catch {
114
+ return { used: [], revoked: [] };
115
+ }
116
+ }
117
+ export async function writeJoinNonceState(storagePath, state) {
118
+ const path = joinNonceStatePath(storagePath);
119
+ await mkdir(dirname(path), { recursive: true });
120
+ // tmp + rename:进程在写盘中途退出也不会留下半截状态(used/revoked 丢失会重新放行旧令牌)。
121
+ const tmp = `${path}.tmp-${process.pid}-${randomBytes(4).toString('hex')}`;
122
+ try {
123
+ await writeFile(tmp, JSON.stringify(state, null, 2), { mode: 0o600 });
124
+ await rename(tmp, path);
125
+ }
126
+ catch (error) {
127
+ await rm(tmp, { force: true }).catch(() => undefined);
128
+ throw error;
129
+ }
130
+ try {
131
+ await chmod(path, 0o600);
132
+ }
133
+ catch {
134
+ // Windows 无 POSIX mode;忽略
135
+ }
136
+ }
137
+ /**
138
+ * 激活新邀请 nonce:把上一个 active 放入 revoked,再落盘新 active。
139
+ * 生成与兑换共用同一把锁(同进程内存队列 + <state>.lock 跨进程),避免并发丢更新。
140
+ */
141
+ export async function activateJoinInvite(storagePath, nonce) {
142
+ if (typeof nonce !== 'string' || !/^[0-9a-f]{32}$/.test(nonce))
143
+ throw new Error('邀请 nonce 非法');
144
+ return withNonceLock(storagePath, async () => {
145
+ const state = await readJoinNonceState(storagePath);
146
+ const previous = state.active;
147
+ let revoked = null;
148
+ if (previous !== undefined && previous !== nonce && !state.used.includes(previous) && !state.revoked.includes(previous)) {
149
+ state.revoked.push(previous);
150
+ revoked = previous;
151
+ }
152
+ state.active = nonce;
153
+ await writeJoinNonceState(storagePath, state);
154
+ return { revoked };
155
+ });
156
+ }
157
+ /** 签发令牌(inviter 设备私钥)。 */
158
+ export async function buildJoinToken(input) {
159
+ const identity = input.mebular.identity.getDeviceKey(input.deviceId);
160
+ if (!identity)
161
+ throw new Error(`本机无设备密钥:${input.deviceId}`);
162
+ const chain = identity.certificateChain ?? (identity.certificate ? [identity.certificate] : []);
163
+ if (chain.length === 0)
164
+ throw new Error('本机无有效证书链,无法签发令牌(先 onboard/join)');
165
+ const masterPub = input.mebular.identity.getUserMasterPublicKey();
166
+ if (!masterPub)
167
+ throw new Error('本机无用户主公钥,无法签发令牌');
168
+ const now = input.now ?? Date.now();
169
+ const unsigned = {
170
+ v: 1,
171
+ kind: 'mebular-fleet-join-token',
172
+ inviterDeviceId: input.deviceId,
173
+ inviterPublicKey: bytesToHex(identity.publicKey),
174
+ inviterChain: chain,
175
+ masterPublicKey: bytesToHex(masterPub),
176
+ namespace: input.namespace,
177
+ nonce: input.nonce ?? randomBytes(16).toString('hex'),
178
+ issuedAt: now,
179
+ expiresAt: now + (input.ttlMs ?? 900_000),
180
+ endpoint: input.endpoint,
181
+ };
182
+ // C2:自动收集本机可达 P2P 地址(缺省),显式传入优先;空则不写字段(与旧令牌等价)
183
+ const endpoints = input.endpoints ?? collectReachableEndpoints(input.mebular);
184
+ const relaySeeds = input.relaySeeds ?? collectRelaySeeds(input.mebular);
185
+ if (endpoints.length > 0)
186
+ unsigned.endpoints = endpoints;
187
+ if (relaySeeds.length > 0)
188
+ unsigned.relaySeeds = relaySeeds;
189
+ const pubReachable = input.pubReachable ?? endpoints.some((addr) => !isLoopbackAddress(addr));
190
+ if (endpoints.length > 0 || input.pubReachable !== undefined)
191
+ unsigned.pubReachable = pubReachable;
192
+ if (input.securityApproval !== undefined)
193
+ unsigned.securityApproval = input.securityApproval;
194
+ const signature = await globalThis.crypto.subtle.sign({ name: 'Ed25519' }, identity.privateKey, new TextEncoder().encode(canonicalJoinTokenData(unsigned)));
195
+ return { ...unsigned, signature: bytesToBase64(new Uint8Array(signature)) };
196
+ }
197
+ /** C2:本机可达 P2P 地址(节点监听 + /p2p/<peerId>;无节点则空)。 */
198
+ export function collectReachableEndpoints(mebular) {
199
+ const node = mebular.node;
200
+ if (!node || !node.isRunning())
201
+ return [];
202
+ const peerId = node.peerId?.id;
203
+ const addrs = node.getLocalMultiaddrs?.() ?? [];
204
+ const out = [];
205
+ for (const addr of addrs) {
206
+ if (typeof addr !== 'string' || addr.includes('/p2p-circuit'))
207
+ continue;
208
+ const withPeer = /\/p2p\//.test(addr) || !peerId ? addr : `${addr}/p2p/${peerId}`;
209
+ if (!out.includes(withPeer))
210
+ out.push(withPeer);
211
+ }
212
+ return out;
213
+ }
214
+ /**
215
+ * C2:可共享的 relay seeds(供新设备在无法直连时中转)。
216
+ * app 已把 `network.relaySeeds` 并入 `network.libp2p.relayServers`,此处经公开 getter 读取。
217
+ */
218
+ export function collectRelaySeeds(mebular) {
219
+ const seeds = mebular.relayServers;
220
+ return Array.isArray(seeds) ? seeds.filter((entry) => typeof entry === 'string' && entry.length > 0) : [];
221
+ }
222
+ /** 地址是否为回环(用于 pubReachable 提示;判断失败按回环处理)。 */
223
+ export function isLoopbackAddress(address) {
224
+ const host = /\/(?:ip4|ip6|dns4|dns6|dns)\/([^/]+)/.exec(address)?.[1] ?? '';
225
+ return ['127.0.0.1', '::1', 'localhost', ''].includes(host) || host.startsWith('127.');
226
+ }
227
+ /** 校验令牌:签名 → 链锚定主密钥 → inviter 匹配 → TTL → 一次性 → 撕票。 */
228
+ export async function verifyJoinToken(token, opts = {}) {
229
+ // 1) 签名(inviter 设备公钥)
230
+ try {
231
+ const key = await globalThis.crypto.subtle.importKey('raw', hexToBytes(token.inviterPublicKey).buffer, { name: 'Ed25519' }, false, ['verify']);
232
+ const ok = await globalThis.crypto.subtle.verify({ name: 'Ed25519' }, key, base64ToBytes(token.signature).buffer, new TextEncoder().encode(canonicalJoinTokenData(token)));
233
+ if (!ok)
234
+ return { ok: false, reason: 'signature' };
235
+ }
236
+ catch {
237
+ return { ok: false, reason: 'signature' };
238
+ }
239
+ // 2) inviter 证书链锚定主密钥
240
+ const chainOk = await verifyCertificateChain(token.inviterChain, hexToBytes(token.masterPublicKey), {
241
+ subjectDeviceId: token.inviterDeviceId,
242
+ });
243
+ if (!chainOk)
244
+ return { ok: false, reason: 'chain' };
245
+ // 3) inviter 匹配
246
+ if (opts.expectedInviter !== undefined && token.inviterDeviceId !== opts.expectedInviter) {
247
+ return { ok: false, reason: 'inviter' };
248
+ }
249
+ // 4) TTL(inviter/服务端时钟为准)
250
+ const now = opts.now ?? Date.now();
251
+ if (!(now <= token.expiresAt))
252
+ return { ok: false, reason: 'expired' };
253
+ // 5) 一次性 / 撕票
254
+ if ((opts.used ?? []).includes(token.nonce))
255
+ return { ok: false, reason: 'used' };
256
+ if ((opts.revoked ?? []).includes(token.nonce))
257
+ return { ok: false, reason: 'revoked' };
258
+ return { ok: true };
259
+ }
260
+ /** inviter 证书链的指纹(诊断/去重;非密钥材料)。 */
261
+ export function chainFingerprint(chain) {
262
+ const leaf = chain[0];
263
+ const material = canonicalCertificateData(leaf) + (chain[chain.length - 1]?.deviceId ?? '');
264
+ return `sha256:${createHash('sha256').update(material).digest('hex').slice(0, 12)}`;
265
+ }
266
+ function readBody(req, limitBytes = 256 * 1024) {
267
+ return new Promise((resolve, reject) => {
268
+ let data = '';
269
+ req.on('data', (chunk) => {
270
+ data += chunk.toString('utf-8');
271
+ if (data.length > limitBytes) {
272
+ reject(new Error('请求体过大'));
273
+ req.destroy();
274
+ }
275
+ });
276
+ req.on('end', () => resolve(data));
277
+ req.on('error', reject);
278
+ });
279
+ }
280
+ function sendJson(res, status, body) {
281
+ const text = JSON.stringify(body);
282
+ res.writeHead(status, { 'content-type': 'application/json' });
283
+ res.end(text);
284
+ }
285
+ /**
286
+ * 启动 join 服务:`POST /mebular/join {token, deviceId, devicePublicKey}` → 验令牌后签发**委派证书**。
287
+ * `GET /mebular/ping` 用于就绪探测。**不接收、不返回任何主密钥材料**。
288
+ */
289
+ /**
290
+ * 每 storagePath 的非一路串行锁:同进程内存队列 + 跨进程 `<state>.lock`。
291
+ * 令牌「先占用后签发」与「生成新令牌时撤销旧 active」共用此锁,避免并发丢更新。
292
+ */
293
+ const nonceLocks = new Map();
294
+ /** 跨进程文件锁;持有时间应远小于 10s,陈旧锁(PID 已退出或超时)自动回收。 */
295
+ async function acquireNonceFileLock(storagePath) {
296
+ const path = `${joinNonceStatePath(storagePath)}.lock`;
297
+ await mkdir(dirname(path), { recursive: true });
298
+ const deadline = Date.now() + 5_000;
299
+ for (;;) {
300
+ try {
301
+ const handle = await open(path, 'wx', 0o600);
302
+ try {
303
+ await handle.writeFile(JSON.stringify({ pid: process.pid, at: Date.now() }));
304
+ }
305
+ finally {
306
+ await handle.close();
307
+ }
308
+ return async () => {
309
+ await unlink(path).catch(() => undefined);
310
+ };
311
+ }
312
+ catch (error) {
313
+ if (error.code !== 'EEXIST')
314
+ throw error;
315
+ }
316
+ let stale = false;
317
+ try {
318
+ const info = JSON.parse(await readFile(path, 'utf-8'));
319
+ if (typeof info.pid === 'number' && info.pid !== process.pid) {
320
+ try {
321
+ process.kill(info.pid, 0);
322
+ }
323
+ catch (error) {
324
+ if (error.code === 'ESRCH')
325
+ stale = true;
326
+ }
327
+ }
328
+ const lockStat = await stat(path);
329
+ if (Date.now() - lockStat.mtimeMs > 10_000)
330
+ stale = true;
331
+ }
332
+ catch {
333
+ // 锁文件可能刚被释放或尚未写完:下一轮重试
334
+ }
335
+ if (stale) {
336
+ await unlink(path).catch(() => undefined);
337
+ continue;
338
+ }
339
+ if (Date.now() >= deadline)
340
+ throw new Error('加入令牌状态被其他进程占用,请稍后重试');
341
+ await new Promise((resolve) => setTimeout(resolve, 10));
342
+ }
343
+ }
344
+ function withNonceLock(key, fn) {
345
+ const prev = nonceLocks.get(key) ?? Promise.resolve();
346
+ const run = prev.then(async () => {
347
+ const release = await acquireNonceFileLock(key);
348
+ try {
349
+ return await fn();
350
+ }
351
+ finally {
352
+ await release();
353
+ }
354
+ });
355
+ nonceLocks.set(key, run.then(() => undefined, () => undefined));
356
+ return run;
357
+ }
358
+ export async function startJoinService(opts) {
359
+ const bind = opts.bind ?? '0.0.0.0';
360
+ const server = createServer((req, res) => {
361
+ void (async () => {
362
+ try {
363
+ if (req.method === 'GET' && req.url === '/mebular/ping') {
364
+ sendJson(res, 200, { ok: true, deviceId: opts.deviceId });
365
+ return;
366
+ }
367
+ if (req.method !== 'POST' || req.url !== '/mebular/join') {
368
+ sendJson(res, 404, { ok: false, error: 'not found' });
369
+ return;
370
+ }
371
+ const body = JSON.parse(await readBody(req));
372
+ if (typeof body.token !== 'string' || typeof body.deviceId !== 'string' || typeof body.devicePublicKey !== 'string') {
373
+ sendJson(res, 400, { ok: false, error: '缺少 token/deviceId/devicePublicKey' });
374
+ return;
375
+ }
376
+ const token = decodeJoinToken(body.token);
377
+ const deviceId = body.deviceId;
378
+ const devicePublicKey = body.devicePublicKey;
379
+ if (!/^[0-9a-fA-F]{64}$/.test(devicePublicKey)) {
380
+ sendJson(res, 400, { ok: false, error: 'devicePublicKey 必须为 32 字节 hex' });
381
+ return;
382
+ }
383
+ // F-2:令牌「一次性」在**单服务进程内**原子(先占用后签发),并发不再重复签发。
384
+ await withNonceLock(opts.storagePath, async () => {
385
+ const state = await readJoinNonceState(opts.storagePath);
386
+ const verdict = await verifyJoinToken(token, {
387
+ used: state.used,
388
+ revoked: state.revoked,
389
+ expectedInviter: opts.deviceId,
390
+ });
391
+ if (!verdict.ok) {
392
+ sendJson(res, 403, { ok: false, error: `令牌不可用:${verdict.reason}` });
393
+ return;
394
+ }
395
+ // **先占用**(落盘 used)再签发:签发失败即 fail-closed(令牌已消费,不二次签发)。
396
+ state.used.push(token.nonce);
397
+ if (state.active === token.nonce)
398
+ delete state.active;
399
+ await writeJoinNonceState(opts.storagePath, state);
400
+ try {
401
+ const issued = await opts.mebular.identity.issueDelegatedCertificateFor(deviceId, devicePublicKey, opts.deviceId);
402
+ opts.log?.(`join: issued delegated cert for ${deviceId} (nonce consumed)`);
403
+ sendJson(res, 200, {
404
+ ok: true,
405
+ certificate: issued.certificate,
406
+ chain: issued.certificateChain,
407
+ namespace: token.namespace,
408
+ inviterDeviceId: token.inviterDeviceId,
409
+ inviterMultiaddrs: opts.mebular.node?.getLocalMultiaddrs() ?? [],
410
+ ...(token.securityApproval !== undefined ? { securityApproval: token.securityApproval } : {}),
411
+ });
412
+ }
413
+ catch (error) {
414
+ opts.log?.(`join: nonce ${token.nonce} consumed but issuance failed: ${error.message}`);
415
+ sendJson(res, 500, { ok: false, error: '签发失败(令牌已消费,fail-closed)' });
416
+ }
417
+ });
418
+ }
419
+ catch (error) {
420
+ sendJson(res, 500, { ok: false, error: error.message });
421
+ }
422
+ })();
423
+ });
424
+ await new Promise((resolve, reject) => {
425
+ server.once('error', reject);
426
+ server.listen({ host: bind === '0.0.0.0' ? undefined : bind, port: opts.port }, () => resolve());
427
+ });
428
+ const addr = server.address();
429
+ const port = typeof addr === 'object' && addr !== null ? addr.port : opts.port;
430
+ return {
431
+ server,
432
+ port,
433
+ close: () => new Promise((resolve) => server.close(() => resolve())),
434
+ };
435
+ }
436
+ /** B 持令牌向 inviter 的 join 端点请求委派证书(纯 HTTP;令牌是 bearer)。 */
437
+ export async function requestJoin(input) {
438
+ const url = new URL('/mebular/join', input.endpoint);
439
+ const payload = JSON.stringify({ token: input.token, deviceId: input.deviceId, devicePublicKey: input.devicePublicKeyHex });
440
+ return await new Promise((resolve, reject) => {
441
+ const transport = url.protocol === 'https:' ? https : http;
442
+ const req = transport.request(url, { method: 'POST', headers: { 'content-type': 'application/json', 'content-length': Buffer.byteLength(payload) } }, (res) => {
443
+ let data = '';
444
+ res.on('data', (c) => (data += c.toString('utf-8')));
445
+ res.on('end', () => {
446
+ try {
447
+ const parsed = JSON.parse(data);
448
+ if (res.statusCode !== 200 || parsed.ok !== true) {
449
+ reject(new Error(`join 失败(HTTP ${res.statusCode}):${parsed.error ?? '未知错误'}`));
450
+ return;
451
+ }
452
+ resolve({
453
+ certificate: parsed.certificate,
454
+ chain: parsed.chain,
455
+ namespace: parsed.namespace,
456
+ inviterDeviceId: parsed.inviterDeviceId,
457
+ inviterMultiaddrs: parsed.inviterMultiaddrs ?? [],
458
+ ...(parsed.securityApproval !== undefined ? { securityApproval: parsed.securityApproval } : {}),
459
+ });
460
+ }
461
+ catch (error) {
462
+ reject(new Error(`join 响应无法解析:${error.message}`));
463
+ }
464
+ });
465
+ });
466
+ req.setTimeout(input.timeoutMs ?? 15_000, () => req.destroy(new Error('join 请求超时')));
467
+ req.on('error', reject);
468
+ req.write(payload);
469
+ req.end();
470
+ });
471
+ }
472
+ //# sourceMappingURL=jointoken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jointoken.js","sourceRoot":"","sources":["../src/jointoken.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { type FleetEndpoint, type FleetTrace, type TaskBudget, type TaskDispatch, type TaskStatus } from './protocol/envelope.js';
2
+ import type { TaskEvent } from './protocol/events.js';
3
+ /** 权威任务状态(由事件推导;与到达顺序无关)。 */
4
+ export interface TaskState {
5
+ taskId: string;
6
+ from: FleetEndpoint;
7
+ to: FleetEndpoint;
8
+ intent: string;
9
+ /** 任务输入负载引用(取自 `created` 事件) */
10
+ payloadRef?: string;
11
+ status: TaskStatus;
12
+ /** 已尝试次数(= 去重后 `claimed` 事件数) */
13
+ attempts: number;
14
+ /** **软约定**:仅本机展示;不参与权威判定 */
15
+ expiresAt?: number;
16
+ trace: FleetTrace;
17
+ terminal: boolean;
18
+ /** 决定 `status` 的事件 id(确定性) */
19
+ lastEventId: string;
20
+ /** `done` 时的结果引用 */
21
+ resultRef?: string;
22
+ /** `failed` 时的原因 */
23
+ reason?: string;
24
+ /** **W1**:子树预算(声明值;缺省 root 用默认、子任务按父推导——见 `collab/tree.ts`) */
25
+ budget?: TaskBudget;
26
+ /** **W1**:root 派发策略(仅 root 有意义;子任务上不参与判定) */
27
+ dispatch?: TaskDispatch;
28
+ }
29
+ /** 状态迁移是否合法(显式迁移表;`from === to` 视为幂等自迁移)。 */
30
+ export declare function validateTaskTransition(from: TaskStatus, to: TaskStatus): boolean;
31
+ /** 非法迁移则抛错(本地发起侧用;负例测试)。 */
32
+ export declare function assertTaskTransition(from: TaskStatus, to: TaskStatus): void;
33
+ /**
34
+ * 去重(按 `eventId`)。同一 `eventId` 对应**不同内容**时(违约/对抗输入),
35
+ * 按稳定序列化取字典序较大者做**确定性裁决**——使「去重后的集合」本身与输入
36
+ * 顺序无关,堵住同一 id 不同内容造成的顺序相关分叉(§2.1 顺序无关收敛)。
37
+ * 契约上 `eventId` 仍应内容寻址或全局唯一;本裁决只是兜底,不改变正常路径。
38
+ */
39
+ export declare function dedupeEvents(events: readonly TaskEvent[]): TaskEvent[];
40
+ /**
41
+ * 由事件集合推导权威状态(**顺序无关、幂等**)。无 `created` 事件 → 返回 `null`(任务未知)。
42
+ * 不读取 `at` / `now`(墙钟无关)。
43
+ */
44
+ export declare function reduceTaskEvents(events: readonly TaskEvent[]): TaskState | null;
45
+ /** 幂等应用器:按 `eventId` 去重;重复投递不改变状态、不重复执行。 */
46
+ export interface ApplyOutcome {
47
+ /** 是否为首次应用(false = 重复投递,被幂等忽略) */
48
+ applied: boolean;
49
+ state: TaskState | null;
50
+ }
51
+ export declare class IdempotentTaskApplier {
52
+ private readonly byTask;
53
+ /** 应用一个事件(首次返回 applied=true;重复返回 applied=false)。 */
54
+ apply(event: TaskEvent): ApplyOutcome;
55
+ hasApplied(taskId: string, eventId: string): boolean;
56
+ /** 是否应执行该事件对应的工作(非 `created` 且未应用过)——保证「重复投递不重复执行」。 */
57
+ shouldExecute(event: TaskEvent): boolean;
58
+ eventsOf(taskId: string): TaskEvent[];
59
+ state(taskId: string): TaskState | null;
60
+ taskIds(): string[];
61
+ }
62
+ /** 本机展示用:是否已过期(**advisory**,不参与权威判定)。 */
63
+ export declare function isExpiredLocally(expiresAt: number | undefined, now: number): boolean;
64
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,6BAA6B;AAC7B,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,aAAa,CAAC;IACpB,EAAE,EAAE,aAAa,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,6CAA6C;AAC7C,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAEhF;AAED,4BAA4B;AAC5B,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI,CAI3E;AAyBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,EAAE,CAatE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,GAAG,IAAI,CA2C/E;AAED,4CAA4C;AAC5C,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CACzB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IAEpE,oDAAoD;IACpD,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY;IAarC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAIpD,uDAAuD;IACvD,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO;IAIxC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE;IAIrC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKvC,OAAO,IAAI,MAAM,EAAE;CAGpB;AAED,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpF"}