@f2a/network 0.1.2 → 0.1.3

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 (136) hide show
  1. package/package.json +8 -1
  2. package/.github/workflows/ci.yml +0 -113
  3. package/.github/workflows/publish.yml +0 -60
  4. package/MONOREPO.md +0 -58
  5. package/SKILL.md +0 -137
  6. package/dist/adapters/openclaw.d.ts +0 -103
  7. package/dist/adapters/openclaw.d.ts.map +0 -1
  8. package/dist/adapters/openclaw.js +0 -297
  9. package/dist/adapters/openclaw.js.map +0 -1
  10. package/dist/core/connection-manager.d.ts +0 -80
  11. package/dist/core/connection-manager.d.ts.map +0 -1
  12. package/dist/core/connection-manager.js +0 -235
  13. package/dist/core/connection-manager.js.map +0 -1
  14. package/dist/core/connection-manager.test.d.ts +0 -2
  15. package/dist/core/connection-manager.test.d.ts.map +0 -1
  16. package/dist/core/connection-manager.test.js +0 -52
  17. package/dist/core/connection-manager.test.js.map +0 -1
  18. package/dist/core/identity.d.ts +0 -47
  19. package/dist/core/identity.d.ts.map +0 -1
  20. package/dist/core/identity.js +0 -130
  21. package/dist/core/identity.js.map +0 -1
  22. package/dist/core/identity.test.d.ts +0 -2
  23. package/dist/core/identity.test.d.ts.map +0 -1
  24. package/dist/core/identity.test.js +0 -43
  25. package/dist/core/identity.test.js.map +0 -1
  26. package/dist/core/serverless.d.ts +0 -155
  27. package/dist/core/serverless.d.ts.map +0 -1
  28. package/dist/core/serverless.js +0 -615
  29. package/dist/core/serverless.js.map +0 -1
  30. package/dist/daemon/webhook.test.d.ts +0 -2
  31. package/dist/daemon/webhook.test.d.ts.map +0 -1
  32. package/dist/daemon/webhook.test.js +0 -24
  33. package/dist/daemon/webhook.test.js.map +0 -1
  34. package/dist/protocol/messages.d.ts +0 -739
  35. package/dist/protocol/messages.d.ts.map +0 -1
  36. package/dist/protocol/messages.js +0 -188
  37. package/dist/protocol/messages.js.map +0 -1
  38. package/dist/protocol/messages.test.d.ts +0 -2
  39. package/dist/protocol/messages.test.d.ts.map +0 -1
  40. package/dist/protocol/messages.test.js +0 -55
  41. package/dist/protocol/messages.test.js.map +0 -1
  42. package/docs/F2A-PROTOCOL.md +0 -61
  43. package/docs/MOBILE_BOOTSTRAP_DESIGN.md +0 -126
  44. package/docs/a2a-lessons.md +0 -316
  45. package/docs/middleware-guide.md +0 -448
  46. package/docs/readme-update-checklist.md +0 -90
  47. package/docs/reputation-guide.md +0 -396
  48. package/docs/rfcs/001-reputation-system.md +0 -712
  49. package/docs/security-design.md +0 -247
  50. package/install.sh +0 -231
  51. package/packages/openclaw-adapter/README.md +0 -510
  52. package/packages/openclaw-adapter/openclaw.plugin.json +0 -106
  53. package/packages/openclaw-adapter/package.json +0 -40
  54. package/packages/openclaw-adapter/src/announcement-queue.test.ts +0 -449
  55. package/packages/openclaw-adapter/src/announcement-queue.ts +0 -403
  56. package/packages/openclaw-adapter/src/capability-detector.test.ts +0 -99
  57. package/packages/openclaw-adapter/src/capability-detector.ts +0 -183
  58. package/packages/openclaw-adapter/src/claim-handlers.test.ts +0 -974
  59. package/packages/openclaw-adapter/src/claim-handlers.ts +0 -482
  60. package/packages/openclaw-adapter/src/connector.business.test.ts +0 -583
  61. package/packages/openclaw-adapter/src/connector.ts +0 -795
  62. package/packages/openclaw-adapter/src/index.test.ts +0 -82
  63. package/packages/openclaw-adapter/src/index.ts +0 -18
  64. package/packages/openclaw-adapter/src/integration.e2e.test.ts +0 -829
  65. package/packages/openclaw-adapter/src/logger.ts +0 -51
  66. package/packages/openclaw-adapter/src/network-client.test.ts +0 -266
  67. package/packages/openclaw-adapter/src/network-client.ts +0 -251
  68. package/packages/openclaw-adapter/src/network-recovery.test.ts +0 -465
  69. package/packages/openclaw-adapter/src/node-manager.test.ts +0 -136
  70. package/packages/openclaw-adapter/src/node-manager.ts +0 -429
  71. package/packages/openclaw-adapter/src/plugin.test.ts +0 -439
  72. package/packages/openclaw-adapter/src/plugin.ts +0 -104
  73. package/packages/openclaw-adapter/src/reputation.test.ts +0 -221
  74. package/packages/openclaw-adapter/src/reputation.ts +0 -368
  75. package/packages/openclaw-adapter/src/task-guard.test.ts +0 -502
  76. package/packages/openclaw-adapter/src/task-guard.ts +0 -860
  77. package/packages/openclaw-adapter/src/task-queue.concurrency.test.ts +0 -462
  78. package/packages/openclaw-adapter/src/task-queue.edge-cases.test.ts +0 -284
  79. package/packages/openclaw-adapter/src/task-queue.persistence.test.ts +0 -408
  80. package/packages/openclaw-adapter/src/task-queue.ts +0 -668
  81. package/packages/openclaw-adapter/src/tool-handlers.test.ts +0 -906
  82. package/packages/openclaw-adapter/src/tool-handlers.ts +0 -574
  83. package/packages/openclaw-adapter/src/types.ts +0 -361
  84. package/packages/openclaw-adapter/src/webhook-pusher.test.ts +0 -188
  85. package/packages/openclaw-adapter/src/webhook-pusher.ts +0 -220
  86. package/packages/openclaw-adapter/src/webhook-server.test.ts +0 -580
  87. package/packages/openclaw-adapter/src/webhook-server.ts +0 -202
  88. package/packages/openclaw-adapter/tsconfig.json +0 -20
  89. package/src/cli/commands.test.ts +0 -157
  90. package/src/cli/commands.ts +0 -129
  91. package/src/cli/index.test.ts +0 -77
  92. package/src/cli/index.ts +0 -234
  93. package/src/core/autonomous-economy.test.ts +0 -291
  94. package/src/core/autonomous-economy.ts +0 -428
  95. package/src/core/e2ee-crypto.test.ts +0 -125
  96. package/src/core/e2ee-crypto.ts +0 -246
  97. package/src/core/f2a.test.ts +0 -269
  98. package/src/core/f2a.ts +0 -618
  99. package/src/core/p2p-network.test.ts +0 -199
  100. package/src/core/p2p-network.ts +0 -1432
  101. package/src/core/reputation-security.test.ts +0 -403
  102. package/src/core/reputation-security.ts +0 -562
  103. package/src/core/reputation.test.ts +0 -260
  104. package/src/core/reputation.ts +0 -576
  105. package/src/core/review-committee.test.ts +0 -380
  106. package/src/core/review-committee.ts +0 -401
  107. package/src/core/token-manager.test.ts +0 -133
  108. package/src/core/token-manager.ts +0 -140
  109. package/src/daemon/control-server.test.ts +0 -216
  110. package/src/daemon/control-server.ts +0 -292
  111. package/src/daemon/index.test.ts +0 -85
  112. package/src/daemon/index.ts +0 -89
  113. package/src/daemon/main.ts +0 -44
  114. package/src/daemon/start.ts +0 -29
  115. package/src/daemon/webhook.test.ts +0 -68
  116. package/src/daemon/webhook.ts +0 -105
  117. package/src/index.test.ts +0 -436
  118. package/src/index.ts +0 -72
  119. package/src/types/index.test.ts +0 -87
  120. package/src/types/index.ts +0 -341
  121. package/src/types/result.ts +0 -68
  122. package/src/utils/benchmark.ts +0 -237
  123. package/src/utils/logger.ts +0 -331
  124. package/src/utils/middleware.ts +0 -229
  125. package/src/utils/rate-limiter.ts +0 -207
  126. package/src/utils/signature.ts +0 -136
  127. package/src/utils/validation.ts +0 -186
  128. package/tests/docker/Dockerfile.node +0 -23
  129. package/tests/docker/Dockerfile.runner +0 -18
  130. package/tests/docker/docker-compose.test.yml +0 -73
  131. package/tests/integration/message-passing.test.ts +0 -109
  132. package/tests/integration/multi-node.test.ts +0 -92
  133. package/tests/integration/p2p-connection.test.ts +0 -83
  134. package/tests/integration/test-config.ts +0 -32
  135. package/tsconfig.json +0 -21
  136. package/vitest.config.ts +0 -26
