wowok 2.1.17 → 2.1.19

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 (97) hide show
  1. package/dist/cjs/w/call/base.js +1 -0
  2. package/dist/cjs/w/call/base.js.map +1 -1
  3. package/dist/cjs/w/call/entity.js +1 -0
  4. package/dist/cjs/w/call/entity.js.map +1 -1
  5. package/dist/cjs/w/call/passport.js +1 -0
  6. package/dist/cjs/w/call/passport.js.map +1 -1
  7. package/dist/cjs/w/call/permission.js.map +1 -1
  8. package/dist/cjs/w/call/proof.js +1 -0
  9. package/dist/cjs/w/call/proof.js.map +1 -1
  10. package/dist/cjs/w/call/util.js +1 -0
  11. package/dist/cjs/w/call/util.js.map +1 -1
  12. package/dist/cjs/w/local/account.d.ts +3 -3
  13. package/dist/cjs/w/local/account.js +102 -29
  14. package/dist/cjs/w/local/account.js.map +1 -1
  15. package/dist/cjs/w/local/index.d.ts +1 -1
  16. package/dist/cjs/w/local/index.js +15 -6
  17. package/dist/cjs/w/local/index.js.map +1 -1
  18. package/dist/cjs/w/local/local.js +10 -5
  19. package/dist/cjs/w/local/local.js.map +1 -1
  20. package/dist/cjs/w/local/wip.js +1 -0
  21. package/dist/cjs/w/local/wip.js.map +1 -1
  22. package/dist/cjs/w/messenger/crypto.js +4 -4
  23. package/dist/cjs/w/messenger/crypto.js.map +1 -1
  24. package/dist/cjs/w/messenger/messenger-api.d.ts +1 -3
  25. package/dist/cjs/w/messenger/messenger-api.js +109 -56
  26. package/dist/cjs/w/messenger/messenger-api.js.map +1 -1
  27. package/dist/cjs/w/messenger/messenger-manager.d.ts +1 -6
  28. package/dist/cjs/w/messenger/messenger-manager.js +95 -150
  29. package/dist/cjs/w/messenger/messenger-manager.js.map +1 -1
  30. package/dist/cjs/w/messenger/messenger.d.ts +90 -31
  31. package/dist/cjs/w/messenger/messenger.js +517 -443
  32. package/dist/cjs/w/messenger/messenger.js.map +1 -1
  33. package/dist/cjs/w/messenger/server.d.ts +9 -1
  34. package/dist/cjs/w/messenger/server.js +56 -5
  35. package/dist/cjs/w/messenger/server.js.map +1 -1
  36. package/dist/cjs/w/messenger/session.d.ts +60 -10
  37. package/dist/cjs/w/messenger/session.js +492 -182
  38. package/dist/cjs/w/messenger/session.js.map +1 -1
  39. package/dist/cjs/w/messenger/storage.d.ts +30 -0
  40. package/dist/cjs/w/messenger/storage.js +143 -8
  41. package/dist/cjs/w/messenger/storage.js.map +1 -1
  42. package/dist/cjs/w/messenger/types.d.ts +37 -2
  43. package/dist/cjs/w/messenger/types.js +14 -3
  44. package/dist/cjs/w/messenger/types.js.map +1 -1
  45. package/dist/cjs/w/query/object.js +1 -0
  46. package/dist/cjs/w/query/object.js.map +1 -1
  47. package/dist/cjs/w/util.js +1 -0
  48. package/dist/cjs/w/util.js.map +1 -1
  49. package/dist/esm/w/call/base.js +1 -0
  50. package/dist/esm/w/call/base.js.map +1 -1
  51. package/dist/esm/w/call/entity.js +1 -0
  52. package/dist/esm/w/call/entity.js.map +1 -1
  53. package/dist/esm/w/call/passport.js +1 -0
  54. package/dist/esm/w/call/passport.js.map +1 -1
  55. package/dist/esm/w/call/permission.js.map +1 -1
  56. package/dist/esm/w/call/proof.js +1 -0
  57. package/dist/esm/w/call/proof.js.map +1 -1
  58. package/dist/esm/w/call/util.js +1 -0
  59. package/dist/esm/w/call/util.js.map +1 -1
  60. package/dist/esm/w/local/account.d.ts +3 -3
  61. package/dist/esm/w/local/account.js +102 -29
  62. package/dist/esm/w/local/account.js.map +1 -1
  63. package/dist/esm/w/local/index.d.ts +1 -1
  64. package/dist/esm/w/local/index.js +15 -6
  65. package/dist/esm/w/local/index.js.map +1 -1
  66. package/dist/esm/w/local/local.js +10 -5
  67. package/dist/esm/w/local/local.js.map +1 -1
  68. package/dist/esm/w/local/wip.js +1 -0
  69. package/dist/esm/w/local/wip.js.map +1 -1
  70. package/dist/esm/w/messenger/crypto.js +4 -4
  71. package/dist/esm/w/messenger/crypto.js.map +1 -1
  72. package/dist/esm/w/messenger/messenger-api.d.ts +1 -3
  73. package/dist/esm/w/messenger/messenger-api.js +109 -56
  74. package/dist/esm/w/messenger/messenger-api.js.map +1 -1
  75. package/dist/esm/w/messenger/messenger-manager.d.ts +1 -6
  76. package/dist/esm/w/messenger/messenger-manager.js +95 -150
  77. package/dist/esm/w/messenger/messenger-manager.js.map +1 -1
  78. package/dist/esm/w/messenger/messenger.d.ts +90 -31
  79. package/dist/esm/w/messenger/messenger.js +517 -443
  80. package/dist/esm/w/messenger/messenger.js.map +1 -1
  81. package/dist/esm/w/messenger/server.d.ts +9 -1
  82. package/dist/esm/w/messenger/server.js +56 -5
  83. package/dist/esm/w/messenger/server.js.map +1 -1
  84. package/dist/esm/w/messenger/session.d.ts +60 -10
  85. package/dist/esm/w/messenger/session.js +492 -182
  86. package/dist/esm/w/messenger/session.js.map +1 -1
  87. package/dist/esm/w/messenger/storage.d.ts +30 -0
  88. package/dist/esm/w/messenger/storage.js +143 -8
  89. package/dist/esm/w/messenger/storage.js.map +1 -1
  90. package/dist/esm/w/messenger/types.d.ts +37 -2
  91. package/dist/esm/w/messenger/types.js +14 -3
  92. package/dist/esm/w/messenger/types.js.map +1 -1
  93. package/dist/esm/w/query/object.js +1 -0
  94. package/dist/esm/w/query/object.js.map +1 -1
  95. package/dist/esm/w/util.js +1 -0
  96. package/dist/esm/w/util.js.map +1 -1
  97. package/package.json +1 -2
@@ -17,33 +17,40 @@
17
17
  import { createHash } from "crypto";
18
18
  import * as fs from "fs";
19
19
  import * as path from "path";
20
- import { CallProof } from "../call/proof.js";
21
- import { MessengerSession } from "./session.js";
20
+ // eslint-disable-next-line import/no-cycle
21
+ import { MessengerSession, DecryptionEngine } from "./session.js";
22
22
  import { MessengerServerClient } from "./server.js";
23
23
  import { MessageStorage, SessionStateStorage } from "./storage.js";
24
24
  import { hashPlaintext, verifyMessage, bytesToBase64 } from "./crypto.js";
25
25
  import { canonicalizeJson } from "./utils.js";
26
26
  import { DEFAULT_MESSENGER_CONFIG, MessengerError, MessengerErrorCode, MessageDirection, MessageStatus, WTS_FILE_BYTES_LIMIT, NORMAL_MESSAGE_BYTES_LIMIT, CHAIN_PROOF_TYPE, } from "./types.js";
27
27
  import { isValidWowAddress } from "../../utils/sui-types.js";
