@f2a/network 0.1.2

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 (234) hide show
  1. package/.github/workflows/ci.yml +113 -0
  2. package/.github/workflows/publish.yml +60 -0
  3. package/LICENSE +21 -0
  4. package/MONOREPO.md +58 -0
  5. package/README.md +280 -0
  6. package/SKILL.md +137 -0
  7. package/dist/adapters/openclaw.d.ts +103 -0
  8. package/dist/adapters/openclaw.d.ts.map +1 -0
  9. package/dist/adapters/openclaw.js +297 -0
  10. package/dist/adapters/openclaw.js.map +1 -0
  11. package/dist/cli/commands.d.ts +17 -0
  12. package/dist/cli/commands.d.ts.map +1 -0
  13. package/dist/cli/commands.js +107 -0
  14. package/dist/cli/commands.js.map +1 -0
  15. package/dist/cli/index.d.ts +6 -0
  16. package/dist/cli/index.d.ts.map +1 -0
  17. package/dist/cli/index.js +203 -0
  18. package/dist/cli/index.js.map +1 -0
  19. package/dist/core/autonomous-economy.d.ts +136 -0
  20. package/dist/core/autonomous-economy.d.ts.map +1 -0
  21. package/dist/core/autonomous-economy.js +255 -0
  22. package/dist/core/autonomous-economy.js.map +1 -0
  23. package/dist/core/connection-manager.d.ts +80 -0
  24. package/dist/core/connection-manager.d.ts.map +1 -0
  25. package/dist/core/connection-manager.js +235 -0
  26. package/dist/core/connection-manager.js.map +1 -0
  27. package/dist/core/connection-manager.test.d.ts +2 -0
  28. package/dist/core/connection-manager.test.d.ts.map +1 -0
  29. package/dist/core/connection-manager.test.js +52 -0
  30. package/dist/core/connection-manager.test.js.map +1 -0
  31. package/dist/core/e2ee-crypto.d.ts +90 -0
  32. package/dist/core/e2ee-crypto.d.ts.map +1 -0
  33. package/dist/core/e2ee-crypto.js +190 -0
  34. package/dist/core/e2ee-crypto.js.map +1 -0
  35. package/dist/core/f2a.d.ts +126 -0
  36. package/dist/core/f2a.d.ts.map +1 -0
  37. package/dist/core/f2a.js +425 -0
  38. package/dist/core/f2a.js.map +1 -0
  39. package/dist/core/identity.d.ts +47 -0
  40. package/dist/core/identity.d.ts.map +1 -0
  41. package/dist/core/identity.js +130 -0
  42. package/dist/core/identity.js.map +1 -0
  43. package/dist/core/identity.test.d.ts +2 -0
  44. package/dist/core/identity.test.d.ts.map +1 -0
  45. package/dist/core/identity.test.js +43 -0
  46. package/dist/core/identity.test.js.map +1 -0
  47. package/dist/core/p2p-network.d.ts +242 -0
  48. package/dist/core/p2p-network.d.ts.map +1 -0
  49. package/dist/core/p2p-network.js +1182 -0
  50. package/dist/core/p2p-network.js.map +1 -0
  51. package/dist/core/reputation-security.d.ts +168 -0
  52. package/dist/core/reputation-security.d.ts.map +1 -0
  53. package/dist/core/reputation-security.js +369 -0
  54. package/dist/core/reputation-security.js.map +1 -0
  55. package/dist/core/reputation.d.ts +179 -0
  56. package/dist/core/reputation.d.ts.map +1 -0
  57. package/dist/core/reputation.js +472 -0
  58. package/dist/core/reputation.js.map +1 -0
  59. package/dist/core/review-committee.d.ts +130 -0
  60. package/dist/core/review-committee.d.ts.map +1 -0
  61. package/dist/core/review-committee.js +251 -0
  62. package/dist/core/review-committee.js.map +1 -0
  63. package/dist/core/serverless.d.ts +155 -0
  64. package/dist/core/serverless.d.ts.map +1 -0
  65. package/dist/core/serverless.js +615 -0
  66. package/dist/core/serverless.js.map +1 -0
  67. package/dist/core/token-manager.d.ts +42 -0
  68. package/dist/core/token-manager.d.ts.map +1 -0
  69. package/dist/core/token-manager.js +122 -0
  70. package/dist/core/token-manager.js.map +1 -0
  71. package/dist/daemon/control-server.d.ts +55 -0
  72. package/dist/daemon/control-server.d.ts.map +1 -0
  73. package/dist/daemon/control-server.js +262 -0
  74. package/dist/daemon/control-server.js.map +1 -0
  75. package/dist/daemon/index.d.ts +35 -0
  76. package/dist/daemon/index.d.ts.map +1 -0
  77. package/dist/daemon/index.js +69 -0
  78. package/dist/daemon/index.js.map +1 -0
  79. package/dist/daemon/main.d.ts +6 -0
  80. package/dist/daemon/main.d.ts.map +1 -0
  81. package/dist/daemon/main.js +38 -0
  82. package/dist/daemon/main.js.map +1 -0
  83. package/dist/daemon/start.d.ts +6 -0
  84. package/dist/daemon/start.d.ts.map +1 -0
  85. package/dist/daemon/start.js +25 -0
  86. package/dist/daemon/start.js.map +1 -0
  87. package/dist/daemon/webhook.d.ts +30 -0
  88. package/dist/daemon/webhook.d.ts.map +1 -0
  89. package/dist/daemon/webhook.js +86 -0
  90. package/dist/daemon/webhook.js.map +1 -0
  91. package/dist/daemon/webhook.test.d.ts +2 -0
  92. package/dist/daemon/webhook.test.d.ts.map +1 -0
  93. package/dist/daemon/webhook.test.js +24 -0
  94. package/dist/daemon/webhook.test.js.map +1 -0
  95. package/dist/index.d.ts +24 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +25 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/protocol/messages.d.ts +739 -0
  100. package/dist/protocol/messages.d.ts.map +1 -0
  101. package/dist/protocol/messages.js +188 -0
  102. package/dist/protocol/messages.js.map +1 -0
  103. package/dist/protocol/messages.test.d.ts +2 -0
  104. package/dist/protocol/messages.test.d.ts.map +1 -0
  105. package/dist/protocol/messages.test.js +55 -0
  106. package/dist/protocol/messages.test.js.map +1 -0
  107. package/dist/types/index.d.ts +247 -0
  108. package/dist/types/index.d.ts.map +1 -0
  109. package/dist/types/index.js +10 -0
  110. package/dist/types/index.js.map +1 -0
  111. package/dist/types/result.d.ts +28 -0
  112. package/dist/types/result.d.ts.map +1 -0
  113. package/dist/types/result.js +16 -0
  114. package/dist/types/result.js.map +1 -0
  115. package/dist/utils/benchmark.d.ts +67 -0
  116. package/dist/utils/benchmark.d.ts.map +1 -0
  117. package/dist/utils/benchmark.js +179 -0
  118. package/dist/utils/benchmark.js.map +1 -0
  119. package/dist/utils/logger.d.ts +105 -0
  120. package/dist/utils/logger.d.ts.map +1 -0
  121. package/dist/utils/logger.js +275 -0
  122. package/dist/utils/logger.js.map +1 -0
  123. package/dist/utils/middleware.d.ts +85 -0
  124. package/dist/utils/middleware.d.ts.map +1 -0
  125. package/dist/utils/middleware.js +173 -0
  126. package/dist/utils/middleware.js.map +1 -0
  127. package/dist/utils/rate-limiter.d.ts +71 -0
  128. package/dist/utils/rate-limiter.d.ts.map +1 -0
  129. package/dist/utils/rate-limiter.js +160 -0
  130. package/dist/utils/rate-limiter.js.map +1 -0
  131. package/dist/utils/signature.d.ts +57 -0
  132. package/dist/utils/signature.d.ts.map +1 -0
  133. package/dist/utils/signature.js +102 -0
  134. package/dist/utils/signature.js.map +1 -0
  135. package/dist/utils/validation.d.ts +504 -0
  136. package/dist/utils/validation.d.ts.map +1 -0
  137. package/dist/utils/validation.js +159 -0
  138. package/dist/utils/validation.js.map +1 -0
  139. package/docs/F2A-PROTOCOL.md +61 -0
  140. package/docs/MOBILE_BOOTSTRAP_DESIGN.md +126 -0
  141. package/docs/a2a-lessons.md +316 -0
  142. package/docs/middleware-guide.md +448 -0
  143. package/docs/readme-update-checklist.md +90 -0
  144. package/docs/reputation-guide.md +396 -0
  145. package/docs/rfcs/001-reputation-system.md +712 -0
  146. package/docs/security-design.md +247 -0
  147. package/install.sh +231 -0
  148. package/package.json +64 -0
  149. package/packages/openclaw-adapter/README.md +510 -0
  150. package/packages/openclaw-adapter/openclaw.plugin.json +106 -0
  151. package/packages/openclaw-adapter/package.json +40 -0
  152. package/packages/openclaw-adapter/src/announcement-queue.test.ts +449 -0
  153. package/packages/openclaw-adapter/src/announcement-queue.ts +403 -0
  154. package/packages/openclaw-adapter/src/capability-detector.test.ts +99 -0
  155. package/packages/openclaw-adapter/src/capability-detector.ts +183 -0
  156. package/packages/openclaw-adapter/src/claim-handlers.test.ts +974 -0
  157. package/packages/openclaw-adapter/src/claim-handlers.ts +482 -0
  158. package/packages/openclaw-adapter/src/connector.business.test.ts +583 -0
  159. package/packages/openclaw-adapter/src/connector.ts +795 -0
  160. package/packages/openclaw-adapter/src/index.test.ts +82 -0
  161. package/packages/openclaw-adapter/src/index.ts +18 -0
  162. package/packages/openclaw-adapter/src/integration.e2e.test.ts +829 -0
  163. package/packages/openclaw-adapter/src/logger.ts +51 -0
  164. package/packages/openclaw-adapter/src/network-client.test.ts +266 -0
  165. package/packages/openclaw-adapter/src/network-client.ts +251 -0
  166. package/packages/openclaw-adapter/src/network-recovery.test.ts +465 -0
  167. package/packages/openclaw-adapter/src/node-manager.test.ts +136 -0
  168. package/packages/openclaw-adapter/src/node-manager.ts +429 -0
  169. package/packages/openclaw-adapter/src/plugin.test.ts +439 -0
  170. package/packages/openclaw-adapter/src/plugin.ts +104 -0
  171. package/packages/openclaw-adapter/src/reputation.test.ts +221 -0
  172. package/packages/openclaw-adapter/src/reputation.ts +368 -0
  173. package/packages/openclaw-adapter/src/task-guard.test.ts +502 -0
  174. package/packages/openclaw-adapter/src/task-guard.ts +860 -0
  175. package/packages/openclaw-adapter/src/task-queue.concurrency.test.ts +462 -0
  176. package/packages/openclaw-adapter/src/task-queue.edge-cases.test.ts +284 -0
  177. package/packages/openclaw-adapter/src/task-queue.persistence.test.ts +408 -0
  178. package/packages/openclaw-adapter/src/task-queue.ts +668 -0
  179. package/packages/openclaw-adapter/src/tool-handlers.test.ts +906 -0
  180. package/packages/openclaw-adapter/src/tool-handlers.ts +574 -0
  181. package/packages/openclaw-adapter/src/types.ts +361 -0
  182. package/packages/openclaw-adapter/src/webhook-pusher.test.ts +188 -0
  183. package/packages/openclaw-adapter/src/webhook-pusher.ts +220 -0
  184. package/packages/openclaw-adapter/src/webhook-server.test.ts +580 -0
  185. package/packages/openclaw-adapter/src/webhook-server.ts +202 -0
  186. package/packages/openclaw-adapter/tsconfig.json +20 -0
  187. package/src/cli/commands.test.ts +157 -0
  188. package/src/cli/commands.ts +129 -0
  189. package/src/cli/index.test.ts +77 -0
  190. package/src/cli/index.ts +234 -0
  191. package/src/core/autonomous-economy.test.ts +291 -0
  192. package/src/core/autonomous-economy.ts +428 -0
  193. package/src/core/e2ee-crypto.test.ts +125 -0
  194. package/src/core/e2ee-crypto.ts +246 -0
  195. package/src/core/f2a.test.ts +269 -0
  196. package/src/core/f2a.ts +618 -0
  197. package/src/core/p2p-network.test.ts +199 -0
  198. package/src/core/p2p-network.ts +1432 -0
  199. package/src/core/reputation-security.test.ts +403 -0
  200. package/src/core/reputation-security.ts +562 -0
  201. package/src/core/reputation.test.ts +260 -0
  202. package/src/core/reputation.ts +576 -0
  203. package/src/core/review-committee.test.ts +380 -0
  204. package/src/core/review-committee.ts +401 -0
  205. package/src/core/token-manager.test.ts +133 -0
  206. package/src/core/token-manager.ts +140 -0
  207. package/src/daemon/control-server.test.ts +216 -0
  208. package/src/daemon/control-server.ts +292 -0
  209. package/src/daemon/index.test.ts +85 -0
  210. package/src/daemon/index.ts +89 -0
  211. package/src/daemon/main.ts +44 -0
  212. package/src/daemon/start.ts +29 -0
  213. package/src/daemon/webhook.test.ts +68 -0
  214. package/src/daemon/webhook.ts +105 -0
  215. package/src/index.test.ts +436 -0
  216. package/src/index.ts +72 -0
  217. package/src/types/index.test.ts +87 -0
  218. package/src/types/index.ts +341 -0
  219. package/src/types/result.ts +68 -0
  220. package/src/utils/benchmark.ts +237 -0
  221. package/src/utils/logger.ts +331 -0
  222. package/src/utils/middleware.ts +229 -0
  223. package/src/utils/rate-limiter.ts +207 -0
  224. package/src/utils/signature.ts +136 -0
  225. package/src/utils/validation.ts +186 -0
  226. package/tests/docker/Dockerfile.node +23 -0
  227. package/tests/docker/Dockerfile.runner +18 -0
  228. package/tests/docker/docker-compose.test.yml +73 -0
  229. package/tests/integration/message-passing.test.ts +109 -0
  230. package/tests/integration/multi-node.test.ts +92 -0
  231. package/tests/integration/p2p-connection.test.ts +83 -0
  232. package/tests/integration/test-config.ts +32 -0
  233. package/tsconfig.json +21 -0
  234. package/vitest.config.ts +26 -0
