@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.
- package/.github/workflows/ci.yml +113 -0
- package/.github/workflows/publish.yml +60 -0
- package/LICENSE +21 -0
- package/MONOREPO.md +58 -0
- package/README.md +280 -0
- package/SKILL.md +137 -0
- package/dist/adapters/openclaw.d.ts +103 -0
- package/dist/adapters/openclaw.d.ts.map +1 -0
- package/dist/adapters/openclaw.js +297 -0
- package/dist/adapters/openclaw.js.map +1 -0
- package/dist/cli/commands.d.ts +17 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +107 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +203 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/autonomous-economy.d.ts +136 -0
- package/dist/core/autonomous-economy.d.ts.map +1 -0
- package/dist/core/autonomous-economy.js +255 -0
- package/dist/core/autonomous-economy.js.map +1 -0
- package/dist/core/connection-manager.d.ts +80 -0
- package/dist/core/connection-manager.d.ts.map +1 -0
- package/dist/core/connection-manager.js +235 -0
- package/dist/core/connection-manager.js.map +1 -0
- package/dist/core/connection-manager.test.d.ts +2 -0
- package/dist/core/connection-manager.test.d.ts.map +1 -0
- package/dist/core/connection-manager.test.js +52 -0
- package/dist/core/connection-manager.test.js.map +1 -0
- package/dist/core/e2ee-crypto.d.ts +90 -0
- package/dist/core/e2ee-crypto.d.ts.map +1 -0
- package/dist/core/e2ee-crypto.js +190 -0
- package/dist/core/e2ee-crypto.js.map +1 -0
- package/dist/core/f2a.d.ts +126 -0
- package/dist/core/f2a.d.ts.map +1 -0
- package/dist/core/f2a.js +425 -0
- package/dist/core/f2a.js.map +1 -0
- package/dist/core/identity.d.ts +47 -0
- package/dist/core/identity.d.ts.map +1 -0
- package/dist/core/identity.js +130 -0
- package/dist/core/identity.js.map +1 -0
- package/dist/core/identity.test.d.ts +2 -0
- package/dist/core/identity.test.d.ts.map +1 -0
- package/dist/core/identity.test.js +43 -0
- package/dist/core/identity.test.js.map +1 -0
- package/dist/core/p2p-network.d.ts +242 -0
- package/dist/core/p2p-network.d.ts.map +1 -0
- package/dist/core/p2p-network.js +1182 -0
- package/dist/core/p2p-network.js.map +1 -0
- package/dist/core/reputation-security.d.ts +168 -0
- package/dist/core/reputation-security.d.ts.map +1 -0
- package/dist/core/reputation-security.js +369 -0
- package/dist/core/reputation-security.js.map +1 -0
- package/dist/core/reputation.d.ts +179 -0
- package/dist/core/reputation.d.ts.map +1 -0
- package/dist/core/reputation.js +472 -0
- package/dist/core/reputation.js.map +1 -0
- package/dist/core/review-committee.d.ts +130 -0
- package/dist/core/review-committee.d.ts.map +1 -0
- package/dist/core/review-committee.js +251 -0
- package/dist/core/review-committee.js.map +1 -0
- package/dist/core/serverless.d.ts +155 -0
- package/dist/core/serverless.d.ts.map +1 -0
- package/dist/core/serverless.js +615 -0
- package/dist/core/serverless.js.map +1 -0
- package/dist/core/token-manager.d.ts +42 -0
- package/dist/core/token-manager.d.ts.map +1 -0
- package/dist/core/token-manager.js +122 -0
- package/dist/core/token-manager.js.map +1 -0
- package/dist/daemon/control-server.d.ts +55 -0
- package/dist/daemon/control-server.d.ts.map +1 -0
- package/dist/daemon/control-server.js +262 -0
- package/dist/daemon/control-server.js.map +1 -0
- package/dist/daemon/index.d.ts +35 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +69 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/main.d.ts +6 -0
- package/dist/daemon/main.d.ts.map +1 -0
- package/dist/daemon/main.js +38 -0
- package/dist/daemon/main.js.map +1 -0
- package/dist/daemon/start.d.ts +6 -0
- package/dist/daemon/start.d.ts.map +1 -0
- package/dist/daemon/start.js +25 -0
- package/dist/daemon/start.js.map +1 -0
- package/dist/daemon/webhook.d.ts +30 -0
- package/dist/daemon/webhook.d.ts.map +1 -0
- package/dist/daemon/webhook.js +86 -0
- package/dist/daemon/webhook.js.map +1 -0
- package/dist/daemon/webhook.test.d.ts +2 -0
- package/dist/daemon/webhook.test.d.ts.map +1 -0
- package/dist/daemon/webhook.test.js +24 -0
- package/dist/daemon/webhook.test.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/messages.d.ts +739 -0
- package/dist/protocol/messages.d.ts.map +1 -0
- package/dist/protocol/messages.js +188 -0
- package/dist/protocol/messages.js.map +1 -0
- package/dist/protocol/messages.test.d.ts +2 -0
- package/dist/protocol/messages.test.d.ts.map +1 -0
- package/dist/protocol/messages.test.js +55 -0
- package/dist/protocol/messages.test.js.map +1 -0
- package/dist/types/index.d.ts +247 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/result.d.ts +28 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +16 -0
- package/dist/types/result.js.map +1 -0
- package/dist/utils/benchmark.d.ts +67 -0
- package/dist/utils/benchmark.d.ts.map +1 -0
- package/dist/utils/benchmark.js +179 -0
- package/dist/utils/benchmark.js.map +1 -0
- package/dist/utils/logger.d.ts +105 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +275 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/middleware.d.ts +85 -0
- package/dist/utils/middleware.d.ts.map +1 -0
- package/dist/utils/middleware.js +173 -0
- package/dist/utils/middleware.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +71 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +160 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/signature.d.ts +57 -0
- package/dist/utils/signature.d.ts.map +1 -0
- package/dist/utils/signature.js +102 -0
- package/dist/utils/signature.js.map +1 -0
- package/dist/utils/validation.d.ts +504 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +159 -0
- package/dist/utils/validation.js.map +1 -0
- package/docs/F2A-PROTOCOL.md +61 -0
- package/docs/MOBILE_BOOTSTRAP_DESIGN.md +126 -0
- package/docs/a2a-lessons.md +316 -0
- package/docs/middleware-guide.md +448 -0
- package/docs/readme-update-checklist.md +90 -0
- package/docs/reputation-guide.md +396 -0
- package/docs/rfcs/001-reputation-system.md +712 -0
- package/docs/security-design.md +247 -0
- package/install.sh +231 -0
- package/package.json +64 -0
- package/packages/openclaw-adapter/README.md +510 -0
- package/packages/openclaw-adapter/openclaw.plugin.json +106 -0
- package/packages/openclaw-adapter/package.json +40 -0
- package/packages/openclaw-adapter/src/announcement-queue.test.ts +449 -0
- package/packages/openclaw-adapter/src/announcement-queue.ts +403 -0
- package/packages/openclaw-adapter/src/capability-detector.test.ts +99 -0
- package/packages/openclaw-adapter/src/capability-detector.ts +183 -0
- package/packages/openclaw-adapter/src/claim-handlers.test.ts +974 -0
- package/packages/openclaw-adapter/src/claim-handlers.ts +482 -0
- package/packages/openclaw-adapter/src/connector.business.test.ts +583 -0
- package/packages/openclaw-adapter/src/connector.ts +795 -0
- package/packages/openclaw-adapter/src/index.test.ts +82 -0
- package/packages/openclaw-adapter/src/index.ts +18 -0
- package/packages/openclaw-adapter/src/integration.e2e.test.ts +829 -0
- package/packages/openclaw-adapter/src/logger.ts +51 -0
- package/packages/openclaw-adapter/src/network-client.test.ts +266 -0
- package/packages/openclaw-adapter/src/network-client.ts +251 -0
- package/packages/openclaw-adapter/src/network-recovery.test.ts +465 -0
- package/packages/openclaw-adapter/src/node-manager.test.ts +136 -0
- package/packages/openclaw-adapter/src/node-manager.ts +429 -0
- package/packages/openclaw-adapter/src/plugin.test.ts +439 -0
- package/packages/openclaw-adapter/src/plugin.ts +104 -0
- package/packages/openclaw-adapter/src/reputation.test.ts +221 -0
- package/packages/openclaw-adapter/src/reputation.ts +368 -0
- package/packages/openclaw-adapter/src/task-guard.test.ts +502 -0
- package/packages/openclaw-adapter/src/task-guard.ts +860 -0
- package/packages/openclaw-adapter/src/task-queue.concurrency.test.ts +462 -0
- package/packages/openclaw-adapter/src/task-queue.edge-cases.test.ts +284 -0
- package/packages/openclaw-adapter/src/task-queue.persistence.test.ts +408 -0
- package/packages/openclaw-adapter/src/task-queue.ts +668 -0
- package/packages/openclaw-adapter/src/tool-handlers.test.ts +906 -0
- package/packages/openclaw-adapter/src/tool-handlers.ts +574 -0
- package/packages/openclaw-adapter/src/types.ts +361 -0
- package/packages/openclaw-adapter/src/webhook-pusher.test.ts +188 -0
- package/packages/openclaw-adapter/src/webhook-pusher.ts +220 -0
- package/packages/openclaw-adapter/src/webhook-server.test.ts +580 -0
- package/packages/openclaw-adapter/src/webhook-server.ts +202 -0
- package/packages/openclaw-adapter/tsconfig.json +20 -0
- package/src/cli/commands.test.ts +157 -0
- package/src/cli/commands.ts +129 -0
- package/src/cli/index.test.ts +77 -0
- package/src/cli/index.ts +234 -0
- package/src/core/autonomous-economy.test.ts +291 -0
- package/src/core/autonomous-economy.ts +428 -0
- package/src/core/e2ee-crypto.test.ts +125 -0
- package/src/core/e2ee-crypto.ts +246 -0
- package/src/core/f2a.test.ts +269 -0
- package/src/core/f2a.ts +618 -0
- package/src/core/p2p-network.test.ts +199 -0
- package/src/core/p2p-network.ts +1432 -0
- package/src/core/reputation-security.test.ts +403 -0
- package/src/core/reputation-security.ts +562 -0
- package/src/core/reputation.test.ts +260 -0
- package/src/core/reputation.ts +576 -0
- package/src/core/review-committee.test.ts +380 -0
- package/src/core/review-committee.ts +401 -0
- package/src/core/token-manager.test.ts +133 -0
- package/src/core/token-manager.ts +140 -0
- package/src/daemon/control-server.test.ts +216 -0
- package/src/daemon/control-server.ts +292 -0
- package/src/daemon/index.test.ts +85 -0
- package/src/daemon/index.ts +89 -0
- package/src/daemon/main.ts +44 -0
- package/src/daemon/start.ts +29 -0
- package/src/daemon/webhook.test.ts +68 -0
- package/src/daemon/webhook.ts +105 -0
- package/src/index.test.ts +436 -0
- package/src/index.ts +72 -0
- package/src/types/index.test.ts +87 -0
- package/src/types/index.ts +341 -0
- package/src/types/result.ts +68 -0
- package/src/utils/benchmark.ts +237 -0
- package/src/utils/logger.ts +331 -0
- package/src/utils/middleware.ts +229 -0
- package/src/utils/rate-limiter.ts +207 -0
- package/src/utils/signature.ts +136 -0
- package/src/utils/validation.ts +186 -0
- package/tests/docker/Dockerfile.node +23 -0
- package/tests/docker/Dockerfile.runner +18 -0
- package/tests/docker/docker-compose.test.yml +73 -0
- package/tests/integration/message-passing.test.ts +109 -0
- package/tests/integration/multi-node.test.ts +92 -0
- package/tests/integration/p2p-connection.test.ts +83 -0
- package/tests/integration/test-config.ts +32 -0
- package/tsconfig.json +21 -0
- 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 @@
|
|
|
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
|