28
- import { Account } from "../local/account.js";
29
- import { EventSource as EventSourcePolyfill } from "eventsource";
30
- // Polyfill EventSource for Node.js environment
31
- if (typeof window === "undefined" &&
32
- typeof globalThis.EventSource === "undefined") {
33
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
- globalThis.EventSource = EventSourcePolyfill;
35
- console.log("[EventSource] Successfully polyfilled EventSource");
28
+ // 动态获取 Account 实例的辅助函数
29
+ async function getAccount() {
30
+ // eslint-disable-next-line import/no-cycle
31
+ const { Account } = await import("../local/account.js");
32
+ return Account.Instance();
36
33
  }
37
34
  export class Messenger {
38
35
  session;
39
36
  serverClient;
40
37
  config;
41
38
  userAddress = null;
42
- eventSource = null;
43
39
  onMessageCallback = null;
44
- prekeyCheckTimer = null;
40
+ pollingTimer = null;
41
+ messageConsecutiveEmptyPulls = 0;
42
+ prekeyConsecutiveOkCount = 0;
43
+ currentMessageInterval;
44
+ isPollingRunning = false;
45
45
  messageStorage;
46
46
  sessionStateStorage;
47
+ decryptionEngine;
48
+ // 【新增】等待解密的消息池(用于 Skip Keys 机制)
49
+ waitingMessages = new Map();
50
+ // 【新增】解密失败的消息(用于用户决策重发)
51
+ failedMessages = new Map();
52
+ // 【新增】重试计数器(3秒×3次机制)
53
+ waitingMessageRetries = new Map();
47
54
  constructor(userAddress, config) {
48
55
  this.userAddress = userAddress;
49
56
  this.config = { ...DEFAULT_MESSENGER_CONFIG, ...config };
@@ -51,6 +58,9 @@ export class Messenger {
51
58
  this.serverClient = new MessengerServerClient(this.config);
52
59
  this.messageStorage = new MessageStorage(userAddress);
53
60
  this.sessionStateStorage = new SessionStateStorage(userAddress);
61
+ this.decryptionEngine = new DecryptionEngine(this.session["store"]); // 使用 session 的 store
62
+ this.currentMessageInterval =
63
+ this.config.message_poll_default_interval_ms ?? 6 * 60 * 1000;
54
64
  }
55
65
  /**
56
66
  * 获取用户地址
@@ -70,7 +80,7 @@ export class Messenger {
70
80
  if (!this.userAddress) {
71
81
  throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, "User address not set");
72
82
  }
73
- const account = await Account.Instance().get(this.userAddress, false);
83
+ const account = await (await getAccount()).get(this.userAddress, false);
74
84
  return account?.pubkey || "";
75
85
  }
76
86
  /**
@@ -93,7 +103,7 @@ export class Messenger {
93
103
  if (!this.userAddress) {
94
104
  throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, "User address not set");
95
105
  }
96
- const account = await Account.Instance().get(this.userAddress, false);
106
+ const account = await (await getAccount()).get(this.userAddress, false);
97
107
  if (!account?.secret) {
98
108
  throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, `Account not found or no secret key for ${this.userAddress}`);
99
109
  }
@@ -126,20 +136,25 @@ export class Messenger {
126
136
  * 2. 注册设备到服务器
127
137
  * 3. 上传预密钥
128
138
  * 4. 检查预密钥状态(如低于阈值则补充)
129
- * 5. 启动定期预密钥检查
139
+ * 5. 启动合并的polling timer
130
140
  */
131
141
  async initialize() {
132
142
  if (!this.userAddress) {
133
143
  throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, "User address not set");
134
144
  }
135
- // 确保身份并注册设备
145
+ // 确保身份
136
146
  await this.session.ensureIdentity(this.userAddress);
147
+ // 【更新】每次都注册/更新设备!
148
+ // Signal Protocol 最佳实践:每次初始化都可以更新预键
149
+ // - 已有会话不受影响(使用双棘轮动态密钥)
150
+ // - 新会话使用新的预键(确保本地和服务器一致)
151
+ //console.log(`[Messenger] Registering/updating device...`);
137
152
  await this.session.registerDevice(this.userAddress);
138
153
  await this.session.ensurePreKeys(this.userAddress);
139
154
  // 初始化时检查预密钥状态
140
155
  await this.checkAndRefillPrekeys();
141
- // 启动定期预密钥检查
142
- this.startPrekeyCheckTimer();
156
+ // 启动合并的polling timer
157
+ this.startPollingTimer();
143
158
  }
144
159
  /**
145
160
  * 检查并补充预密钥
@@ -153,26 +168,112 @@ export class Messenger {
153
168
  await this.session.ensurePreKeys(this.userAddress, false);
154
169
  }
155
170
  /**
156
- * 启动预密钥定期检查定时器
171
+ * 启动合并的polling timer
157
172
  */
158
- startPrekeyCheckTimer() {
159
- if (this.prekeyCheckTimer) {
160
- clearInterval(this.prekeyCheckTimer);
173
+ startPollingTimer() {
174
+ if (this.pollingTimer) {
175
+ clearTimeout(this.pollingTimer);
161
176
  }
162
- const interval = this.config.prekeyCheckIntervalMs ?? 24 * 60 * 60 * 1000; // 默认1天
163
- this.prekeyCheckTimer = setInterval(() => {
164
- this.checkAndRefillPrekeys();
177
+ this.isPollingRunning = true;
178
+ this.scheduleNextPoll();
179
+ }
180
+ /**
181
+ * 停止polling timer
182
+ */
183
+ stopPollingTimer() {
184
+ this.isPollingRunning = false;
185
+ if (this.pollingTimer) {
186
+ clearTimeout(this.pollingTimer);
187
+ this.pollingTimer = null;
188
+ }
189
+ }
190
+ /**
191
+ * 安排下一次poll
192
+ */
193
+ scheduleNextPoll() {
194
+ if (!this.isPollingRunning)
195
+ return;
196
+ const interval = this.getNextPollInterval();
197
+ this.pollingTimer = setTimeout(() => {
198
+ this.poll()
199
+ .catch((error) => {
200
+ console.error("[Polling] Error during poll:", error);
201
+ })
202
+ .finally(() => {
203
+ this.scheduleNextPoll();
204
+ });
165
205
  }, interval);
166
- //console.log(`Prekey check timer started (interval: ${interval}ms)`);
167
206
  }
168
207
  /**
169
- * 停止预密钥定期检查定时器
208
+ * 获取下次poll的间隔时间
209
+ * 【优化】增加3秒快速模式(有待解密消息时)
210
+ */
211
+ getNextPollInterval() {
212
+ // 如果有等待解密的消息,使用3秒快速轮询
213
+ if (this.waitingMessages.size > 0) {
214
+ return this.config.message_poll_waiting_interval_ms ?? 3 * 1000;
215
+ }
216
+ return this.currentMessageInterval;
217
+ }
218
+ /**
219
+ * 执行一次poll(拉取消息和检查prekey状态)
220
+ */
221
+ async poll() {
222
+ if (!this.userAddress)
223
+ return;
224
+ try {
225
+ const response = await this.pullMessages();
226
+ // 处理消息
227
+ if (response.messages.length > 0) {
228
+ this.messageConsecutiveEmptyPulls = 0;
229
+ this.currentMessageInterval =
230
+ this.config.message_poll_fast_interval_ms ?? 6 * 1000;
231
+ if (this.onMessageCallback) {
232
+ this.onMessageCallback(response.messages);
233
+ }
234
+ }
235
+ else {
236
+ this.messageConsecutiveEmptyPulls++;
237
+ if (this.messageConsecutiveEmptyPulls >=
238
+ (this.config.message_poll_consecutive_empty_limit ?? 3)) {
239
+ this.currentMessageInterval =
240
+ this.config.message_poll_default_interval_ms ??
241
+ 6 * 60 * 1000;
242
+ this.messageConsecutiveEmptyPulls = 0;
243
+ }
244
+ }
245
+ // 处理prekey状态
246
+ if (response.prekey_status) {
247
+ const prekeyStatus = response.prekey_status;
248
+ if (prekeyStatus.shouldRefill) {
249
+ this.prekeyConsecutiveOkCount = 0;
250
+ await this.checkAndRefillPrekeys();
251
+ }
252
+ else {
253
+ this.prekeyConsecutiveOkCount++;
254
+ if (this.prekeyConsecutiveOkCount >=
255
+ (this.config.prekey_poll_consecutive_ok_limit ?? 3)) {
256
+ this.prekeyConsecutiveOkCount = 0;
257
+ }
258
+ }
259
+ }
260
+ }
261
+ catch (error) {
262
+ console.error("[Polling] Poll error:", error);
263
+ }
264
+ }
265
+ /**
266
+ * 触发快速poll(发送消息后调用)
170
267
  */
171
- stopPrekeyCheckTimer() {
172
- if (this.prekeyCheckTimer) {
173
- clearInterval(this.prekeyCheckTimer);
174
- this.prekeyCheckTimer = null;
175
- //console.log("Prekey check timer stopped");
268
+ triggerFastPoll() {
269
+ this.currentMessageInterval =
270
+ this.config.message_poll_fast_interval_ms ?? 6 * 1000;
271
+ this.messageConsecutiveEmptyPulls = 0;
272
+ if (this.isPollingRunning) {
273
+ if (this.pollingTimer) {
274
+ clearTimeout(this.pollingTimer);
275
+ }
276
+ this.scheduleNextPoll();
176
277
  }
177
278
  }
178
279
  /**
@@ -206,7 +307,7 @@ export class Messenger {
206
307
  const plaintextHash = hashPlaintext(plaintext, createdAt, options?.guardAddress, options?.passportAddress, lastReceivedLeafIndex);
207
308
  // 3. 签名消息
208
309
  // 注意: guard_address 和 passport_address 始终包含在签名中(可能为空字符串),防止参数篡改
209
- const account = await Account.Instance().get(this.userAddress, false);
310
+ const account = await (await getAccount()).get(this.userAddress, false);
210
311
  if (!account) {
211
312
  throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, "User account not found");
212
313
  }
@@ -218,7 +319,7 @@ export class Messenger {
218
319
  const lastReceivedStr = lastReceivedLeafIndex >= 0 ? lastReceivedLeafIndex.toString() : "";
219
320
  const forceStr = options?.force ? "true" : "false";
220
321
  const signMessage = `send_message:${this.userAddress}:${recipientAddress}:${guardAddr}:${passportAddr}:${plaintextHash}:${lastReceivedStr}:${publicKey}:${timestamp}:${nonce}:${forceStr}`;
221
- const signResult = await Account.Instance().signData(this.userAddress, signMessage);
322
+ const signResult = await (await getAccount()).signData(this.userAddress, signMessage);
222
323
  const signatureBuffer = Buffer.from(signResult.signature.slice(2), "hex");
223
324
  const signatureBase64 = bytesToBase64(new Uint8Array(signatureBuffer));
224
325
  // 使用统一的 sendMessage API
@@ -296,6 +397,7 @@ export class Messenger {
296
397
  }
297
398
  }
298
399
  }
400
+ this.triggerFastPoll();
299
401
  return {
300
402
  messageId: response.messageId,
301
403
  status: message.status,
@@ -321,9 +423,9 @@ export class Messenger {
321
423
  const timestamp = Date.now(); //@ 使用ms时间戳
322
424
  const nonce = this.generateNonce();
323
425
  const message = `fetch_messages:${this.userAddress}:${limit || 100}:${timestamp}:${nonce}`;
324
- const account = await Account.Instance().get(this.userAddress, false);
426
+ const account = await (await getAccount()).get(this.userAddress, false);
325
427
  const publicKey = account?.pubkey || "";
326
- const signResult = await Account.Instance().signData(this.userAddress, message);
428
+ const signResult = await (await getAccount()).signData(this.userAddress, message);
327
429
  const signature = Buffer.from(signResult.signature.slice(2), "hex");
328
430
  const signatureParams = {
329
431
  signatureScheme: "ED25519",
@@ -338,149 +440,81 @@ export class Messenger {
338
440
  console.log(`[Messenger] 消息 IDs: ${response.messages.map(m => m.id).join(', ')}`);
339
441
  }*/
340
442
  if (response.messages.length === 0) {
341
- return [];
443
+ return {
444
+ messages: [],
445
+ prekey_status: response.prekey_status,
446
+ };
342
447
  }
343
448
  const decryptedMessages = [];
344
449
  const acknowledgedIds = [];
345
- for (const serverMsg of response.messages) {
346
- try {
347
- //console.log(`[Messenger] 处理消息 ${serverMsg.id}, from=${serverMsg.from}, msgType=${serverMsg.msgType}`);
348
- // 检查消息是否已经在本地存储
349
- // 注意:由于每个用户有自己的数据库文件,消息 ID 不会冲突
350
- const existingMessage = this.messageStorage.getMessage(serverMsg.id);
351
- if (existingMessage) {
352
- // 消息已存在,直接确认
353
- //console.log(`[Messenger] 消息 ${serverMsg.id} 已存在于本地存储,跳过`);
354
- acknowledgedIds.push(serverMsg.id);
355
- continue;
356
- }
357
- // 2. 解密消息
358
- //console.log(`[Messenger] 解密消息 ${serverMsg.id}...`);
359
- const ciphertext = Uint8Array.from(Buffer.from(serverMsg.bodyB64, "base64"));
360
- //console.log(`[Messenger] 密文长度: ${ciphertext.length} bytes`);
361
- const decryptedData = await this.session.decryptMessage(this.userAddress, serverMsg.from, ciphertext.buffer, serverMsg.msgType);
362
- //console.log(`[Messenger] 消息 ${serverMsg.id} 解密成功`);
363
- // 【更新】明文直接就是消息内容(不再是 JSON 格式)
364
- const plaintext = decryptedData;
365
- // 【新增】从服务器返回的字段获取 lastReceivedLeafIndex
366
- const senderLastReceivedIndex = serverMsg.lastReceivedLeafIndex ?? -1;
367
- // 【新增】处理消息确认信息
368
- if (senderLastReceivedIndex >= 0) {
369
- const myLastSent = this.getLastSentLeafIndex(serverMsg.from);
370
- if (senderLastReceivedIndex < myLastSent) {
371
- /*console.warn(
372
- `[Messenger] ${serverMsg.from} 可能丢失了消息,` +
373
- `对方确认: ${senderLastReceivedIndex}, ` +
374
- `我已发送: ${myLastSent}`,
375
- );*/
376
- }
377
- }
378
- // 3. 使用通用验证函数验证消息
379
- // 检查必需字段
380
- if (!serverMsg.clientTimestamp) {
381
- throw new Error(`Missing clientTimestamp for message ${serverMsg.id}`);
382
- }
383
- if (!serverMsg.plaintextHash) {
384
- throw new Error(`Missing plaintextHash for message ${serverMsg.id}`);
385
- }
386
- // 验证 Merkle 元数据完整性
387
- if (serverMsg.merkleMetadata) {
388
- if (!serverMsg.merkleMetadata.prevRoot) {
389
- throw new Error(`Message ${serverMsg.id} missing prevRoot in merkleMetadata`);
390
- }
391
- if (!serverMsg.merkleMetadata.newRoot) {
392
- throw new Error(`Message ${serverMsg.id} missing newRoot in merkleMetadata`);
393
- }
394
- }
395
- const verificationResult = verifyMessage({
396
- messageId: serverMsg.id,
397
- plaintext,
398
- plaintextHash: serverMsg.plaintextHash,
399
- createdAt: serverMsg.clientTimestamp,
400
- guardAddress: serverMsg.guardAddress,
401
- passportAddress: serverMsg.passportAddress,
402
- lastReceivedLeafIndex: serverMsg.lastReceivedLeafIndex, // 【新增】传入消息确认字段
403
- serverSignature: serverMsg.merkleMetadata?.serverSignature,
404
- serverPublicKey: serverMsg.merkleMetadata?.serverPublicKey,
405
- merkleMetadata: serverMsg.merkleMetadata
406
- ? {
407
- prevRoot: serverMsg.merkleMetadata.prevRoot,
408
- newRoot: serverMsg.merkleMetadata.newRoot,
409
- serverTimestamp: serverMsg.merkleMetadata.serverTimestamp,
410
- leafIndex: serverMsg.merkleMetadata.leafIndex,
411
- proofSiblings: serverMsg.merkleMetadata.proofSiblings,
412
- proofIndices: serverMsg.merkleMetadata.proofIndices,
413
- }
414
- : undefined,
415
- });
416
- if (!verificationResult.valid) {
417
- throw new Error(verificationResult.error);
418
- }
419
- // 5. 保存到本地存储
420
- // 经过 verifyMessage 验证,这些字段一定存在
421
- const message = {
422
- messageId: serverMsg.id,
423
- fromAddress: serverMsg.from,
424
- toAddress: this.userAddress,
425
- plaintextHash: serverMsg.plaintextHash,
426
- plaintext,
427
- guardAddress: serverMsg.guardAddress,
428
- passportAddress: serverMsg.passportAddress,
429
- lastReceivedLeafIndex: serverMsg.lastReceivedLeafIndex, // 【新增】保存消息确认字段
430
- direction: MessageDirection.RECEIVED,
431
- status: MessageStatus.CONFIRMED,
432
- msgType: serverMsg.msgType,
433
- leafIndex: serverMsg.merkleMetadata?.leafIndex,
434
- prevRoot: serverMsg.merkleMetadata?.prevRoot,
435
- newRoot: serverMsg.merkleMetadata?.newRoot,
436
- serverSignature: serverMsg.merkleMetadata?.serverSignature,
437
- serverTimestamp: serverMsg.merkleMetadata?.serverTimestamp,
438
- serverPublicKey: serverMsg.merkleMetadata?.serverPublicKey,
439
- createdAt: serverMsg.clientTimestamp,
440
- // 保存 ZIP 元数据(如果是 ZIP 消息)
441
- zipMetadata: serverMsg.zipMetadata,
442
- };
443
- this.messageStorage.saveMessage(message);
444
- // 更新会话状态
445
- if (serverMsg.merkleMetadata) {
446
- this.sessionStateStorage.updateSessionState(this.userAddress, serverMsg.from, {
447
- currentRoot: serverMsg.merkleMetadata.newRoot,
448
- prevRoot: serverMsg.merkleMetadata.prevRoot,
449
- lastLeafIndex: serverMsg.merkleMetadata.leafIndex,
450
- lastSyncAt: Date.now(),
451
- });
452
- }
453
- const timestamp = serverMsg.merkleMetadata?.serverTimestamp ||
454
- serverMsg.clientTimestamp ||
455
- Date.now();
456
- decryptedMessages.push({
457
- id: serverMsg.id,
458
- from: serverMsg.from,
459
- plaintext, // 【更新】明文直接是消息内容
460
- timestamp,
461
- merkleVerified: !!serverMsg.merkleMetadata,
462
- merkleData: serverMsg.merkleMetadata
463
- ? {
464
- leafIndex: serverMsg.merkleMetadata.leafIndex,
465
- rootHash: serverMsg.merkleMetadata.newRoot,
466
- }
467
- : undefined,
468
- });
450
+ // clientTimestamp 排序消息(发送方本地时间)
451
+ const sortedMessages = [...response.messages].sort(function (a, b) {
452
+ return (a.clientTimestamp || 0) - (b.clientTimestamp || 0);
453
+ });
454
+ // 【优化】首先尝试处理 waitingMessages 池中的消息
455
+ await this.processWaitingMessages(decryptedMessages, acknowledgedIds);
456
+ // 处理新拉取的消息(已排序)
457
+ for (const serverMsg of sortedMessages) {
458
+ // 检查是否已在 waitingMessages 池中
459
+ if (this.waitingMessages.has(serverMsg.id)) {
460
+ acknowledgedIds.push(serverMsg.id);
461
+ continue;
462
+ }
463
+ // 检查是否已在 failedMessages 中
464
+ if (this.failedMessages.has(serverMsg.id)) {
469
465
  acknowledgedIds.push(serverMsg.id);
466
+ continue;
470
467
  }
471
- catch (error) {
472
- throw new Error(`Failed to decrypt message ${serverMsg.id}: ${error instanceof Error ? error.message : String(error)}`);
468
+ // 检查消息是否已经在本地存储
469
+ const existingMessage = this.messageStorage.getMessage(serverMsg.id);
470
+ if (existingMessage) {
471
+ // 消息已存在,直接确认
472
+ acknowledgedIds.push(serverMsg.id);
473
+ continue;
474
+ }
475
+ // 尝试解密消息
476
+ const decryptResult = await this.tryDecryptMessage(serverMsg);
477
+ if (decryptResult.success &&
478
+ decryptResult.message &&
479
+ decryptResult.decryptedData) {
480
+ // 解密成功,保存并添加到结果
481
+ this.messageStorage.saveMessage(decryptResult.message);
482
+ decryptedMessages.push(decryptResult.decryptedData);
483
+ acknowledgedIds.push(serverMsg.id);
484
+ // 从 waitingMessages 中移除(如果存在)
485
+ this.waitingMessages.delete(serverMsg.id);
473
486
  }
487
+ else if (decryptResult.shouldRetry) {
488
+ // 需要重试(Skip Keys 机制),加入等待池
489
+ console.warn(`[Messenger] 消息 ${serverMsg.id} 解密失败,加入等待池: ${decryptResult.error}`);
490
+ this.waitingMessages.set(serverMsg.id, serverMsg);
491
+ // 不解密成功,不加入 acknowledgedIds,下次继续尝试
492
+ }
493
+ else {
494
+ // 永久失败,保存失败状态
495
+ console.error(`[Messenger] 消息 ${serverMsg.id} 解密永久失败: ${decryptResult.error}`);
496
+ this.failedMessages.set(serverMsg.id, {
497
+ message: serverMsg,
498
+ error: decryptResult.error || "Unknown error",
499
+ });
500
+ // 保存失败状态到存储
501
+ await this.saveFailedMessage(serverMsg, decryptResult.error || "Unknown error");
502
+ acknowledgedIds.push(serverMsg.id);
503
+ }
504
+ }
505
+ // 【优化】重新调度轮询(如果有等待消息,会切换到3秒快速模式)
506
+ if (this.waitingMessages.size > 0 && this.isPollingRunning) {
507
+ this.reschedulePolling();
474
508
  }
475
509
  // 5. 确认已处理的消息(带签名)
476
510
  if (acknowledgedIds.length > 0 && this.userAddress) {
477
511
  const ackTimestamp = Date.now(); //@ 使用ms时间戳
478
512
  const ackNonce = this.generateNonce();
479
513
  // 签名消息格式: ack_messages:{user}:{message_ids}:{public_key}:{timestamp}:{nonce}
480
- const account = await Account.Instance().get(this.userAddress, false);
514
+ const account = await (await getAccount()).get(this.userAddress, false);
481
515
  if (account?.pubkey) {
482
516
  const ackMessage = `ack_messages:${this.userAddress}:${acknowledgedIds.join(",")}:${account.pubkey}:${ackTimestamp}:${ackNonce}`;
483
- const signResult = await Account.Instance().signData(this.userAddress, ackMessage);
517
+ const signResult = await (await getAccount()).signData(this.userAddress, ackMessage);
484
518
  const signatureBuffer = Buffer.from(signResult.signature.slice(2), "hex");
485
519
  const signatureBase64 = bytesToBase64(new Uint8Array(signatureBuffer));
486
520
  await this.serverClient.acknowledgeMessages(acknowledgedIds, signResult.publicKey, {
@@ -492,9 +526,11 @@ export class Messenger {
492
526
  });
493
527
  }
494
528
  }
495
- // 6. 补充预密钥
496
- await this.session.ensurePreKeys(this.userAddress);
497
- return decryptedMessages;
529
+ // 6. 补充预密钥(poll方法会根据prekey_status来决定是否补充)
530
+ return {
531
+ messages: decryptedMessages,
532
+ prekey_status: response.prekey_status,
533
+ };
498
534
  }
499
535
  /**
500
536
  * 获取最后发送的消息序号
@@ -565,6 +601,7 @@ export class Messenger {
565
601
  timestamp: Date.now(),
566
602
  };
567
603
  // 使用 CallProof 提交到链上
604
+ const { CallProof } = await import("../call/proof.js");
568
605
  const callProof = new CallProof({
569
606
  proof: JSON.stringify(proofData),
570
607
  server_pubkey: serverPubKey,
@@ -585,281 +622,12 @@ export class Messenger {
585
622
  txHash: result?.digest || "",
586
623
  };
587
624
  }
588
- /**
589
- * 建立 SSE 连接并监听服务器事件
590
- *
591
- * 安全要求:必须提供签名验证,防止未授权监听他人事件
592
- * @param onMessage 新消息回调
593
- * @param signatureParams 签名参数(可选,不提供时自动生成)
594
- */
595
- async connectEventSource(onMessage, signatureParams) {
596
- if (!this.userAddress) {
597
- throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, "User address not set");
598
- }
599
- // 关闭已有连接
600
- this.disconnectEventSource();
601
- if (onMessage) {
602
- this.onMessageCallback = onMessage;
603
- }
604
- // 如果没有提供签名参数,自动生成
605
- // 签名格式: event_stream:{address}:{timestamp}:{nonce}
606
- const account = await Account.Instance().get(this.userAddress, false);
607
- const publicKey = account?.pubkey || "";
608
- let params = signatureParams;
609
- if (!params) {
610
- const timestamp = Date.now(); //@ 使用ms时间戳
611
- const nonce = this.generateNonce();
612
- const message = `event_stream:${this.userAddress}:${timestamp}:${nonce}`;
613
- const signResult = await Account.Instance().signData(this.userAddress, message);
614
- const signatureBuffer = Buffer.from(signResult.signature.slice(2), "hex");
615
- const signatureBase64 = bytesToBase64(new Uint8Array(signatureBuffer));
616
- params = {
617
- signatureScheme: "ED25519",
618
- signature: signatureBase64,
619
- timestamp,
620
- nonce,
621
- };
622
- }
623
- // 构建带签名的 URL
624
- const queryParams = new URLSearchParams({
625
- publicKey: publicKey,
626
- signatureScheme: params.signatureScheme,
627
- signature: params.signature,
628
- timestamp: params.timestamp.toString(),
629
- nonce: params.nonce,
630
- });
631
- const url = `${this.config.serverUrl}/v1/events/${this.userAddress}?${queryParams}`;
632
- //console.log(`Connecting to SSE: ${url}`);
633
- // 检查是否有 EventSource 可用
634
- if (typeof EventSource === "undefined") {
635
- console.warn("EventSource is not available in this environment. SSE functionality disabled, falling back to polling.");
636
- return;
637
- }
638
- try {
639
- this.eventSource = new EventSource(url);
640
- }
641
- catch (error) {
642
- console.warn("Failed to create EventSource connection, falling back to polling.", error);
643
- return;
644
- }
645
- // 监听消息事件
646
- this.eventSource.onmessage = async (event) => {
647
- try {
648
- const sseEvent = JSON.parse(event.data);
649
- //console.log("SSE event received:", sseEvent.type);
650
- switch (sseEvent.type) {
651
- case "NewMessage":
652
- // 收到新消息通知,拉取并解密消息
653
- if (this.onMessageCallback) {
654
- const messages = await this.pullMessages();
655
- if (messages.length > 0) {
656
- this.onMessageCallback(messages);
657
- }
658
- }
659
- break;
660
- case "ark_confirmed": {
661
- // 发送方收到 ARK 确认,验证接收方签名后更新本地状态
662
- const { message_ids, recipient, recipient_public_key, signature, timestamp, } = sseEvent.data;
663
- /*console.log(
664
- `SSE ark_confirmed: messages ${message_ids} confirmed by ${recipient}`,
665
- );*/
666
- // 验证接收方签名(防止服务器作恶)
667
- // 签名消息格式: ack_messages:{recipient}:{message_ids}:{public_key}:{timestamp}:{nonce}
668
- // 注意: SSE事件中不包含nonce,因为nonce是在ARK请求时由接收方生成的,服务器只是转发
669
- const verifyMessage = `ack_messages:${recipient}:${message_ids.join(",")}:${recipient_public_key}:${timestamp}`;
670
- try {
671
- // 使用事件中携带的接收方公钥验证签名
672
- const { Ed25519PublicKey } = await import("../../keypairs/ed25519/publickey.js");
673
- const publicKey = new Ed25519PublicKey(recipient_public_key);
674
- const signatureBytes = Uint8Array.from(Buffer.from(signature, "base64"));
675
- const isValid = await publicKey.verify(new TextEncoder().encode(verifyMessage), signatureBytes);
676
- if (isValid) {
677
- // 签名验证成功,保存 ARK 确认(不可更改字段)
678
- for (const msgId of message_ids) {
679
- // 获取现有消息并更新 ARK 确认
680
- const existingMsg = this.messageStorage.getMessage(msgId);
681
- if (existingMsg) {
682
- existingMsg.arkConfirmed = {
683
- recipient,
684
- recipientPublicKey: recipient_public_key,
685
- signature,
686
- timestamp,
687
- };
688
- this.messageStorage.saveMessage(existingMsg);
689
- }
690
- }
691
- /*console.log(
692
- `ARK verified, stored ${message_ids.length} ARK confirmations`,
693
- );*/
694
- }
695
- else {
696
- console.error("ARK signature verification failed - possible server tampering");
697
- }
698
- }
699
- catch (error) {
700
- console.error("Failed to verify ARK signature:", error);
701
- }
702
- break;
703
- }
704
- case "PreKeyLow":
705
- // 收到预密钥低库存通知,立即补充
706
- /*console.log(
707
- `SSE PreKeyLow event: ${sseEvent.data.current}/${sseEvent.data.max_allowed}, auto-refilling...`,
708
- );*/
709
- await this.checkAndRefillPrekeys();
710
- break;
711
- case "Custom":
712
- // 自定义事件(如 Guard 确认/拒绝),暂不处理
713
- //console.log("SSE Custom event received");
714
- break;
715
- case "guard_confirmed": {
716
- // Guard 消息验证通过,更新消息的 merkleData
717
- const { message_id, merkle_data, timestamp: _timestamp, } = sseEvent.data;
718
- /*console.log(
719
- `SSE guard_confirmed: message ${message_id} confirmed`,
720
- );*/
721
- // 更新本地消息状态
722
- // 获取原始消息数据用于验证
723
- const existingMsg = this.messageStorage.getMessage(message_id);
724
- if (!existingMsg) {
725
- console.warn(`Guard confirmed event received but message ${message_id} not found in local storage`);
726
- break;
727
- }
728
- // 验证 Merkle 数据完整性
729
- if (!merkle_data.prevRoot) {
730
- console.error(`Guard message ${message_id} missing prevRoot in merkle_data`);
731
- break;
732
- }
733
- if (!merkle_data.newRoot) {
734
- console.error(`Guard message ${message_id} missing newRoot in merkle_data`);
735
- break;
736
- }
737
- if (!merkle_data.serverTimestamp) {
738
- console.error(`Guard message ${message_id} missing serverTimestamp in merkle_data`);
739
- break;
740
- }
741
- if (!merkle_data.serverSignature) {
742
- console.error(`Guard message ${message_id} missing serverSignature in merkle_data`);
743
- break;
744
- }
745
- if (!merkle_data.serverPublicKey) {
746
- console.error(`Guard message ${message_id} missing serverPublicKey in merkle_data`);
747
- break;
748
- }
749
- // 验证消息的 Merkle Root 计算
750
- const { verifySingleMerkleRoot } = await import("./crypto.js");
751
- const rootValid = verifySingleMerkleRoot(merkle_data.prevRoot, merkle_data.newRoot, existingMsg.plaintextHash, merkle_data.serverTimestamp, merkle_data.leafIndex);
752
- if (!rootValid.valid) {
753
- console.error(`Guard message ${message_id} Merkle root verification failed: ${rootValid.error}`);
754
- break;
755
- }
756
- // 验证服务器签名
757
- const { verifyEd25519Signature } = await import("./crypto.js");
758
- const signData = `${merkle_data.prevRoot}:${merkle_data.newRoot}:${merkle_data.serverTimestamp}:${merkle_data.serverPublicKey}`;
759
- const signatureValid = verifyEd25519Signature(merkle_data.serverPublicKey, signData, merkle_data.serverSignature);
760
- if (!signatureValid) {
761
- console.error(`Guard message ${message_id} server signature verification failed`);
762
- break;
763
- }
764
- /*console.log(
765
- `Guard message ${message_id} verification passed, updating...`,
766
- );*/
767
- // 直接使用 updateMessageStatus 更新消息的 Merkle 数据
768
- // 因为 message_id 已经包含 nonce,不需要再更新消息 ID
769
- this.messageStorage.updateMessageStatus(message_id, MessageStatus.CONFIRMED, {
770
- leafIndex: merkle_data.leafIndex,
771
- newRoot: merkle_data.newRoot,
772
- serverSignature: merkle_data.serverSignature,
773
- serverTimestamp: merkle_data.serverTimestamp,
774
- serverPublicKey: merkle_data.serverPublicKey,
775
- });
776
- const updated = true;
777
- if (updated) {
778
- /*console.log(
779
- `Guard message ${message_id} updated with merkle data`,
780
- );*/
781
- // 更新会话状态
782
- if (existingMsg.toAddress === null) {
783
- throw new Error(`Guard message ${message_id} has null toAddress`);
784
- }
785
- const toAddr = existingMsg.toAddress;
786
- if (toAddr === null) {
787
- throw new Error(`Guard message ${message_id} has null toAddress`);
788
- }
789
- this.sessionStateStorage.updateSessionState(this.userAddress, toAddr, {
790
- currentRoot: merkle_data.newRoot,
791
- prevRoot: merkle_data.prevRoot,
792
- lastLeafIndex: merkle_data.leafIndex,
793
- lastSyncAt: Date.now(),
794
- });
795
- }
796
- else {
797
- console.warn(`Failed to update Guard message ${message_id}`);
798
- }
799
- break;
800
- }
801
- case "guard_rejected": {
802
- // Guard 消息验证被拒绝
803
- const { message_id, reason: _reason, timestamp: _timestamp, } = sseEvent.data;
804
- /*console.log(
805
- `SSE guard_rejected: message ${message_id} rejected: ${reason}`,
806
- );*/
807
- // 更新本地消息状态
808
- // 首先尝试通过 message_id 查找消息
809
- const existingMsg = this.messageStorage.getMessage(message_id);
810
- if (existingMsg) {
811
- existingMsg.status = MessageStatus.REJECTED;
812
- this.messageStorage.saveMessage(existingMsg);
813
- /*console.log(
814
- `Guard message ${message_id} marked as rejected`,
815
- );*/
816
- }
817
- else {
818
- /*console.warn(
819
- `Guard rejected event received but message ${message_id} not found in local storage`,
820
- );*/
821
- }
822
- break;
823
- }
824
- }
825
- }
826
- catch (error) {
827
- console.error("Failed to handle SSE event:", error);
828
- }
829
- };
830
- // 连接打开
831
- this.eventSource.onopen = () => {
832
- //console.log("SSE connection opened");
833
- };
834
- // 连接错误
835
- this.eventSource.onerror = (error) => {
836
- console.error("SSE connection error:", error);
837
- this.disconnectEventSource();
838
- };
839
- }
840
- /**
841
- * 检查 SSE 是否已连接
842
- */
843
- isEventSourceConnected() {
844
- return this.eventSource !== null;
845
- }
846
- /**
847
- * 断开 SSE 连接
848
- */
849
- disconnectEventSource() {
850
- if (this.eventSource) {
851
- this.eventSource.close();
852
- this.eventSource = null;
853
- //console.log("SSE connection closed");
854
- }
855
- }
856
625
  /**
857
626
  * 销毁 Messenger 实例
858
- * 清理所有资源(定时器、SSE 连接等)
627
+ * 清理所有资源(定时器等)
859
628
  */
860
629
  destroy() {
861
- this.stopPrekeyCheckTimer();
862
- this.disconnectEventSource();
630
+ this.stopPollingTimer();
863
631
  //console.log("Messenger instance destroyed");
864
632
  }
865
633
  /**
@@ -869,6 +637,13 @@ export class Messenger {
869
637
  disconnect() {
870
638
  this.destroy();
871
639
  }
640
+ /**
641
+ * 设置新消息回调
642
+ * @param onMessage 新消息回调函数
643
+ */
644
+ setOnMessageCallback(onMessage) {
645
+ this.onMessageCallback = onMessage;
646
+ }
872
647
  /**
873
648
  * 发送 ZIP 压缩文件
874
649
  *
@@ -922,7 +697,7 @@ export class Messenger {
922
697
  // 8. 发送到服务器(带 ZIP 元数据)
923
698
  const timestamp = Date.now();
924
699
  const nonce = this.generateNonce();
925
- const account = await Account.Instance().get(this.userAddress, false);
700
+ const account = await (await getAccount()).get(this.userAddress, false);
926
701
  if (!account) {
927
702
  throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, "User account not found");
928
703
  }
@@ -932,7 +707,7 @@ export class Messenger {
932
707
  const lastReceivedStr = lastReceivedLeafIndex >= 0 ? lastReceivedLeafIndex.toString() : "";
933
708
  const forceStr = options?.force ? "true" : "false";
934
709
  const signMessage = `send_message:${this.userAddress}:${recipientAddress}:${guardAddr}:${passportAddr}:${plaintextHash}:${lastReceivedStr}:${publicKey}:${timestamp}:${nonce}:${forceStr}`;
935
- const signResult = await Account.Instance().signData(this.userAddress, signMessage);
710
+ const signResult = await (await getAccount()).signData(this.userAddress, signMessage);
936
711
  const signatureBuffer = Buffer.from(signResult.signature.slice(2), "hex");
937
712
  const signatureBase64 = bytesToBase64(new Uint8Array(signatureBuffer));
938
713
  // 使用统一的 sendMessage API
@@ -1013,6 +788,7 @@ export class Messenger {
1013
788
  }
1014
789
  }
1015
790
  }
791
+ this.triggerFastPoll();
1016
792
  return {
1017
793
  messageId: response.messageId,
1018
794
  status: message.status,
@@ -1067,11 +843,11 @@ export class Messenger {
1067
843
  const nonce = this.generateNonce();
1068
844
  const dataJson = canonicalizeJson(data);
1069
845
  const signMessage = `${timestamp}:${nonce}:${dataJson}`;
1070
- const signResult = await Account.Instance().signData(this.userAddress, signMessage);
846
+ const signResult = await (await getAccount()).signData(this.userAddress, signMessage);
1071
847
  const signatureBuffer = Buffer.from(signResult.signature.slice(2), "hex");
1072
848
  const signatureBase64 = bytesToBase64(new Uint8Array(signatureBuffer));
1073
849
  // 获取公钥(带标志位)用于服务器验证
1074
- const account = await Account.Instance().get(this.userAddress, false);
850
+ const account = await (await getAccount()).get(this.userAddress, false);
1075
851
  if (!account || !account.pubkey) {
1076
852
  throw new MessengerError(MessengerErrorCode.IDENTITY_NOT_FOUND, "Account public key not found");
1077
853
  }
@@ -1325,5 +1101,303 @@ export class Messenger {
1325
1101
  const signedRequest = await this._createSignedRequest({});
1326
1102
  return this.serverClient.getGuardList(this.userAddress, signedRequest);
1327
1103
  }
1104
+ // ========== 【新增】Skip Keys 和消息池相关方法 ==========
1105
+ /**
1106
+ * 尝试解密单条消息
1107
+ * @param serverMsg 服务器消息
1108
+ * @returns 解密结果
1109
+ */
1110
+ async tryDecryptMessage(serverMsg) {
1111
+ try {
1112
+ // 1. 使用新的解密引擎解密消息
1113
+ const ciphertext = Uint8Array.from(Buffer.from(serverMsg.bodyB64, "base64"));
1114
+ const decryptResult = await this.decryptionEngine.decryptMessage(this.userAddress, serverMsg.from, ciphertext.buffer, serverMsg.msgType);
1115
+ if (!decryptResult.success) {
1116
+ // 解密失败,判断是否应该重试
1117
+ const shouldRetry = this.isRetryableError(decryptResult.error || "");
1118
+ return {
1119
+ success: false,
1120
+ shouldRetry,
1121
+ error: decryptResult.error,
1122
+ sessionUpdated: decryptResult.sessionUpdated,
1123
+ };
1124
+ }
1125
+ const plaintext = decryptResult.plaintext;
1126
+ // 2. 验证消息
1127
+ if (!serverMsg.clientTimestamp) {
1128
+ throw new Error(`Missing clientTimestamp for message ${serverMsg.id}`);
1129
+ }
1130
+ if (!serverMsg.plaintextHash) {
1131
+ throw new Error(`Missing plaintextHash for message ${serverMsg.id}`);
1132
+ }
1133
+ const verificationResult = verifyMessage({
1134
+ messageId: serverMsg.id,
1135
+ plaintext,
1136
+ plaintextHash: serverMsg.plaintextHash,
1137
+ createdAt: serverMsg.clientTimestamp,
1138
+ guardAddress: serverMsg.guardAddress,
1139
+ passportAddress: serverMsg.passportAddress,
1140
+ lastReceivedLeafIndex: serverMsg.lastReceivedLeafIndex,
1141
+ serverSignature: serverMsg.merkleMetadata?.serverSignature,
1142
+ serverPublicKey: serverMsg.merkleMetadata?.serverPublicKey,
1143
+ merkleMetadata: serverMsg.merkleMetadata
1144
+ ? {
1145
+ prevRoot: serverMsg.merkleMetadata.prevRoot,
1146
+ newRoot: serverMsg.merkleMetadata.newRoot,
1147
+ serverTimestamp: serverMsg.merkleMetadata.serverTimestamp,
1148
+ leafIndex: serverMsg.merkleMetadata.leafIndex,
1149
+ proofSiblings: serverMsg.merkleMetadata.proofSiblings,
1150
+ proofIndices: serverMsg.merkleMetadata.proofIndices,
1151
+ }
1152
+ : undefined,
1153
+ });
1154
+ if (!verificationResult.valid) {
1155
+ throw new Error(verificationResult.error);
1156
+ }
1157
+ // 3. 构造消息对象
1158
+ const message = {
1159
+ messageId: serverMsg.id,
1160
+ fromAddress: serverMsg.from,
1161
+ toAddress: this.userAddress,
1162
+ plaintextHash: serverMsg.plaintextHash,
1163
+ plaintext,
1164
+ guardAddress: serverMsg.guardAddress,
1165
+ passportAddress: serverMsg.passportAddress,
1166
+ lastReceivedLeafIndex: serverMsg.lastReceivedLeafIndex,
1167
+ direction: MessageDirection.RECEIVED,
1168
+ status: MessageStatus.DECRYPTED,
1169
+ msgType: serverMsg.msgType,
1170
+ leafIndex: serverMsg.merkleMetadata?.leafIndex,
1171
+ prevRoot: serverMsg.merkleMetadata?.prevRoot,
1172
+ newRoot: serverMsg.merkleMetadata?.newRoot,
1173
+ serverSignature: serverMsg.merkleMetadata?.serverSignature,
1174
+ serverTimestamp: serverMsg.merkleMetadata?.serverTimestamp,
1175
+ serverPublicKey: serverMsg.merkleMetadata?.serverPublicKey,
1176
+ createdAt: serverMsg.clientTimestamp,
1177
+ receivedAt: Date.now(),
1178
+ zipMetadata: serverMsg.zipMetadata,
1179
+ };
1180
+ // 4. 更新会话状态
1181
+ if (serverMsg.merkleMetadata) {
1182
+ this.sessionStateStorage.updateSessionState(this.userAddress, serverMsg.from, {
1183
+ currentRoot: serverMsg.merkleMetadata.newRoot,
1184
+ prevRoot: serverMsg.merkleMetadata.prevRoot,
1185
+ lastLeafIndex: serverMsg.merkleMetadata.leafIndex,
1186
+ lastSyncAt: Date.now(),
1187
+ });
1188
+ }
1189
+ const timestamp = serverMsg.merkleMetadata?.serverTimestamp ||
1190
+ serverMsg.clientTimestamp ||
1191
+ Date.now();
1192
+ // 【新增】根据收到的 lastReceivedLeafIndex,更新我发送的消息状态
1193
+ if (serverMsg.lastReceivedLeafIndex !== undefined &&
1194
+ serverMsg.lastReceivedLeafIndex >= 0) {
1195
+ const mySentMessages = this.messageStorage
1196
+ .getMessagesBySession(this.userAddress, serverMsg.from)
1197
+ .filter((m) => m.direction === MessageDirection.SENT &&
1198
+ m.status === MessageStatus.CONFIRMED &&
1199
+ m.leafIndex !== undefined &&
1200
+ m.leafIndex <= serverMsg.lastReceivedLeafIndex);
1201
+ for (const sentMsg of mySentMessages) {
1202
+ this.messageStorage.updateMessageStatus(sentMsg.messageId, MessageStatus.READ);
1203
+ }
1204
+ }
1205
+ return {
1206
+ success: true,
1207
+ shouldRetry: false,
1208
+ message,
1209
+ decryptedData: {
1210
+ id: serverMsg.id,
1211
+ from: serverMsg.from,
1212
+ plaintext,
1213
+ timestamp,
1214
+ merkleVerified: !!serverMsg.merkleMetadata,
1215
+ merkleData: serverMsg.merkleMetadata
1216
+ ? {
1217
+ leafIndex: serverMsg.merkleMetadata.leafIndex,
1218
+ rootHash: serverMsg.merkleMetadata.newRoot,
1219
+ }
1220
+ : undefined,
1221
+ },
1222
+ sessionUpdated: decryptResult.sessionUpdated,
1223
+ };
1224
+ }
1225
+ catch (error) {
1226
+ const errorMessage = error instanceof Error ? error.message : String(error);
1227
+ // 判断是否应该重试(Skip Keys 机制)
1228
+ const shouldRetry = this.isRetryableError(errorMessage);
1229
+ return {
1230
+ success: false,
1231
+ shouldRetry,
1232
+ error: errorMessage,
1233
+ };
1234
+ }
1235
+ }
1236
+ /**
1237
+ * 判断错误是否可重试(Skip Keys 机制)
1238
+ * @param errorMessage 错误信息
1239
+ * @returns 是否可重试
1240
+ */
1241
+ isRetryableError(errorMessage) {
1242
+ // Signal Protocol 内部已经处理了 Skip Keys
1243
+ // 这里的错误通常是更严重的错误
1244
+ const retryablePatterns = [
1245
+ /message number/i,
1246
+ /chain key/i,
1247
+ /session not found/i,
1248
+ /prekey not found/i,
1249
+ /PREKEY 竞争:我的地址较小,保留我的会话/i, // 【用户要求】处理 PREKEY 竞争情况
1250
+ /The operation failed for an operation-specific reason/i, // 【新增】处理 DOMException 类型错误
1251
+ /DOMException/i, // 【新增】处理 DOMException 类型错误
1252
+ /收到 WHISPER_MESSAGE 但无现有会话,需要等待 PREKEY_MESSAGE/i, // 【新增】处理无会话但收到 WHISPER_MESSAGE 的情况
1253
+ ];
1254
+ return retryablePatterns.some((pattern) => pattern.test(errorMessage));
1255
+ }
1256
+ /**
1257
+ * 处理 waitingMessages 池中的消息
1258
+ * @param decryptedMessages 解密成功的消息列表
1259
+ * @param acknowledgedIds 已确认的消息ID列表
1260
+ */
1261
+ async processWaitingMessages(decryptedMessages, acknowledgedIds) {
1262
+ if (this.waitingMessages.size === 0)
1263
+ return;
1264
+ console.log(`[Messenger] 尝试处理 ${this.waitingMessages.size} 条等待消息`);
1265
+ const processedIds = [];
1266
+ // 对等待消息按 clientTimestamp 排序(发送方本地时间)
1267
+ const sortedWaitingMsgs = Array.from(this.waitingMessages.values()).sort(function (a, b) {
1268
+ return (a.clientTimestamp || 0) - (b.clientTimestamp || 0);
1269
+ });
1270
+ for (const serverMsg of sortedWaitingMsgs) {
1271
+ const id = serverMsg.id;
1272
+ const decryptResult = await this.tryDecryptMessage(serverMsg);
1273
+ if (decryptResult.success &&
1274
+ decryptResult.message &&
1275
+ decryptResult.decryptedData) {
1276
+ // 解密成功
1277
+ this.messageStorage.saveMessage(decryptResult.message);
1278
+ decryptedMessages.push(decryptResult.decryptedData);
1279
+ acknowledgedIds.push(id);
1280
+ processedIds.push(id);
1281
+ // 清除重试计数
1282
+ this.waitingMessageRetries.delete(id);
1283
+ }
1284
+ else if (!decryptResult.shouldRetry) {
1285
+ // 永久失败
1286
+ console.error(`[Messenger] 等待消息 ${id} 解密永久失败: ${decryptResult.error}`);
1287
+ this.failedMessages.set(id, {
1288
+ message: serverMsg,
1289
+ error: decryptResult.error || "Unknown error",
1290
+ });
1291
+ await this.saveFailedMessage(serverMsg, decryptResult.error || "Unknown error");
1292
+ acknowledgedIds.push(id);
1293
+ processedIds.push(id);
1294
+ // 清除重试计数
1295
+ this.waitingMessageRetries.delete(id);
1296
+ }
1297
+ else {
1298
+ // 需要重试,增加重试计数
1299
+ const currentRetries = this.waitingMessageRetries.get(id) || 0;
1300
+ const newRetries = currentRetries + 1;
1301
+ if (newRetries >= 3) {
1302
+ // 超过3次重试,标记为永久失败
1303
+ console.error(`[Messenger] 等待消息 ${id} 重试3次后仍失败,标记为永久失败`);
1304
+ this.failedMessages.set(id, {
1305
+ message: serverMsg,
1306
+ error: decryptResult.error || "Retry limit exceeded",
1307
+ });
1308
+ await this.saveFailedMessage(serverMsg, decryptResult.error || "Retry limit exceeded");
1309
+ acknowledgedIds.push(id);
1310
+ processedIds.push(id);
1311
+ this.waitingMessageRetries.delete(id);
1312
+ }
1313
+ else {
1314
+ // 保留在 waitingMessages 中,等待下次重试
1315
+ this.waitingMessageRetries.set(id, newRetries);
1316
+ console.log(`[Messenger] 消息 ${id} 第 ${newRetries}/3 次重试失败,继续等待`);
1317
+ }
1318
+ }
1319
+ }
1320
+ // 从 waitingMessages 中移除已处理的消息
1321
+ for (const id of processedIds) {
1322
+ this.waitingMessages.delete(id);
1323
+ }
1324
+ if (processedIds.length > 0) {
1325
+ console.log(`[Messenger] 成功处理 ${processedIds.length} 条等待消息`);
1326
+ }
1327
+ }
1328
+ /**
1329
+ * 保存解密失败的消息
1330
+ * @param serverMsg 服务器消息
1331
+ * @param error 错误信息
1332
+ */
1333
+ async saveFailedMessage(serverMsg, error) {
1334
+ const failedMessage = {
1335
+ messageId: serverMsg.id,
1336
+ fromAddress: serverMsg.from,
1337
+ toAddress: this.userAddress,
1338
+ plaintextHash: serverMsg.plaintextHash || "",
1339
+ guardAddress: serverMsg.guardAddress,
1340
+ passportAddress: serverMsg.passportAddress,
1341
+ lastReceivedLeafIndex: serverMsg.lastReceivedLeafIndex,
1342
+ direction: MessageDirection.RECEIVED,
1343
+ status: MessageStatus.DECRYPT_FAILED,
1344
+ msgType: serverMsg.msgType,
1345
+ leafIndex: serverMsg.merkleMetadata?.leafIndex,
1346
+ prevRoot: serverMsg.merkleMetadata?.prevRoot,
1347
+ newRoot: serverMsg.merkleMetadata?.newRoot,
1348
+ serverSignature: serverMsg.merkleMetadata?.serverSignature,
1349
+ serverTimestamp: serverMsg.merkleMetadata?.serverTimestamp,
1350
+ serverPublicKey: serverMsg.merkleMetadata?.serverPublicKey,
1351
+ createdAt: serverMsg.clientTimestamp || Date.now(),
1352
+ receivedAt: Date.now(),
1353
+ zipMetadata: serverMsg.zipMetadata,
1354
+ decryptError: error,
1355
+ decryptAttempts: 1,
1356
+ lastDecryptAttemptAt: Date.now(),
1357
+ };
1358
+ this.messageStorage.saveMessage(failedMessage);
1359
+ }
1360
+ /**
1361
+ * 重新调度轮询(用于切换到快速模式)
1362
+ */
1363
+ reschedulePolling() {
1364
+ if (!this.isPollingRunning || !this.pollingTimer)
1365
+ return;
1366
+ console.log(`[Messenger] 重新调度轮询,切换到快速模式(等待消息: ${this.waitingMessages.size})`);
1367
+ clearTimeout(this.pollingTimer);
1368
+ this.pollingTimer = null;
1369
+ this.scheduleNextPoll();
1370
+ }
1371
+ /**
1372
+ * 获取解密失败的消息(供用户决策重发)
1373
+ * @returns 失败消息列表
1374
+ */
1375
+ getFailedMessages() {
1376
+ return Array.from(this.failedMessages.entries()).map(([id, data]) => ({
1377
+ messageId: id,
1378
+ from: data.message.from,
1379
+ error: data.error,
1380
+ leafIndex: data.message.merkleMetadata?.leafIndex,
1381
+ }));
1382
+ }
1383
+ /**
1384
+ * 清除解密失败的消息记录
1385
+ * @param messageId 消息ID(可选,不提供则清除所有)
1386
+ */
1387
+ clearFailedMessages(messageId) {
1388
+ if (messageId) {
1389
+ this.failedMessages.delete(messageId);
1390
+ }
1391
+ else {
1392
+ this.failedMessages.clear();
1393
+ }
1394
+ }
1395
+ /**
1396
+ * 获取等待解密的消息数量
1397
+ * @returns 等待消息数量
1398
+ */
1399
+ getWaitingMessageCount() {
1400
+ return this.waitingMessages.size;
1401
+ }
1328
1402
  }
1329
1403
  //# sourceMappingURL=messenger.js.map