wowok 2.1.20 → 2.1.22

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 (57) hide show
  1. package/dist/cjs/w/local/account.d.ts +1 -1
  2. package/dist/cjs/w/local/account.js +15 -47
  3. package/dist/cjs/w/local/account.js.map +1 -1
  4. package/dist/cjs/w/messenger/crypto.js +31 -0
  5. package/dist/cjs/w/messenger/crypto.js.map +1 -1
  6. package/dist/cjs/w/messenger/messenger-api.d.ts +27 -4
  7. package/dist/cjs/w/messenger/messenger-api.js +191 -256
  8. package/dist/cjs/w/messenger/messenger-api.js.map +1 -1
  9. package/dist/cjs/w/messenger/messenger-manager.d.ts +39 -3
  10. package/dist/cjs/w/messenger/messenger-manager.js +194 -107
  11. package/dist/cjs/w/messenger/messenger-manager.js.map +1 -1
  12. package/dist/cjs/w/messenger/messenger.d.ts +9 -1
  13. package/dist/cjs/w/messenger/messenger.js +33 -0
  14. package/dist/cjs/w/messenger/messenger.js.map +1 -1
  15. package/dist/cjs/w/messenger/server.d.ts +2 -2
  16. package/dist/cjs/w/messenger/server.js.map +1 -1
  17. package/dist/cjs/w/messenger/session.d.ts +15 -0
  18. package/dist/cjs/w/messenger/session.js +83 -35
  19. package/dist/cjs/w/messenger/session.js.map +1 -1
  20. package/dist/cjs/w/messenger/storage.d.ts +12 -0
  21. package/dist/cjs/w/messenger/storage.js +51 -2
  22. package/dist/cjs/w/messenger/storage.js.map +1 -1
  23. package/dist/cjs/w/messenger/templates/wts-html-template.d.ts +61 -0
  24. package/dist/cjs/w/messenger/templates/wts-html-template.js +414 -0
  25. package/dist/cjs/w/messenger/templates/wts-html-template.js.map +1 -0
  26. package/dist/cjs/w/messenger/types.d.ts +9 -5
  27. package/dist/cjs/w/messenger/types.js +3 -2
  28. package/dist/cjs/w/messenger/types.js.map +1 -1
  29. package/dist/esm/w/local/account.d.ts +1 -1
  30. package/dist/esm/w/local/account.js +15 -47
  31. package/dist/esm/w/local/account.js.map +1 -1
  32. package/dist/esm/w/messenger/crypto.js +31 -0
  33. package/dist/esm/w/messenger/crypto.js.map +1 -1
  34. package/dist/esm/w/messenger/messenger-api.d.ts +27 -4
  35. package/dist/esm/w/messenger/messenger-api.js +191 -256
  36. package/dist/esm/w/messenger/messenger-api.js.map +1 -1
  37. package/dist/esm/w/messenger/messenger-manager.d.ts +39 -3
  38. package/dist/esm/w/messenger/messenger-manager.js +194 -107
  39. package/dist/esm/w/messenger/messenger-manager.js.map +1 -1
  40. package/dist/esm/w/messenger/messenger.d.ts +9 -1
  41. package/dist/esm/w/messenger/messenger.js +33 -0
  42. package/dist/esm/w/messenger/messenger.js.map +1 -1
  43. package/dist/esm/w/messenger/server.d.ts +2 -2
  44. package/dist/esm/w/messenger/server.js.map +1 -1
  45. package/dist/esm/w/messenger/session.d.ts +15 -0
  46. package/dist/esm/w/messenger/session.js +83 -35
  47. package/dist/esm/w/messenger/session.js.map +1 -1
  48. package/dist/esm/w/messenger/storage.d.ts +12 -0
  49. package/dist/esm/w/messenger/storage.js +51 -2
  50. package/dist/esm/w/messenger/storage.js.map +1 -1
  51. package/dist/esm/w/messenger/templates/wts-html-template.d.ts +61 -0
  52. package/dist/esm/w/messenger/templates/wts-html-template.js +414 -0
  53. package/dist/esm/w/messenger/templates/wts-html-template.js.map +1 -0
  54. package/dist/esm/w/messenger/types.d.ts +9 -5
  55. package/dist/esm/w/messenger/types.js +3 -2
  56. package/dist/esm/w/messenger/types.js.map +1 -1
  57. package/package.json +1 -1