@@ -0,0 +1,80 @@
1
+ /**
2
+ * ConnectionManager - 连接确认管理器
3
+ *
4
+ * 管理待确认连接请求,支持:
5
+ * - 1小时有效期
6
+ * - 同一 Agent 去重(保留最新)
7
+ * - 通过序号或 ID 确认/拒绝
8
+ */
9
+ import { EventEmitter } from 'eventemitter3';
10
+ import { Socket } from 'net';
11
+ import { PendingConnection, PendingConnectionView, ConnectionRequestEvent, ConfirmationEvent, RejectionEvent, ExpirationEvent, Result } from '../types';
12
+ export interface ConnectionManagerOptions {
13
+ timeout?: number;
14
+ cleanupInterval?: number;
15
+ }
16
+ export declare class ConnectionManager extends EventEmitter<{
17
+ pending_added: (event: ConnectionRequestEvent) => void;
18
+ confirmed: (event: ConfirmationEvent) => void;
19
+ rejected: (event: RejectionEvent) => void;
20
+ expired: (event: ExpirationEvent) => void;
21
+ }> {
22
+ private pendingConnections;
23
+ private agentToConfirmation;
24
+ private maxIndex;
25
+ private cleanupInterval?;
26
+ private options;
27
+ constructor(options?: ConnectionManagerOptions);
28
+ /**
29
+ * 添加待确认连接
30
+ */
31
+ addPending(agentId: string, socket: Socket, publicKey: string, address: string, port: number): {
32
+ confirmationId: string;
33
+ isDuplicate: boolean;
34
+ };
35
+ /**
36
+ * 获取待确认连接列表
37
+ */
38
+ getPendingList(): PendingConnectionView[];
39
+ /**
40
+ * 通过序号查找
41
+ */
42
+ getByIndex(index: number): PendingConnection | null;
43
+ /**
44
+ * 通过 ID 查找
45
+ */
46
+ getById(confirmationId: string): PendingConnection | null;
47
+ /**
48
+ * 确认连接
49
+ */
50
+ confirm(idOrIndex: string | number): Result<PendingConnection>;
51
+ /**
52
+ * 拒绝连接
53
+ */
54
+ reject(idOrIndex: string | number, reason?: string): Result<PendingConnection>;
55
+ /**
56
+ * 获取待确认数量
57
+ */
58
+ getPendingCount(): number;
59
+ /**
60
+ * 检查 Agent 是否有待确认请求
61
+ */
62
+ hasPendingForAgent(agentId: string): boolean;
63
+ /**
64
+ * 停止管理器
65
+ */
66
+ stop(): void;
67
+ /**
68
+ * 启动定期清理
69
+ */
70
+ private startCleanup;
71
+ /**
72
+ * 清理过期连接
73
+ */
74
+ private cleanup;
75
+ /**
76
+ * 安全关闭 socket
77
+ */
78
+ private closeSocket;
79
+ }
80
+ //# sourceMappingURL=connection-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../../src/core/connection-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,MAAM,EACP,MAAM,UAAU,CAAC;AAMlB,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,iBAAkB,SAAQ,YAAY,CAAC;IAClD,aAAa,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACvD,SAAS,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3C,CAAC;IACA,OAAO,CAAC,kBAAkB,CAA6C;IACvE,OAAO,CAAC,mBAAmB,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,OAAO,CAAqC;gBAExC,OAAO,GAAE,wBAA6B;IASlD;;OAEG;IACH,UAAU,CACR,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE;IA8CnD;;OAEG;IACH,cAAc,IAAI,qBAAqB,EAAE;IAwBzC;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IASnD;;OAEG;IACH,OAAO,CAAC,cAAc,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAgBzD;;OAEG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAuB9D;;OAEG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,GAAE,MAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAyBtF;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI5C;;OAEG;IACH,IAAI,IAAI,IAAI;IAcZ;;OAEG;IACH,OAAO,CAAC,YAAY;IAMpB;;OAEG;IACH,OAAO,CAAC,OAAO;IAuBf;;OAEG;IACH,OAAO,CAAC,WAAW;CAOpB"}
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ /**
3
+ * ConnectionManager - 连接确认管理器
4
+ *
5
+ * 管理待确认连接请求,支持:
6
+ * - 1小时有效期
7
+ * - 同一 Agent 去重(保留最新)
8
+ * - 通过序号或 ID 确认/拒绝
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.ConnectionManager = void 0;
12
+ const eventemitter3_1 = require("eventemitter3");
13
+ const crypto_1 = require("crypto");
14
+ // 常量
15
+ const PENDING_TIMEOUT = 60 * 60 * 1000; // 1小时
16
+ const CLEANUP_INTERVAL = 60 * 1000; // 每分钟清理一次
17
+ class ConnectionManager extends eventemitter3_1.EventEmitter {
18
+ pendingConnections = new Map();
19
+ agentToConfirmation = new Map();
20
+ maxIndex = 0;
21
+ cleanupInterval;
22
+ options;
23
+ constructor(options = {}) {
24
+ super();
25
+ this.options = {
26
+ timeout: options.timeout ?? PENDING_TIMEOUT,
27
+ cleanupInterval: options.cleanupInterval ?? CLEANUP_INTERVAL
28
+ };
29
+ this.startCleanup();
30
+ }
31
+ /**
32
+ * 添加待确认连接
33
+ */
34
+ addPending(agentId, socket, publicKey, address, port) {
35
+ // 检查是否已有同一 Agent 的待确认请求
36
+ const existingId = this.agentToConfirmation.get(agentId);
37
+ let isDuplicate = false;
38
+ if (existingId) {
39
+ const existing = this.pendingConnections.get(existingId);
40
+ if (existing) {
41
+ // 关闭旧的 socket
42
+ this.closeSocket(existing.socket);
43
+ // 删除旧的记录
44
+ this.pendingConnections.delete(existingId);
45
+ console.log(`[ConnectionManager] 更新 ${agentId.slice(0, 16)}... 的连接请求(去重)`);
46
+ isDuplicate = true;
47
+ }
48
+ }
49
+ const confirmationId = (0, crypto_1.randomUUID)();
50
+ const now = Date.now();
51
+ const pending = {
52
+ confirmationId,
53
+ agentId,
54
+ socket,
55
+ publicKey,
56
+ address,
57
+ port,
58
+ timestamp: now,
59
+ expiresAt: now + this.options.timeout,
60
+ index: ++this.maxIndex
61
+ };
62
+ this.pendingConnections.set(confirmationId, pending);
63
+ this.agentToConfirmation.set(agentId, confirmationId);
64
+ this.emit('pending_added', {
65
+ confirmationId,
66
+ agentId,
67
+ address,
68
+ port,
69
+ isDuplicate
70
+ });
71
+ return { confirmationId, isDuplicate };
72
+ }
73
+ /**
74
+ * 获取待确认连接列表
75
+ */
76
+ getPendingList() {
77
+ const now = Date.now();
78
+ const list = [];
79
+ for (const pending of this.pendingConnections.values()) {
80
+ const remainingMs = pending.expiresAt - now;
81
+ const remainingMinutes = Math.max(0, Math.floor(remainingMs / 60000));
82
+ list.push({
83
+ index: pending.index,
84
+ confirmationId: pending.confirmationId,
85
+ shortId: pending.confirmationId.slice(0, 8),
86
+ agentId: pending.agentId,
87
+ agentIdShort: pending.agentId.slice(0, 16) + '...',
88
+ address: pending.address,
89
+ port: pending.port,
90
+ remainingMinutes,
91
+ requestedAt: pending.timestamp
92
+ });
93
+ }
94
+ return list.sort((a, b) => a.index - b.index);
95
+ }
96
+ /**
97
+ * 通过序号查找
98
+ */
99
+ getByIndex(index) {
100
+ for (const pending of this.pendingConnections.values()) {
101
+ if (pending.index === index) {
102
+ return pending;
103
+ }
104
+ }
105
+ return null;
106
+ }
107
+ /**
108
+ * 通过 ID 查找
109
+ */
110
+ getById(confirmationId) {
111
+ // 完整匹配
112
+ if (this.pendingConnections.has(confirmationId)) {
113
+ return this.pendingConnections.get(confirmationId);
114
+ }
115
+ // 短 ID 匹配(前8位)
116
+ for (const [id, pending] of this.pendingConnections) {
117
+ if (id.startsWith(confirmationId)) {
118
+ return pending;
119
+ }
120
+ }
121
+ return null;
122
+ }
123
+ /**
124
+ * 确认连接
125
+ */
126
+ confirm(idOrIndex) {
127
+ const pending = typeof idOrIndex === 'number'
128
+ ? this.getByIndex(idOrIndex)
129
+ : this.getById(idOrIndex);
130
+ if (!pending) {
131
+ return { success: false, error: '连接请求不存在或已过期' };
132
+ }
133
+ // 清理记录
134
+ this.pendingConnections.delete(pending.confirmationId);
135
+ this.agentToConfirmation.delete(pending.agentId);
136
+ this.emit('confirmed', {
137
+ confirmationId: pending.confirmationId,
138
+ agentId: pending.agentId,
139
+ socket: pending.socket,
140
+ publicKey: pending.publicKey
141
+ });
142
+ return { success: true, data: pending };
143
+ }
144
+ /**
145
+ * 拒绝连接
146
+ */
147
+ reject(idOrIndex, reason = '用户拒绝') {
148
+ const pending = typeof idOrIndex === 'number'
149
+ ? this.getByIndex(idOrIndex)
150
+ : this.getById(idOrIndex);
151
+ if (!pending) {
152
+ return { success: false, error: '连接请求不存在或已过期' };
153
+ }
154
+ // 关闭 socket
155
+ this.closeSocket(pending.socket);
156
+ // 清理记录
157
+ this.pendingConnections.delete(pending.confirmationId);
158
+ this.agentToConfirmation.delete(pending.agentId);
159
+ this.emit('rejected', {
160
+ confirmationId: pending.confirmationId,
161
+ agentId: pending.agentId,
162
+ reason
163
+ });
164
+ return { success: true, data: pending };
165
+ }
166
+ /**
167
+ * 获取待确认数量
168
+ */
169
+ getPendingCount() {
170
+ return this.pendingConnections.size;
171
+ }
172
+ /**
173
+ * 检查 Agent 是否有待确认请求
174
+ */
175
+ hasPendingForAgent(agentId) {
176
+ return this.agentToConfirmation.has(agentId);
177
+ }
178
+ /**
179
+ * 停止管理器
180
+ */
181
+ stop() {
182
+ if (this.cleanupInterval) {
183
+ clearInterval(this.cleanupInterval);
184
+ }
185
+ // 关闭所有待确认连接
186
+ for (const pending of this.pendingConnections.values()) {
187
+ this.closeSocket(pending.socket);
188
+ }
189
+ this.pendingConnections.clear();
190
+ this.agentToConfirmation.clear();
191
+ }
192
+ /**
193
+ * 启动定期清理
194
+ */
195
+ startCleanup() {
196
+ this.cleanupInterval = setInterval(() => {
197
+ this.cleanup();
198
+ }, this.options.cleanupInterval);
199
+ }
200
+ /**
201
+ * 清理过期连接
202
+ */
203
+ cleanup() {
204
+ const now = Date.now();
205
+ let expiredCount = 0;
206
+ for (const [confirmationId, pending] of this.pendingConnections) {
207
+ if (now > pending.expiresAt) {
208
+ this.closeSocket(pending.socket);
209
+ this.agentToConfirmation.delete(pending.agentId);
210
+ this.pendingConnections.delete(confirmationId);
211
+ expiredCount++;
212
+ this.emit('expired', {
213
+ confirmationId,
214
+ agentId: pending.agentId
215
+ });
216
+ }
217
+ }
218
+ if (expiredCount > 0) {
219
+ console.log(`[ConnectionManager] 清理 ${expiredCount} 个过期连接`);
220
+ }
221
+ }
222
+ /**
223
+ * 安全关闭 socket
224
+ */
225
+ closeSocket(socket) {
226
+ try {
227
+ socket.end();
228
+ }
229
+ catch {
230
+ // 忽略错误
231
+ }
232
+ }
233
+ }
234
+ exports.ConnectionManager = ConnectionManager;
235
+ //# sourceMappingURL=connection-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-manager.js","sourceRoot":"","sources":["../../src/core/connection-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=connection-manager.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-manager.test.d.ts","sourceRoot":"","sources":["../../src/core/connection-manager.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const connection_manager_1 = require("./connection-manager");
5
+ // Mock Socket
6
+ function createMockSocket() {
7
+ return {
8
+ ended: false,
9
+ end: function () { this.ended = true; },
10
+ remoteAddress: '192.168.1.100',
11
+ remotePort: 9001
12
+ };
13
+ }
14
+ (0, vitest_1.describe)('ConnectionManager', () => {
15
+ let cm;
16
+ (0, vitest_1.beforeEach)(() => {
17
+ cm = new connection_manager_1.ConnectionManager({ timeout: 1000, cleanupInterval: 100 });
18
+ });
19
+ (0, vitest_1.afterEach)(() => {
20
+ cm.stop();
21
+ });
22
+ (0, vitest_1.it)('should add pending connection', () => {
23
+ const socket = createMockSocket();
24
+ const result = cm.addPending('agent-1', socket, 'key', '192.168.1.100', 9001);
25
+ (0, vitest_1.expect)(result.confirmationId).toBeDefined();
26
+ (0, vitest_1.expect)(result.isDuplicate).toBe(false);
27
+ (0, vitest_1.expect)(cm.getPendingCount()).toBe(1);
28
+ });
29
+ (0, vitest_1.it)('should deduplicate same agent requests', () => {
30
+ const socket1 = createMockSocket();
31
+ cm.addPending('agent-1', socket1, 'key1', '192.168.1.100', 9001);
32
+ const socket2 = createMockSocket();
33
+ const result = cm.addPending('agent-1', socket2, 'key2', '192.168.1.100', 9002);
34
+ (0, vitest_1.expect)(result.isDuplicate).toBe(true);
35
+ (0, vitest_1.expect)(cm.getPendingCount()).toBe(1);
36
+ });
37
+ (0, vitest_1.it)('should confirm connection', () => {
38
+ cm.addPending('agent-1', createMockSocket(), 'key1', '192.168.1.100', 9001);
39
+ const result = cm.confirm(1);
40
+ (0, vitest_1.expect)(result.success).toBe(true);
41
+ (0, vitest_1.expect)(cm.getPendingCount()).toBe(0);
42
+ });
43
+ (0, vitest_1.it)('should reject connection', () => {
44
+ const socket = createMockSocket();
45
+ cm.addPending('agent-1', socket, 'key1', '192.168.1.100', 9001);
46
+ const result = cm.reject(1, 'test reason');
47
+ (0, vitest_1.expect)(result.success).toBe(true);
48
+ (0, vitest_1.expect)(socket.ended).toBe(true);
49
+ (0, vitest_1.expect)(cm.getPendingCount()).toBe(0);
50
+ });
51
+ });
52
+ //# sourceMappingURL=connection-manager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-manager.test.js","sourceRoot":"","sources":["../../src/core/connection-manager.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * 端到端加密模块
3
+ * 使用 X25519 + AES-256-GCM 实现 Agent 间加密通信
4
+ */
5
+ /**
6
+ * 加密密钥对
7
+ */
8
+ export interface EncryptionKeyPair {
9
+ publicKey: Uint8Array;
10
+ privateKey: Uint8Array;
11
+ }
12
+ /**
13
+ * 加密后的消息
14
+ */
15
+ export interface EncryptedMessage {
16
+ /** 发送方公钥 (用于接收方识别身份) */
17
+ senderPublicKey: string;
18
+ /** nonce/IV */
19
+ iv: string;
20
+ /** 认证标签 */
21
+ authTag: string;
22
+ /** 加密后的密文 */
23
+ ciphertext: string;
24
+ /** 可选的附加认证数据 */
25
+ aad?: string;
26
+ /** 密钥派生使用的随机盐值(每次加密随机生成) */
27
+ salt: string;
28
+ }
29
+ /**
30
+ * 密钥管理器
31
+ */
32
+ export declare class E2EECrypto {
33
+ private keyPair;
34
+ private peerPublicKeys;
35
+ private sharedSecrets;
36
+ private logger;
37
+ constructor();
38
+ /**
39
+ * 初始化密钥对
40
+ */
41
+ initialize(): Promise<void>;
42
+ /**
43
+ * 从已有密钥初始化
44
+ */
45
+ initializeWithKeyPair(privateKey: Uint8Array, publicKey: Uint8Array): void;
46
+ /**
47
+ * 获取公钥 (用于广播)
48
+ */
49
+ getPublicKey(): string | null;
50
+ /**
51
+ * 注册对等方的公钥
52
+ */
53
+ registerPeerPublicKey(peerId: string, publicKeyBase64: string): void;
54
+ /**
55
+ * 检查是否可以对等方加密通信
56
+ */
57
+ canEncryptTo(peerId: string): boolean;
58
+ /**
59
+ * 加密消息
60
+ */
61
+ encrypt(peerId: string, plaintext: string, aad?: string): EncryptedMessage | null;
62
+ /**
63
+ * 解密消息
64
+ */
65
+ decrypt(encrypted: EncryptedMessage): string | null;
66
+ /**
67
+ * 从共享密钥派生 AES 密钥
68
+ * 使用 HKDF (HMAC-based Key Derivation Function) 进行安全密钥派生
69
+ * @param sharedSecret 共享密钥
70
+ * @param salt 随机盐值(每次加密使用不同的盐值,提高安全性)
71
+ */
72
+ private deriveAESKey;
73
+ /**
74
+ * 获取已注册的对等方公钥
75
+ */
76
+ getPeerPublicKey(peerId: string): string | null;
77
+ /**
78
+ * 序列化密钥对用于存储
79
+ */
80
+ exportKeyPair(): {
81
+ publicKey: string;
82
+ privateKey: string;
83
+ } | null;
84
+ /**
85
+ * 获取已注册的对等方数量
86
+ */
87
+ getRegisteredPeerCount(): number;
88
+ }
89
+ export declare const defaultE2EECrypto: E2EECrypto;
90
+ //# sourceMappingURL=e2ee-crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2ee-crypto.d.ts","sourceRoot":"","sources":["../../src/core/e2ee-crypto.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wBAAwB;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,MAAM,CAAS;;IAMvB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;OAEG;IACH,qBAAqB,CAAC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,IAAI;IAI1E;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;IAK7B;;OAEG;IACH,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI;IAepE;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIrC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAmDjF;;OAEG;IACH,OAAO,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI;IAuCnD;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAWpB;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAK/C;;OAEG;IACH,aAAa,IAAI;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAQjE;;OAEG;IACH,sBAAsB,IAAI,MAAM;CAGjC;AAGD,eAAO,MAAM,iBAAiB,YAAmB,CAAC"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * 端到端加密模块
3
+ * 使用 X25519 + AES-256-GCM 实现 Agent 间加密通信
4
+ */
5
+ import { x25519 } from '@noble/curves/ed25519.js';
6
+ import { randomBytes, createCipheriv, createDecipheriv, hkdfSync } from 'crypto';
7
+ import { Logger } from '../utils/logger.js';
8
+ // AES-256-GCM 参数
9
+ const AES_KEY_SIZE = 32; // 256 bits
10
+ const AES_IV_SIZE = 16; // 128 bits
11
+ const AES_TAG_SIZE = 16; // 128 bits
12
+ /**
13
+ * 密钥管理器
14
+ */
15
+ export class E2EECrypto {
16
+ keyPair = null;
17
+ peerPublicKeys = new Map();
18
+ sharedSecrets = new Map();
19
+ logger;
20
+ constructor() {
21
+ this.logger = new Logger({ component: 'E2EE' });
22
+ }
23
+ /**
24
+ * 初始化密钥对
25
+ */
26
+ async initialize() {
27
+ // 生成 X25519 密钥对用于加密
28
+ const privateKey = x25519.utils.randomSecretKey();
29
+ const publicKey = x25519.getPublicKey(privateKey);
30
+ this.keyPair = { publicKey, privateKey };
31
+ }
32
+ /**
33
+ * 从已有密钥初始化
34
+ */
35
+ initializeWithKeyPair(privateKey, publicKey) {
36
+ this.keyPair = { privateKey, publicKey };
37
+ }
38
+ /**
39
+ * 获取公钥 (用于广播)
40
+ */
41
+ getPublicKey() {
42
+ if (!this.keyPair)
43
+ return null;
44
+ return Buffer.from(this.keyPair.publicKey).toString('base64');
45
+ }
46
+ /**
47
+ * 注册对等方的公钥
48
+ */
49
+ registerPeerPublicKey(peerId, publicKeyBase64) {
50
+ try {
51
+ const publicKey = Buffer.from(publicKeyBase64, 'base64');
52
+ this.peerPublicKeys.set(peerId, publicKey);
53
+ // 预计算共享密钥
54
+ if (this.keyPair) {
55
+ const sharedSecret = x25519.getSharedSecret(this.keyPair.privateKey, publicKey);
56
+ this.sharedSecrets.set(peerId, sharedSecret);
57
+ }
58
+ }
59
+ catch (error) {
60
+ this.logger.error('Failed to register public key', { peerId, error });
61
+ }
62
+ }
63
+ /**
64
+ * 检查是否可以对等方加密通信
65
+ */
66
+ canEncryptTo(peerId) {
67
+ return this.sharedSecrets.has(peerId);
68
+ }
69
+ /**
70
+ * 加密消息
71
+ */
72
+ encrypt(peerId, plaintext, aad) {
73
+ if (!this.keyPair) {
74
+ this.logger.error('Not initialized');
75
+ return null;
76
+ }
77
+ const sharedSecret = this.sharedSecrets.get(peerId);
78
+ if (!sharedSecret) {
79
+ this.logger.error('No shared secret for peer', { peerId });
80
+ return null;
81
+ }
82
+ try {
83
+ // 生成随机盐值(每次加密使用不同的盐值,提高安全性)
84
+ const salt = randomBytes(16);
85
+ // 从共享密钥派生 AES 密钥
86
+ const aesKey = this.deriveAESKey(sharedSecret, salt);
87
+ // 生成随机 IV
88
+ const iv = randomBytes(AES_IV_SIZE);
89
+ // 创建加密器
90
+ const cipher = createCipheriv('aes-256-gcm', aesKey, iv);
91
+ // 添加 AAD (如果有)
92
+ if (aad) {
93
+ cipher.setAAD(Buffer.from(aad, 'utf-8'));
94
+ }
95
+ // 加密
96
+ let ciphertext = cipher.update(plaintext, 'utf-8', 'base64');
97
+ ciphertext += cipher.final('base64');
98
+ // 获取认证标签
99
+ const authTag = cipher.getAuthTag();
100
+ return {
101
+ senderPublicKey: this.getPublicKey(),
102
+ iv: iv.toString('base64'),
103
+ authTag: authTag.toString('base64'),
104
+ ciphertext,
105
+ aad,
106
+ salt: salt.toString('base64')
107
+ };
108
+ }
109
+ catch (error) {
110
+ this.logger.error('Encryption failed', { error });
111
+ return null;
112
+ }
113
+ }
114
+ /**
115
+ * 解密消息
116
+ */
117
+ decrypt(encrypted) {
118
+ if (!this.keyPair) {
119
+ this.logger.error('Not initialized');
120
+ return null;
121
+ }
122
+ try {
123
+ // 使用发送方公钥计算共享密钥
124
+ const senderPublicKey = Buffer.from(encrypted.senderPublicKey, 'base64');
125
+ const sharedSecret = x25519.getSharedSecret(this.keyPair.privateKey, senderPublicKey);
126
+ // 使用消息中的盐值派生 AES 密钥(与加密方使用相同的盐值)
127
+ const salt = encrypted.salt ? Buffer.from(encrypted.salt, 'base64') : Buffer.from('F2A-E2EE-SALT-2024', 'utf-8');
128
+ const aesKey = this.deriveAESKey(sharedSecret, salt);
129
+ // 解码参数
130
+ const iv = Buffer.from(encrypted.iv, 'base64');
131
+ const authTag = Buffer.from(encrypted.authTag, 'base64');
132
+ // 创建解密器
133
+ const decipher = createDecipheriv('aes-256-gcm', aesKey, iv);
134
+ decipher.setAuthTag(authTag);
135
+ // 添加 AAD (如果有)
136
+ if (encrypted.aad) {
137
+ decipher.setAAD(Buffer.from(encrypted.aad, 'utf-8'));
138
+ }
139
+ // 解密
140
+ let plaintext = decipher.update(encrypted.ciphertext, 'base64', 'utf-8');
141
+ plaintext += decipher.final('utf-8');
142
+ return plaintext;
143
+ }
144
+ catch (error) {
145
+ this.logger.error('Decryption failed', { error });
146
+ return null;
147
+ }
148
+ }
149
+ /**
150
+ * 从共享密钥派生 AES 密钥
151
+ * 使用 HKDF (HMAC-based Key Derivation Function) 进行安全密钥派生
152
+ * @param sharedSecret 共享密钥
153
+ * @param salt 随机盐值(每次加密使用不同的盐值,提高安全性)
154
+ */
155
+ deriveAESKey(sharedSecret, salt) {
156
+ // HKDF 参数
157
+ const info = Buffer.from('AES-256-GCM-KEY', 'utf-8'); // 密钥用途标识
158
+ // 使用 HKDF-SHA256 进行密钥派生
159
+ // hkdfSync(digest, ikm, salt, info, keylen)
160
+ const derivedKey = hkdfSync('sha256', sharedSecret, salt, info, AES_KEY_SIZE);
161
+ return Buffer.from(derivedKey);
162
+ }
163
+ /**
164
+ * 获取已注册的对等方公钥
165
+ */
166
+ getPeerPublicKey(peerId) {
167
+ const publicKey = this.peerPublicKeys.get(peerId);
168
+ return publicKey ? Buffer.from(publicKey).toString('base64') : null;
169
+ }
170
+ /**
171
+ * 序列化密钥对用于存储
172
+ */
173
+ exportKeyPair() {
174
+ if (!this.keyPair)
175
+ return null;
176
+ return {
177
+ publicKey: Buffer.from(this.keyPair.publicKey).toString('base64'),
178
+ privateKey: Buffer.from(this.keyPair.privateKey).toString('base64')
179
+ };
180
+ }
181
+ /**
182
+ * 获取已注册的对等方数量
183
+ */
184
+ getRegisteredPeerCount() {
185
+ return this.peerPublicKeys.size;
186
+ }
187
+ }
188
+ // 单例导出
189
+ export const defaultE2EECrypto = new E2EECrypto();
190
+ //# sourceMappingURL=e2ee-crypto.js.map