@@ -1,428 +0,0 @@
1
- /**
2
- * F2A 自治经济系统
3
- * Phase 4: 信誉消耗、评审激励、优先级调度
4
- */
5
-
6
- import { Logger } from '../utils/logger.js';
7
- import { ReputationManager } from './reputation.js';
8
- import { ReviewCommittee, ReviewResult } from './review-committee.js';
9
-
10
- // ============================================================================
11
- // 类型定义
12
- // ============================================================================
13
-
14
- /**
15
- * 任务请求
16
- */
17
- export interface TaskRequest {
18
- taskId: string;
19
- requesterId: string;
20
- capability: string;
21
- description: string;
22
- parameters?: Record<string, unknown>;
23
- timeout?: number;
24
- estimatedComplexity?: number;
25
- }
26
-
27
- /**
28
- * 任务成本估算
29
- */
30
- export interface TaskCost {
31
- baseCost: number;
32
- discount: number;
33
- finalCost: number;
34
- priority: number;
35
- }
36
-
37
- /**
38
- * 任务奖励
39
- */
40
- export interface TaskReward {
41
- executorReward: number;
42
- reviewerReward: number;
43
- requesterRefund: number;
44
- }
45
-
46
- /**
47
- * 经济配置
48
- */
49
- export interface EconomyConfig {
50
- /** 基础任务成本 */
51
- baseTaskCost: number;
52
- /** 复杂度系数 */
53
- complexityMultiplier: number;
54
- /** 执行者奖励比例 */
55
- executorRewardRate: number;
56
- /** 评审者奖励比例 */
57
- reviewerRewardRate: number;
58
- /** 任务超时惩罚 */
59
- timeoutPenalty: number;
60
- /** 拒绝任务惩罚 */
61
- rejectionPenalty: number;
62
- }
63
-
64
- /**
65
- * 优先级队列项
66
- */
67
- export interface PriorityQueueItem {
68
- task: TaskRequest;
69
- priority: number;
70
- cost: number;
71
- deducted: boolean;
72
- timestamp: number;
73
- }
74
-
75
- /**
76
- * 任务执行结果
77
- */
78
- export interface TaskExecutionResult {
79
- taskId: string;
80
- executorId: string;
81
- status: 'success' | 'failure' | 'timeout' | 'rejected';
82
- result?: unknown;
83
- error?: string;
84
- reviewResult?: ReviewResult;
85
- }
86
-
87
- // ============================================================================
88
- // 默认配置
89
- // ============================================================================
90
-
91
- const DEFAULT_ECONOMY_CONFIG: EconomyConfig = {
92
- baseTaskCost: 5,
93
- complexityMultiplier: 0.1,
94
- executorRewardRate: 0.5,
95
- reviewerRewardRate: 0.2,
96
- timeoutPenalty: 15,
97
- rejectionPenalty: 5,
98
- };
99
-
100
- // ============================================================================
101
- // 自治经济管理器
102
- // ============================================================================
103
-
104
- export class AutonomousEconomy {
105
- private config: EconomyConfig;
106
- private reputationManager: ReputationManager;
107
- private reviewCommittee: ReviewCommittee;
108
- private taskQueue: PriorityQueueItem[] = [];
109
- private pendingTasks: Map<string, PriorityQueueItem> = new Map();
110
- private logger: Logger;
111
-
112
- constructor(
113
- reputationManager: ReputationManager,
114
- reviewCommittee: ReviewCommittee,
115
- config: Partial<EconomyConfig> = {}
116
- ) {
117
- this.config = { ...DEFAULT_ECONOMY_CONFIG, ...config };
118
- this.reputationManager = reputationManager;
119
- this.reviewCommittee = reviewCommittee;
120
- this.logger = new Logger({ component: 'AutonomousEconomy' });
121
- }
122
-
123
- /**
124
- * 提交任务(消耗信誉)
125
- */
126
- submitTask(task: TaskRequest): { success: boolean; cost?: TaskCost; error?: string } {
127
- // 检查发布权限
128
- if (!this.reputationManager.hasPermission(task.requesterId, 'publish')) {
129
- return { success: false, error: 'No permission to publish tasks' };
130
- }
131
-
132
- // 计算成本
133
- const cost = this.calculateTaskCost(task);
134
-
135
- // 检查信誉是否足够
136
- const reputation = this.reputationManager.getReputation(task.requesterId);
137
- if (reputation.score < cost.finalCost) {
138
- return {
139
- success: false,
140
- error: `Insufficient reputation: ${reputation.score.toFixed(1)} < ${cost.finalCost.toFixed(1)}`,
141
- };
142
- }
143
-
144
- // 预扣信誉
145
- this.reputationManager.recordFailure(
146
- task.requesterId,
147
- `task-submit-${task.taskId}`,
148
- 'Task submission cost',
149
- -cost.finalCost
150
- );
151
-
152
- // 加入优先级队列
153
- const queueItem: PriorityQueueItem = {
154
- task,
155
- priority: cost.priority,
156
- cost: cost.finalCost,
157
- deducted: true,
158
- timestamp: Date.now(),
159
- };
160
-
161
- this.taskQueue.push(queueItem);
162
- this.taskQueue.sort((a, b) => b.priority - a.priority);
163
- this.pendingTasks.set(task.taskId, queueItem);
164
-
165
- this.logger.info('Task submitted', {
166
- taskId: task.taskId,
167
- requesterId: task.requesterId.slice(0, 16),
168
- cost: cost.finalCost,
169
- priority: cost.priority,
170
- });
171
-
172
- return { success: true, cost };
173
- }
174
-
175
- /**
176
- * 计算任务成本
177
- */
178
- calculateTaskCost(task: TaskRequest): TaskCost {
179
- const complexity = task.estimatedComplexity || 1;
180
- const baseCost = this.config.baseTaskCost * complexity;
181
-
182
- // 获取折扣
183
- const discount = this.reputationManager.getPublishDiscount(task.requesterId);
184
- const finalCost = Math.floor(baseCost * discount);
185
-
186
- // 获取优先级
187
- const priority = this.reputationManager.getPublishPriority(task.requesterId);
188
-
189
- return {
190
- baseCost,
191
- discount,
192
- finalCost,
193
- priority,
194
- };
195
- }
196
-
197
- /**
198
- * 分配任务给执行者
199
- */
200
- assignTask(taskId: string, executorId: string): boolean {
201
- const queueItem = this.pendingTasks.get(taskId);
202
- if (!queueItem) return false;
203
-
204
- // 检查执行者权限
205
- if (!this.reputationManager.hasPermission(executorId, 'execute')) {
206
- this.logger.warn('Executor lacks permission', { executorId: executorId.slice(0, 16) });
207
- return false;
208
- }
209
-
210
- this.logger.info('Task assigned', {
211
- taskId,
212
- executorId: executorId.slice(0, 16),
213
- });
214
-
215
- return true;
216
- }
217
-
218
- /**
219
- * 完成任务并结算
220
- */
221
- completeTask(result: TaskExecutionResult): TaskReward | null {
222
- const queueItem = this.pendingTasks.get(result.taskId);
223
- if (!queueItem) return null;
224
-
225
- const task = queueItem.task;
226
- let reward: TaskReward = {
227
- executorReward: 0,
228
- reviewerReward: 0,
229
- requesterRefund: 0,
230
- };
231
-
232
- switch (result.status) {
233
- case 'success':
234
- // 任务成功
235
- if (result.reviewResult) {
236
- reward = this.calculateRewardFromReview(
237
- task,
238
- result.executorId,
239
- result.reviewResult
240
- );
241
- } else {
242
- // 无评审结果,使用默认奖励
243
- reward.executorReward = queueItem.cost * this.config.executorRewardRate;
244
- }
245
-
246
- // 奖励执行者
247
- this.reputationManager.recordSuccess(
248
- result.executorId,
249
- result.taskId,
250
- reward.executorReward
251
- );
252
-
253
- // 部分返还请求者
254
- if (reward.requesterRefund > 0) {
255
- this.reputationManager.recordSuccess(
256
- task.requesterId,
257
- `refund-${result.taskId}`,
258
- reward.requesterRefund
259
- );
260
- }
261
-
262
- this.logger.info('Task completed successfully', {
263
- taskId: result.taskId,
264
- executorReward: reward.executorReward,
265
- requesterRefund: reward.requesterRefund,
266
- });
267
- break;
268
-
269
- case 'failure':
270
- // 任务失败
271
- this.reputationManager.recordFailure(
272
- result.executorId,
273
- result.taskId,
274
- result.error || 'Task failed'
275
- );
276
- this.logger.warn('Task failed', { taskId: result.taskId, error: result.error });
277
- break;
278
-
279
- case 'timeout':
280
- // 任务超时
281
- this.reputationManager.recordFailure(
282
- result.executorId,
283
- result.taskId,
284
- 'Task timeout',
285
- -this.config.timeoutPenalty
286
- );
287
- this.logger.warn('Task timeout', { taskId: result.taskId });
288
- break;
289
-
290
- case 'rejected':
291
- // 任务被拒绝
292
- this.reputationManager.recordRejection(
293
- result.executorId,
294
- result.taskId,
295
- result.error || 'Task rejected'
296
- );
297
- break;
298
- }
299
-
300
- // 清理
301
- this.pendingTasks.delete(result.taskId);
302
- this.taskQueue = this.taskQueue.filter(item => item.task.taskId !== result.taskId);
303
-
304
- return reward;
305
- }
306
-
307
- /**
308
- * 从评审结果计算奖励
309
- */
310
- calculateRewardFromReview(
311
- task: TaskRequest,
312
- executorId: string,
313
- reviewResult: ReviewResult
314
- ): TaskReward {
315
- const { finalWorkload, finalValue } = reviewResult;
316
-
317
- // 执行者奖励 = 工作量 × 价值系数
318
- const valueFactor = (finalValue + 100) / 200; // 归一化到 0-1
319
- const executorReward = finalWorkload * valueFactor * this.config.executorRewardRate;
320
-
321
- // 评审者奖励(在 ReviewCommittee 中已处理)
322
- const reviewerReward = reviewResult.reviews.length * 3;
323
-
324
- // 请求者返还
325
- let requesterRefund = 0;
326
- if (finalValue > 0) {
327
- // 正价值任务,部分返还
328
- requesterRefund = finalWorkload * 0.1;
329
- }
330
-
331
- return {
332
- executorReward,
333
- reviewerReward,
334
- requesterRefund,
335
- };
336
- }
337
-
338
- /**
339
- * 获取下一个待处理任务
340
- */
341
- getNextTask(): PriorityQueueItem | null {
342
- return this.taskQueue.length > 0 ? this.taskQueue[0] : null;
343
- }
344
-
345
- /**
346
- * 获取队列长度
347
- */
348
- getQueueLength(): number {
349
- return this.taskQueue.length;
350
- }
351
-
352
- /**
353
- * 获取待处理任务
354
- */
355
- getPendingTask(taskId: string): PriorityQueueItem | null {
356
- return this.pendingTasks.get(taskId) || null;
357
- }
358
-
359
- /**
360
- * 取消任务(返还部分信誉)
361
- */
362
- cancelTask(taskId: string): boolean {
363
- const queueItem = this.pendingTasks.get(taskId);
364
- if (!queueItem) return false;
365
-
366
- // 返还部分信誉
367
- const refund = queueItem.cost * 0.5;
368
- this.reputationManager.recordSuccess(
369
- queueItem.task.requesterId,
370
- `cancel-${taskId}`,
371
- refund
372
- );
373
-
374
- // 清理
375
- this.pendingTasks.delete(taskId);
376
- this.taskQueue = this.taskQueue.filter(item => item.task.taskId !== taskId);
377
-
378
- this.logger.info('Task cancelled', {
379
- taskId,
380
- refund,
381
- });
382
-
383
- return true;
384
- }
385
-
386
- /**
387
- * 获取经济统计
388
- */
389
- getEconomyStats(): {
390
- pendingTasks: number;
391
- queueLength: number;
392
- totalCostDeducted: number;
393
- } {
394
- const totalCostDeducted = Array.from(this.pendingTasks.values())
395
- .filter(item => item.deducted)
396
- .reduce((sum, item) => sum + item.cost, 0);
397
-
398
- return {
399
- pendingTasks: this.pendingTasks.size,
400
- queueLength: this.taskQueue.length,
401
- totalCostDeducted,
402
- };
403
- }
404
-
405
- /**
406
- * 清理过期任务
407
- */
408
- cleanupExpiredTasks(maxAge: number = 24 * 60 * 60 * 1000): string[] {
409
- const now = Date.now();
410
- const expired: string[] = [];
411
-
412
- for (const [taskId, item] of this.pendingTasks) {
413
- if (now - item.timestamp > maxAge) {
414
- expired.push(taskId);
415
- this.cancelTask(taskId);
416
- }
417
- }
418
-
419
- if (expired.length > 0) {
420
- this.logger.info('Cleaned up expired tasks', { count: expired.length });
421
- }
422
-
423
- return expired;
424
- }
425
- }
426
-
427
- // 默认导出
428
- export default AutonomousEconomy;
@@ -1,125 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { E2EECrypto } from './e2ee-crypto.js';
3
-
4
- describe('E2EECrypto', () => {
5
- let cryptoA: E2EECrypto;
6
- let cryptoB: E2EECrypto;
7
-
8
- beforeEach(async () => {
9
- cryptoA = new E2EECrypto();
10
- cryptoB = new E2EECrypto();
11
- await cryptoA.initialize();
12
- await cryptoB.initialize();
13
- });
14
-
15
- describe('initialization', () => {
16
- it('should generate key pair on initialize', async () => {
17
- const publicKey = cryptoA.getPublicKey();
18
- expect(publicKey).not.toBeNull();
19
- expect(typeof publicKey).toBe('string');
20
- expect(publicKey!.length).toBeGreaterThan(0);
21
- });
22
-
23
- it('should generate different keys for different instances', async () => {
24
- const keyA = cryptoA.getPublicKey();
25
- const keyB = cryptoB.getPublicKey();
26
- expect(keyA).not.toBe(keyB);
27
- });
28
-
29
- it('should export and import key pair', () => {
30
- const exported = cryptoA.exportKeyPair();
31
- expect(exported).not.toBeNull();
32
- expect(exported!.publicKey).toBeDefined();
33
- expect(exported!.privateKey).toBeDefined();
34
-
35
- // Create new instance and import
36
- const cryptoC = new E2EECrypto();
37
- const privateKey = Buffer.from(exported!.privateKey, 'base64');
38
- const publicKey = Buffer.from(exported!.publicKey, 'base64');
39
- cryptoC.initializeWithKeyPair(privateKey, publicKey);
40
-
41
- expect(cryptoC.getPublicKey()).toBe(exported!.publicKey);
42
- });
43
- });
44
-
45
- describe('peer key registration', () => {
46
- it('should register peer public key', () => {
47
- const keyB = cryptoB.getPublicKey()!;
48
- cryptoA.registerPeerPublicKey('peer-b', keyB);
49
- expect(cryptoA.canEncryptTo('peer-b')).toBe(true);
50
- });
51
-
52
- it('should track registered peer count', () => {
53
- expect(cryptoA.getRegisteredPeerCount()).toBe(0);
54
- cryptoA.registerPeerPublicKey('peer-1', cryptoB.getPublicKey()!);
55
- expect(cryptoA.getRegisteredPeerCount()).toBe(1);
56
- });
57
- });
58
-
59
- describe('encryption/decryption', () => {
60
- beforeEach(() => {
61
- // Exchange public keys
62
- cryptoA.registerPeerPublicKey('peer-b', cryptoB.getPublicKey()!);
63
- cryptoB.registerPeerPublicKey('peer-a', cryptoA.getPublicKey()!);
64
- });
65
-
66
- it('should encrypt and decrypt message', () => {
67
- const plaintext = 'Hello, secure world!';
68
- const encrypted = cryptoA.encrypt('peer-b', plaintext);
69
-
70
- expect(encrypted).not.toBeNull();
71
- expect(encrypted!.ciphertext).toBeDefined();
72
- expect(encrypted!.iv).toBeDefined();
73
- expect(encrypted!.authTag).toBeDefined();
74
-
75
- const decrypted = cryptoB.decrypt(encrypted!);
76
- expect(decrypted).toBe(plaintext);
77
- });
78
-
79
- it('should encrypt with AAD', () => {
80
- const plaintext = 'Secret message';
81
- const aad = 'message-metadata';
82
-
83
- const encrypted = cryptoA.encrypt('peer-b', plaintext, aad);
84
- expect(encrypted).not.toBeNull();
85
- expect(encrypted!.aad).toBe(aad);
86
-
87
- const decrypted = cryptoB.decrypt(encrypted!);
88
- expect(decrypted).toBe(plaintext);
89
- });
90
-
91
- it('should fail to decrypt tampered ciphertext', () => {
92
- const plaintext = 'Original message';
93
- const encrypted = cryptoA.encrypt('peer-b', plaintext);
94
-
95
- // Tamper with ciphertext
96
- encrypted!.ciphertext = encrypted!.ciphertext.slice(0, -4) + 'xxxx';
97
-
98
- const decrypted = cryptoB.decrypt(encrypted!);
99
- expect(decrypted).toBeNull(); // Should fail
100
- });
101
-
102
- it('should return null when encrypting to unknown peer', async () => {
103
- const cryptoC = new E2EECrypto();
104
- await cryptoC.initialize();
105
- // Don't register any peer keys
106
-
107
- const result = cryptoC.encrypt('unknown-peer', 'test');
108
- expect(result).toBeNull();
109
- });
110
- });
111
-
112
- describe('error handling', () => {
113
- it('should return null when decrypting malformed message', () => {
114
- const malformed = {
115
- senderPublicKey: 'invalid-base64!!!',
116
- iv: Buffer.from('invalid').toString('base64'),
117
- authTag: Buffer.from('short').toString('base64'),
118
- ciphertext: 'garbage'
119
- };
120
-
121
- const decrypted = cryptoA.decrypt(malformed as any);
122
- expect(decrypted).toBeNull();
123
- });
124
- });
125
- });