@@ -12,6 +12,7 @@ import * as path from "path";
12
12
  import { isValidU64 } from "../common.js";
13
13
  import { verifySingleMerkleRoot, hashPlaintext, verifyEd25519Signature, } from "./crypto.js";
14
14
  import { canonicalizeJson } from "./utils.js";
15
+ import { generateHtmlPage, getThemeColors, } from "./templates/wts-html-template.js";
15
16
  import { GetAccountOrMark_Address, GetManyAccountOrMark_Address, } from "../local/index.js";
16
17
  import { query_objects } from "../query/object.js";
17
18
  import { Messenger } from "./messenger.js";
@@ -89,10 +90,15 @@ export async function watch_conversations(account) {
89
90
  W_ERROR(WErrors.AccountNotFound, `watch_conversations.account ${account}`);
90
91
  }
91
92
  const myAddress = address.toLowerCase();
92
- // First, pull messages from server to ensure local storage is up to date
93
- const messenger = new Messenger(address);
94
- await messenger.initialize();
95
- await messenger.pullMessages();
93
+ // 【修改】使用 MessengerManager 确保账号已就绪并拉取消息
94
+ const manager = getMessengerManager();
95
+ if (!isInitialized) {
96
+ await manager.start();
97
+ }
98
+ // 确保账号已就绪(自动初始化)
99
+ const accountInfo = await manager.ensureAccountReady(address);
100
+ // 拉取消息
101
+ await accountInfo.messenger.pullMessages();
96
102
  const messageStorage = new MessageStorage(myAddress);
97
103
  const allMessages = messageStorage.getAllMessages(myAddress);
98
104
  const conversations = new Map();
@@ -150,9 +156,12 @@ export async function send_message(from, to, content, options) {
150
156
  W_ERROR(WErrors.AccountNotFound, `send_message.guardAddress or passportAddress not found`);
151
157
  }
152
158
  }
153
- const messenger = new Messenger(fromAddress);
154
- await messenger.initialize();
155
- return messenger.sendMessage(t, content, options);
159
+ // 【修改】使用 MessengerManager 确保账号已就绪并发送消息
160
+ const manager = getMessengerManager();
161
+ if (!isInitialized) {
162
+ await manager.start();
163
+ }
164
+ return manager.send(fromAddress, t, content, options);
156
165
  }
157
166
  /**
158
167
  * 发送文件(ZIP 格式)
@@ -185,7 +194,11 @@ export async function send_file(from, to, filePath, options) {
185
194
  W_ERROR(WErrors.AccountNotFound, `send_file.guardAddress or passportAddress not found`);
186
195
  }
187
196
  }
197
+ // 【修改】使用 MessengerManager 确保账号已就绪并发送文件
188
198
  const manager = getMessengerManager();
199
+ if (!isInitialized) {
200
+ await manager.start();
201
+ }
189
202
  return manager.send_file(fromAddress, t, filePath, options);
190
203
  }
191
204
  /**
@@ -207,7 +220,11 @@ export async function watch_messages(filter) {
207
220
  if (filter?.customListFilter?.excludeAddresses != null) {
208
221
  filter.customListFilter.excludeAddresses = (await Account.Instance().get_many_address(filter.customListFilter.excludeAddresses)).filter((v) => v != null);
209
222
  }
223
+ // 【修改】使用 MessengerManager 确保账号已就绪并查询消息
210
224
  const manager = getMessengerManager();
225
+ if (!isInitialized) {
226
+ await manager.start();
227
+ }
211
228
  return manager.watch(filter);
212
229
  }
213
230
  export async function pull_messages(account, limit) {
@@ -215,9 +232,13 @@ export async function pull_messages(account, limit) {
215
232
  if (!address) {
216
233
  W_ERROR(WErrors.AccountNotFound, `pull_messages.account ${account}`);
217
234
  }
218
- const messenger = new Messenger(address);
219
- await messenger.initialize();
220
- const result = await messenger.pullMessages(limit);
235
+ // 【修改】使用 MessengerManager 确保账号已就绪并拉取消息
236
+ const manager = getMessengerManager();
237
+ if (!isInitialized) {
238
+ await manager.start();
239
+ }
240
+ const accountInfo = await manager.ensureAccountReady(address);
241
+ const result = await accountInfo.messenger.pullMessages(limit);
221
242
  return result.messages.map((dm) => dm);
222
243
  }
223
244
  /**
@@ -297,12 +318,11 @@ export async function extract_zip_messages(account, messages, outputDir) {
297
318
  if (!userAddress) {
298
319
  throw new MessengerError(MessengerErrorCode.INVALID_INPUT, "account is required when extracting by message IDs");
299
320
  }
300
- // 判断是 Message 数组还是 messageId 数组
301
- const isMessageIds = messages.length > 0 && typeof messages[0] === "string";
302
321
  for (const item of messages) {
303
322
  try {
304
323
  let message;
305
- if (isMessageIds) {
324
+ // 逐个判断是 Message 对象还是 messageId 字符串
325
+ if (typeof item === "string") {
306
326
  const messageId = item;
307
327
  const messageStorage = new MessageStorage(userAddress);
308
328
  const storedMessage = messageStorage.getMessageById(messageId);
@@ -324,9 +344,7 @@ export async function extract_zip_messages(account, messages, outputDir) {
324
344
  results.push(filePath);
325
345
  }
326
346
  catch (e) {
327
- const id = isMessageIds
328
- ? item
329
- : item.messageId;
347
+ const id = typeof item === "string" ? item : item.messageId;
330
348
  console.error(`Failed to extract message ${id}:`, e);
331
349
  }
332
350
  }
@@ -384,7 +402,7 @@ export async function verify_wts(wtsFilePath) {
384
402
  // 1. 加载 WTS 文件
385
403
  const wtsFile = load_wts(wtsFilePath);
386
404
  // 2. 验证基本结构
387
- if (!wtsFile.wts || !wtsFile.payload || !wtsFile.meta) {
405
+ if (!wtsFile.payload || !wtsFile.meta) {
388
406
  return { valid: false, error: "Invalid WTS file structure" };
389
407
  }
390
408
  if (wtsFile.meta.type !== "wts") {
@@ -394,20 +412,91 @@ export async function verify_wts(wtsFilePath) {
394
412
  };
395
413
  }
396
414
  const { payload, meta } = wtsFile;
397
- // 2. 验证每个消息的 Merkle Root 计算(不验证跨消息链连续性)
398
- // 因为消息可能来自不同的 Merkle Tree(不同会话方向)
399
- for (const msg of payload.messages) {
415
+ // 2. 验证每个消息的 Merkle Root 计算和链连续性
416
+ // 首先按leafIndex排序消息
417
+ const sortedMessages = [...payload.messages].sort((a, b) => {
418
+ if (a.leafIndex === undefined || b.leafIndex === undefined)
419
+ return 0;
420
+ return a.leafIndex - b.leafIndex;
421
+ });
422
+ for (let i = 0; i < sortedMessages.length; i++) {
423
+ const msg = sortedMessages[i];
424
+ // 检查消息对象是否为空
425
+ if (!msg) {
426
+ return {
427
+ valid: false,
428
+ error: `Message ${i}: Message is null or undefined`,
429
+ };
430
+ }
431
+ // 检查关键字段是否为空
432
+ if (!msg.prevRoot) {
433
+ return {
434
+ valid: false,
435
+ error: `Message ${i}: Missing prevRoot`,
436
+ };
437
+ }
438
+ if (!msg.merkleRoot) {
439
+ return {
440
+ valid: false,
441
+ error: `Message ${i}: Missing merkleRoot`,
442
+ };
443
+ }
444
+ if (!msg.plaintextHash) {
445
+ return {
446
+ valid: false,
447
+ error: `Message ${i}: Missing plaintextHash`,
448
+ };
449
+ }
450
+ if (msg.timestamp === undefined || msg.timestamp === null) {
451
+ return {
452
+ valid: false,
453
+ error: `Message ${i}: Missing timestamp`,
454
+ };
455
+ }
456
+ if (msg.leafIndex === undefined || msg.leafIndex === null) {
457
+ return {
458
+ valid: false,
459
+ error: `Message ${i}: Missing leafIndex`,
460
+ };
461
+ }
462
+ // 验证单个消息的Merkle Root计算
400
463
  const result = verifySingleMerkleRoot(msg.prevRoot, msg.merkleRoot, msg.plaintextHash, msg.timestamp, msg.leafIndex);
401
464
  if (!result.valid) {
402
465
  return {
403
466
  valid: false,
404
- error: `${result.error} at leafIndex ${msg.leafIndex}`,
467
+ error: `${result.error} at message ${i}, leafIndex ${msg.leafIndex}`,
405
468
  };
406
469
  }
470
+ // 【新增】验证Merkle链连续性(除了第一条消息)
471
+ if (i > 0) {
472
+ const prevMsg = sortedMessages[i - 1];
473
+ // 检查leafIndex是否连续
474
+ if (msg.leafIndex !== prevMsg.leafIndex + 1) {
475
+ return {
476
+ valid: false,
477
+ error: `Merkle chain discontinuity: leafIndex ${prevMsg.leafIndex} -> ${msg.leafIndex} (expected ${prevMsg.leafIndex + 1})`,
478
+ };
479
+ }
480
+ // 检查merkleRoot是否匹配
481
+ if (msg.prevRoot.toLowerCase() !==
482
+ prevMsg.merkleRoot.toLowerCase()) {
483
+ return {
484
+ valid: false,
485
+ error: `Merkle root mismatch at leafIndex ${msg.leafIndex}: expected prevRoot=${prevMsg.merkleRoot}, got ${msg.prevRoot}`,
486
+ };
487
+ }
488
+ }
407
489
  }
408
490
  // 3. 验证每个消息的 plaintextHash 和服务器签名(如果提供了明文)
409
491
  for (let i = 0; i < payload.messages.length; i++) {
410
492
  const msg = payload.messages[i];
493
+ // 检查消息对象是否为空
494
+ if (!msg) {
495
+ return {
496
+ valid: false,
497
+ error: `Message ${i}: Message is null or undefined`,
498
+ };
499
+ }
411
500
  // 判断是否为非文本消息(ZIP/WTS/WIP)
412
501
  const isNonTextMsg = !!msg.zipMetadata;
413
502
  // 对于非文本消息,跳过 plaintextHash 格式验证(它们使用不同的哈希格式)
@@ -795,247 +884,38 @@ async function convertWtsToHtml(wtsFilePath, options = {}) {
795
884
  // 2. 加载 WTS 文件
796
885
  const wtsFile = load_wts(wtsFilePath);
797
886
  const { payload, meta } = wtsFile;
798
- const bgColor = theme === "dark" ? "#1a1a1a" : "#ffffff";
799
- const textColor = theme === "dark" ? "#e0e0e0" : "#333333";
800
- const borderColor = theme === "dark" ? "#444444" : "#e0e0e0";
801
- const escapeHtml = (text) => {
802
- return text
803
- .replace(/&/g, "&amp;")
804
- .replace(/</g, "&lt;")
805
- .replace(/>/g, "&gt;")
806
- .replace(/"/g, "&quot;")
807
- .replace(/'/g, "&#039;");
808
- };
809
- // 判断是否为非文本消息(ZIP/WTS/WIP)
810
- const isNonTextMessage = (msg) => {
811
- return !!msg.zipMetadata;
812
- };
813
- // 获取文件类型标签
814
- const getFileTypeLabel = (msg) => {
815
- // 首先检查 contentType
816
- if (msg.zipMetadata?.contentType) {
817
- return msg.zipMetadata.contentType.toUpperCase();
818
- }
819
- // 根据文件名推断类型
820
- const fileName = msg.zipMetadata?.fileName || "";
821
- if (fileName.endsWith(".wts"))
822
- return "WTS";
823
- if (fileName.endsWith(".wip"))
824
- return "WIP";
825
- if (fileName.endsWith(".zip"))
826
- return "ZIP";
827
- if (fileName.endsWith(".json"))
828
- return "JSON";
829
- if (fileName.endsWith(".txt"))
830
- return "TXT";
831
- // 根据 zipMetadata 推断
832
- if (msg.zipMetadata)
833
- return "ZIP";
834
- return "FILE";
835
- };
836
- // 生成保存按钮的 HTML
837
- const generateSaveButton = (msg, index) => {
838
- const fileType = getFileTypeLabel(msg);
839
- const fileName = msg.zipMetadata?.fileName ||
840
- `message_${index}.${fileType.toLowerCase()}`;
841
- // 对于非文本消息,plaintext 是 base64 编码的文件内容
842
- const fileData = msg.plaintext || "";
843
- return `
844
- <div style="margin: 12px 0; padding: 16px; background: ${theme === "dark" ? "#2a3f2a" : "#e8f5e9"}; border: 1px solid ${theme === "dark" ? "#4caf50" : "#81c784"}; border-radius: 8px; text-align: center;">
845
- <div style="font-size: 14px; color: ${theme === "dark" ? "#81c784" : "#2e7d32"}; margin-bottom: 8px;">
846
- 📎 ${fileType} File
847
- ${msg.zipMetadata ? `<span style="font-size: 12px; color: #666;">(${formatFileSize(msg.zipMetadata.fileSize)})</span>` : ""}
848
- </div>
849
- <button
850
- onclick="saveFile${index}()"
851
- style="padding: 10px 24px; background: #4caf50; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;"
852
- onmouseover="this.style.background='#45a049'"
853
- onmouseout="this.style.background='#4caf50'"
854
- >
855
- 💾 Save ${escapeHtml(fileName)}
856
- </button>
857
- </div>
858
- <script>
859
- function saveFile${index}() {
860
- try {
861
- // Base64 解码
862
- const base64Data = "${escapeHtml(fileData)}";
863
- const byteCharacters = atob(base64Data);
864
- const byteNumbers = new Array(byteCharacters.length);
865
- for (let i = 0; i < byteCharacters.length; i++) {
866
- byteNumbers[i] = byteCharacters.charCodeAt(i);
867
- }
868
- const byteArray = new Uint8Array(byteNumbers);
869
-
870
- // 根据文件类型设置 MIME 类型
871
- let mimeType = "application/octet-stream";
872
- const fileName = "${escapeHtml(fileName)}";
873
- if (fileName.endsWith('.json')) mimeType = "application/json";
874
- else if (fileName.endsWith('.zip')) mimeType = "application/zip";
875
- else if (fileName.endsWith('.txt')) mimeType = "text/plain";
876
-
877
- const blob = new Blob([byteArray], { type: mimeType });
878
- const url = URL.createObjectURL(blob);
879
- const a = document.createElement("a");
880
- a.href = url;
881
- a.download = fileName;
882
- document.body.appendChild(a);
883
- a.click();
884
- document.body.removeChild(a);
885
- URL.revokeObjectURL(url);
886
- } catch (e) {
887
- alert('保存文件失败: ' + e.message);
888
- }
889
- }
890
- </script>
891
- `;
892
- };
893
- // 格式化文件大小
894
- const formatFileSize = (bytes) => {
895
- if (bytes < 1024)
896
- return bytes + " B";
897
- if (bytes < 1024 * 1024)
898
- return (bytes / 1024).toFixed(1) + " KB";
899
- return (bytes / (1024 * 1024)).toFixed(1) + " MB";
900
- };
887
+ // 获取主题颜色
888
+ const { bgColor, textColor, borderColor } = getThemeColors(theme);
901
889
  // 【修正】分析消息确定"我"是谁,并收集最大 lastReceivedLeafIndex
902
- // WTS 文件是从一方视角生成的,该方的消息会有 lastReceivedLeafIndex 字段
903
- // 策略:统计每个发送方有 lastReceivedLeafIndex 的消息数量,数量多的一方是"我"
904
- const senderWithLastReceived = {};
890
+ // 算法:找出生成WTS的账户(myAccount)收到的消息中,lastReceivedLeafIndex的最大值
891
+ // 生成WTS的账户 = meta.creator
892
+ const myAddress = meta.creator;
905
893
  let maxLastReceivedLeafIndex = -1;
906
894
  for (const msg of payload.messages) {
907
- if (msg.lastReceivedLeafIndex !== undefined &&
908
- msg.lastReceivedLeafIndex >= 0) {
909
- // 统计每个发送方有 lastReceivedLeafIndex 的消息数量
910
- senderWithLastReceived[msg.from] =
911
- (senderWithLastReceived[msg.from] ?? 0) + 1;
912
- // 收集最大 lastReceivedLeafIndex
913
- if (msg.lastReceivedLeafIndex > maxLastReceivedLeafIndex) {
914
- maxLastReceivedLeafIndex = msg.lastReceivedLeafIndex;
895
+ // 只考虑"我"收到的消息(to === myAddress)
896
+ if (msg.to.toLowerCase() === myAddress.toLowerCase()) {
897
+ if (msg.lastReceivedLeafIndex !== undefined &&
898
+ msg.lastReceivedLeafIndex >= 0) {
899
+ // 收集最大 lastReceivedLeafIndex
900
+ if (msg.lastReceivedLeafIndex > maxLastReceivedLeafIndex) {
901
+ maxLastReceivedLeafIndex = msg.lastReceivedLeafIndex;
902
+ }
915
903
  }
916
904
  }
917
905
  }
918
- // 确定"我"是谁(有 lastReceivedLeafIndex 消息数量更多的一方)
919
- /*let myAddress: string | null = null;
920
- let maxCount = 0;
921
- for (const [sender, count] of Object.entries(senderWithLastReceived)) {
922
- if (count > maxCount) {
923
- maxCount = count;
924
- myAddress = sender;
925
- }
926
- }*/
927
- const messagesHtml = payload.messages
928
- .map((msg, index) => {
929
- const isNonText = isNonTextMessage(msg);
930
- // 【已注释】判断这条消息是否已被对方解密
931
- // 只标记"我发送的消息",且 leafIndex <= 对方最后收到的序号
932
- // const isMyMessage = myAddress !== null && msg.from === myAddress;
933
- // const isDecryptedByRecipient =
934
- // isMyMessage &&
935
- // maxLastReceivedLeafIndex >= 0 &&
936
- // msg.leafIndex <= maxLastReceivedLeafIndex;
937
- return `
938
- <div style="margin: 16px 0; padding: 16px; border: 1px solid ${borderColor}; border-radius: 8px; background: ${theme === "dark" ? "#2a2a2a" : "#f9f9f9"};">
939
- <div style="display: flex; justify-content: space-between; margin-bottom: 8px; font-size: 12px; color: #666;">
940
- <span>From: ${escapeHtml(msg.from.slice(0, 6))}...${escapeHtml(msg.from.slice(-3))} To: ${escapeHtml(msg.to.slice(0, 6))}...${escapeHtml(msg.to.slice(-3))}</span>
941
- <span>${new Date(msg.timestamp).toLocaleString()}</span>
942
- </div>
943
- ${isNonText
944
- ? generateSaveButton(msg, index)
945
- : msg.plaintext
946
- ? `<div style="margin: 12px 0; padding: 12px; background: ${theme === "dark" ? "#333333" : "#ffffff"}; border: 1px solid ${borderColor}; border-radius: 4px; font-size: 14px; line-height: 1.6; max-height: calc(1.6em * 6); overflow-y: auto; white-space: pre-wrap; word-break: break-word;">${escapeHtml(msg.plaintext)}</div>`
947
- : ""}
948
- <div style="margin: 8px 0; font-size: 11px; color: #666;">
949
- <div>Merkle Root: ${escapeHtml(msg.merkleRoot)}</div>
950
- ${msg.lastReceivedLeafIndex !== undefined && msg.lastReceivedLeafIndex >= 0 ? `<div>Last Received Leaf Index: ${msg.lastReceivedLeafIndex}</div>` : ""}
951
- ${msg.arkConfirmed ? `<div>ARK Confirmed: ${escapeHtml(msg.arkConfirmed.recipient)} at ${new Date(msg.arkConfirmed.timestamp).toLocaleString()}</div>` : ""}
952
- ${msg.guardAddress ? `<div>Guard: ${escapeHtml(msg.guardAddress)}</div>` : ""}
953
- ${msg.passportAddress ? `<div>Passport: ${escapeHtml(msg.passportAddress)}</div>` : ""}
954
- </div>
955
- <div style="font-size: 11px; color: #888; margin-top: 8px; padding-top: 8px; border-top: 1px solid ${borderColor};">
956
- <div>Leaf Index: ${msg.leafIndex}</div>
957
- </div>
958
- </div>
959
- `;
960
- })
961
- .join("");
962
- // 签名信息不再在 HTML 中显示(根据安全设计)
963
- const signatureHtml = "";
964
- const html = `<!DOCTYPE html>
965
- <html lang="en">
966
- <head>
967
- <meta charset="UTF-8">
968
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
969
- <title>${escapeHtml(title)}</title>
970
- <style>
971
- body {
972
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
973
- max-width: 800px;
974
- margin: 0 auto;
975
- padding: 20px;
976
- background: ${bgColor};
977
- color: ${textColor};
978
- }
979
- .header {
980
- border-bottom: 2px solid ${borderColor};
981
- padding-bottom: 16px;
982
- margin-bottom: 24px;
983
- }
984
- .meta {
985
- font-size: 12px;
986
- color: #666;
987
- margin-top: 8px;
988
- }
989
- .note {
990
- font-size: 11px;
991
- color: #999;
992
- margin-top: 12px;
993
- padding: 8px;
994
- background: ${theme === "dark" ? "#2a2a2a" : "#f5f5f5"};
995
- border-radius: 4px;
996
- font-style: italic;
997
- }
998
- </style>
999
- </head>
1000
- <body>
1001
- <div class="header">
1002
- <h1>Witness Timestamped Sequence</h1>
1003
- <div class="note">
1004
- Important Note: This page is for message browsing and verification reference only. Please verify whether the message sequence has been tampered with through the API using the WTS file.
1005
- </div>
1006
- <div style="font-size: 14px; color: #666; margin-top: 4px;">
1007
- ${new Date(meta.startTime).toLocaleDateString()} - ${new Date(meta.endTime).toLocaleDateString()}
1008
- ${verifyResult.valid
1009
- ? `<span style="color: #4caf50; margin-left: 8px;">✓ The accuracy, sequentiality, and integrity of the messages are verified without tampering</span>`
1010
- : `<span style="color: #ff9800; margin-left: 8px;">⚠ ${verifyResult.error || "Hash mismatch - content has been tampered"}</span>`}
1011
- </div>
1012
- <div class="meta">
1013
- <div>Session Participants: ${payload.session.participants.map((p) => escapeHtml(p.slice(0, 6)) + "..." + escapeHtml(p.slice(-3))).join(", ")}</div>
1014
- <div>Messages: ${meta.messageCount} | Time: ${new Date(meta.startTime).toLocaleString()} - ${new Date(meta.endTime).toLocaleString()}</div>
1015
- <div style="word-break: break-all;">Merkle Root: ${escapeHtml(meta.merkleRoot)}</div>
1016
- ${verifyResult.signatures && verifyResult.signatures.length > 0
1017
- ? `
1018
- <div style="margin-top: 8px; padding: 8px; background: ${theme === "dark" ? "#2a3f2a" : "#e8f5e9"}; border-radius: 4px;">
1019
- <div style="font-size: 11px; color: ${theme === "dark" ? "#81c784" : "#2e7d32"}; margin-bottom: 4px;">✓ Signature Verification (${verifyResult.signatures.length} signature${verifyResult.signatures.length > 1 ? "s" : ""})</div>
1020
- ${verifyResult.signatures
1021
- .map((s, idx) => `
1022
- <div style="font-size: 10px; color: ${textColor}; margin-left: 8px;">
1023
- ${idx + 1}. ${s.address ? escapeHtml(s.address.slice(0, 6)) + "..." + escapeHtml(s.address.slice(-3)) : "Unknown"}: ${s.valid ? '<span style="color: #4caf50;">✓ Valid</span>' : '<span style="color: #f44336;">✗ Invalid</span>'}
1024
- </div>
1025
- `)
1026
- .join("")}
1027
- </div>
1028
- `
1029
- : ""}
1030
- </div>
1031
- </div>
1032
- <div class="messages">
1033
- ${messagesHtml}
1034
- </div>
1035
- ${signatureHtml}
1036
- </body>
1037
- </html>`;
1038
- return html;
906
+ // 使用模板生成 HTML
907
+ return generateHtmlPage({
908
+ title,
909
+ theme,
910
+ bgColor,
911
+ textColor,
912
+ borderColor,
913
+ meta,
914
+ payload,
915
+ verifyResult,
916
+ maxLastReceivedLeafIndex,
917
+ myAddress,
918
+ });
1039
919
  }
1040
920
  /**
1041
921
  * 提交消息链上证明
@@ -1157,7 +1037,13 @@ export async function blacklist(request) {
1157
1037
  if (!acc) {
1158
1038
  W_ERROR(WErrors.AccountNotFound, `blacklist.account ${request.account}`);
1159
1039
  }
1040
+ // 【修改】使用 MessengerManager 确保账号已就绪
1160
1041
  const manager = getMessengerManager();
1042
+ if (!isInitialized) {
1043
+ await manager.start();
1044
+ }
1045
+ // 确保账号已就绪(自动初始化)
1046
+ await manager.ensureAccountReady(acc);
1161
1047
  switch (request.op) {
1162
1048
  case "add": {
1163
1049
  let addresses = await GetManyAccountOrMark_Address(request.users);
@@ -1220,7 +1106,13 @@ export async function friendslist(request) {
1220
1106
  if (!acc) {
1221
1107
  W_ERROR(WErrors.AccountNotFound, `friendslist.account ${request.account}`);
1222
1108
  }
1109
+ // 【修改】使用 MessengerManager 确保账号已就绪
1223
1110
  const manager = getMessengerManager();
1111
+ if (!isInitialized) {
1112
+ await manager.start();
1113
+ }
1114
+ // 确保账号已就绪(自动初始化)
1115
+ await manager.ensureAccountReady(acc);
1224
1116
  switch (request.op) {
1225
1117
  case "add": {
1226
1118
  let addresses = await GetManyAccountOrMark_Address(request.users);
@@ -1280,7 +1172,13 @@ export async function guardlist(request) {
1280
1172
  if (!acc) {
1281
1173
  W_ERROR(WErrors.AccountNotFound, `guardlist.account ${request.account}`);
1282
1174
  }
1175
+ // 【修改】使用 MessengerManager 确保账号已就绪
1283
1176
  const manager = getMessengerManager();
1177
+ if (!isInitialized) {
1178
+ await manager.start();
1179
+ }
1180
+ // 确保账号已就绪(自动初始化)
1181
+ await manager.ensureAccountReady(acc);
1284
1182
  switch (request.op) {
1285
1183
  case "add": {
1286
1184
  // 按 guard 字段去重,保留最后一个
@@ -1371,4 +1269,41 @@ export async function guardlist(request) {
1371
1269
  throw new MessengerError(MessengerErrorCode.INVALID_INPUT, `guardlist.unknown op: ${request}`);
1372
1270
  }
1373
1271
  }
1272
+ /**
1273
+ * 用户设置管理 - 统一入口
1274
+ * @param request 操作请求
1275
+ * @returns 操作结果
1276
+ */
1277
+ export async function settings(request) {
1278
+ const acc = await Account.Instance().get_address(request.account);
1279
+ if (!acc) {
1280
+ W_ERROR(WErrors.AccountNotFound, `settings.account ${request.account}`);
1281
+ }
1282
+ // 使用 MessengerManager 确保账号已就绪
1283
+ const manager = getMessengerManager();
1284
+ if (!isInitialized) {
1285
+ await manager.start();
1286
+ }
1287
+ // 确保账号已就绪(自动初始化)
1288
+ await manager.ensureAccountReady(acc);
1289
+ switch (request.op) {
1290
+ case "get": {
1291
+ const result = await manager.getSettings(acc);
1292
+ return { op: "get", result };
1293
+ }
1294
+ case "set": {
1295
+ const settings = {};
1296
+ if (request.allowStrangerMessages !== undefined) {
1297
+ settings.allowStrangerMessages = request.allowStrangerMessages;
1298
+ }
1299
+ if (request.maxInboxSize !== undefined) {
1300
+ settings.maxInboxSize = request.maxInboxSize;
1301
+ }
1302
+ const result = await manager.setSettings(acc, settings);
1303
+ return { op: "set", result };
1304
+ }
1305
+ default:
1306
+ throw new MessengerError(MessengerErrorCode.INVALID_INPUT, `settings.unknown op: ${request}`);
1307
+ }
1308
+ }
1374
1309
  //# sourceMappingURL=messenger-api.js.map