@mrlegendbot/baileys 1.2.3 → 1.2.4

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 (212) hide show
  1. package/README.upstream.md +1312 -0
  2. package/WAProto/WAProto.json +1 -0
  3. package/WAProto/WAProto.proto +6275 -0
  4. package/WAProto/compiler.js +550 -0
  5. package/WAProto/index.js +2 -97691
  6. package/lib/Defaults/index.js +89 -92
  7. package/lib/Signal/Group/ciphertext-message.js +9 -10
  8. package/lib/Signal/Group/group-session-builder.js +21 -22
  9. package/lib/Signal/Group/group_cipher.js +75 -69
  10. package/lib/Signal/Group/index.js +0 -1
  11. package/lib/Signal/Group/keyhelper.js +9 -10
  12. package/lib/Signal/Group/sender-chain-key.js +21 -22
  13. package/lib/Signal/Group/sender-key-distribution-message.js +51 -60
  14. package/lib/Signal/Group/sender-key-message.js +56 -62
  15. package/lib/Signal/Group/sender-key-name.js +38 -40
  16. package/lib/Signal/Group/sender-key-record.js +33 -34
  17. package/lib/Signal/Group/sender-key-state.js +72 -76
  18. package/lib/Signal/Group/sender-message-key.js +22 -23
  19. package/lib/Signal/libsignal.js +506 -405
  20. package/lib/Signal/lid-mapping.js +276 -258
  21. package/lib/Socket/Client/index.js +0 -1
  22. package/lib/Socket/Client/types.js +6 -7
  23. package/lib/Socket/Client/websocket.js +48 -49
  24. package/lib/Socket/business.js +349 -369
  25. package/lib/Socket/chats.js +1172 -1148
  26. package/lib/Socket/communities.js +473 -413
  27. package/lib/Socket/groups.js +387 -331
  28. package/lib/Socket/index.js +6 -8
  29. package/lib/Socket/messages-recv.js +1782 -1719
  30. package/lib/Socket/messages-send.js +1503 -2450
  31. package/lib/Socket/mex.js +40 -35
  32. package/lib/Socket/newsletter.js +239 -191
  33. package/lib/Socket/socket.js +992 -923
  34. package/lib/Store/index.js +8 -0
  35. package/lib/Store/keyed-db.js +108 -0
  36. package/lib/Store/make-cache-manager-store.js +70 -0
  37. package/lib/Store/make-in-memory-store.js +417 -0
  38. package/lib/Store/make-ordered-dictionary.js +69 -0
  39. package/lib/Store/object-repository.js +27 -0
  40. package/lib/Types/Auth.js +0 -1
  41. package/lib/Types/Bussines.js +0 -1
  42. package/lib/Types/Call.js +0 -1
  43. package/lib/Types/Chat.js +1 -8
  44. package/lib/Types/Contact.js +0 -1
  45. package/lib/Types/Events.js +1 -2
  46. package/lib/Types/GroupMetadata.js +0 -1
  47. package/lib/Types/Label.js +20 -22
  48. package/lib/Types/LabelAssociation.js +2 -4
  49. package/lib/Types/Message.js +3 -5
  50. package/lib/Types/Mex.js +26 -31
  51. package/lib/Types/Product.js +0 -1
  52. package/lib/Types/Signal.js +1 -2
  53. package/lib/Types/Socket.js +2 -3
  54. package/lib/Types/State.js +4 -52
  55. package/lib/Types/USync.js +0 -1
  56. package/lib/Types/index.js +10 -11
  57. package/lib/Utils/auth-utils.js +240 -277
  58. package/lib/Utils/browser-utils.js +20 -23
  59. package/lib/Utils/business.js +200 -204
  60. package/lib/Utils/chat-utils.js +836 -810
  61. package/lib/Utils/companion-reg-client-utils.js +23 -25
  62. package/lib/Utils/crypto.js +70 -86
  63. package/lib/Utils/decode-wa-message.js +277 -284
  64. package/lib/Utils/event-buffer.js +592 -595
  65. package/lib/Utils/generics.js +312 -335
  66. package/lib/Utils/history.js +123 -115
  67. package/lib/Utils/index.js +1 -2
  68. package/lib/Utils/link-preview.js +74 -73
  69. package/lib/Utils/logger.js +3 -2
  70. package/lib/Utils/lt-hash.js +0 -6
  71. package/lib/Utils/make-mutex.js +27 -27
  72. package/lib/Utils/message-retry-manager.js +213 -254
  73. package/lib/Utils/messages-media.js +741 -715
  74. package/lib/Utils/messages.js +791 -827
  75. package/lib/Utils/noise-handler.js +215 -187
  76. package/lib/Utils/pre-key-manager.js +69 -98
  77. package/lib/Utils/process-message.js +617 -586
  78. package/lib/Utils/reporting-utils.js +553 -234
  79. package/lib/Utils/signal.js +217 -170
  80. package/lib/Utils/stanza-ack.js +27 -35
  81. package/lib/Utils/sync-action-utils.js +37 -41
  82. package/lib/Utils/tc-token-utils.js +120 -141
  83. package/lib/Utils/use-multi-file-auth-state.js +87 -105
  84. package/lib/Utils/use-sqlite-auth-state.js +162 -0
  85. package/lib/Utils/validate-connection.js +190 -188
  86. package/lib/WABinary/constants.js +28 -1294
  87. package/lib/WABinary/decode.js +245 -249
  88. package/lib/WABinary/encode.js +201 -206
  89. package/lib/WABinary/generic-utils.js +86 -89
  90. package/lib/WABinary/index.js +0 -1
  91. package/lib/WABinary/jid-utils.js +68 -77
  92. package/lib/WABinary/types.js +0 -1
  93. package/lib/WAM/BinaryInfo.js +7 -8
  94. package/lib/WAM/constants.js +19892 -22853
  95. package/lib/WAM/encode.js +121 -132
  96. package/lib/WAM/index.js +0 -1
  97. package/lib/WAUSync/Protocols/USyncContactProtocol.js +46 -43
  98. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +47 -48
  99. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +22 -23
  100. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +30 -33
  101. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +19 -20
  102. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +53 -44
  103. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +24 -24
  104. package/lib/WAUSync/Protocols/index.js +0 -1
  105. package/lib/WAUSync/USyncQuery.js +79 -88
  106. package/lib/WAUSync/USyncUser.js +28 -29
  107. package/lib/WAUSync/index.js +0 -1
  108. package/lib/index.js +2 -2
  109. package/package.json +22 -86
  110. package/WAProto/GenerateStatics.sh +0 -3
  111. package/WAProto/fix-imports.js +0 -85
  112. package/WAProto/index.d.ts +0 -14017
  113. package/lib/Defaults/index.d.ts +0 -75
  114. package/lib/Signal/Group/ciphertext-message.d.ts +0 -10
  115. package/lib/Signal/Group/group-session-builder.d.ts +0 -15
  116. package/lib/Signal/Group/group_cipher.d.ts +0 -17
  117. package/lib/Signal/Group/index.d.ts +0 -12
  118. package/lib/Signal/Group/keyhelper.d.ts +0 -11
  119. package/lib/Signal/Group/sender-chain-key.d.ts +0 -14
  120. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -17
  121. package/lib/Signal/Group/sender-key-message.d.ts +0 -19
  122. package/lib/Signal/Group/sender-key-name.d.ts +0 -18
  123. package/lib/Signal/Group/sender-key-record.d.ts +0 -31
  124. package/lib/Signal/Group/sender-key-state.d.ts +0 -39
  125. package/lib/Signal/Group/sender-message-key.d.ts +0 -12
  126. package/lib/Signal/libsignal.d.ts +0 -5
  127. package/lib/Signal/lid-mapping.d.ts +0 -23
  128. package/lib/Socket/Client/index.d.ts +0 -3
  129. package/lib/Socket/Client/types.d.ts +0 -16
  130. package/lib/Socket/Client/websocket.d.ts +0 -13
  131. package/lib/Socket/business.d.ts +0 -217
  132. package/lib/Socket/chats.d.ts +0 -125
  133. package/lib/Socket/communities.d.ts +0 -273
  134. package/lib/Socket/groups.d.ts +0 -161
  135. package/lib/Socket/index.d.ts +0 -260
  136. package/lib/Socket/messages-recv.d.ts +0 -203
  137. package/lib/Socket/messages-send.d.ts +0 -199
  138. package/lib/Socket/mex.d.ts +0 -3
  139. package/lib/Socket/newsletter.d.ts +0 -170
  140. package/lib/Socket/socket.d.ts +0 -59
  141. package/lib/Types/Auth.d.ts +0 -117
  142. package/lib/Types/Bussines.d.ts +0 -25
  143. package/lib/Types/Call.d.ts +0 -15
  144. package/lib/Types/Chat.d.ts +0 -124
  145. package/lib/Types/Contact.d.ts +0 -26
  146. package/lib/Types/Events.d.ts +0 -256
  147. package/lib/Types/GroupMetadata.d.ts +0 -71
  148. package/lib/Types/Label.d.ts +0 -47
  149. package/lib/Types/LabelAssociation.d.ts +0 -30
  150. package/lib/Types/Message.d.ts +0 -320
  151. package/lib/Types/Mex.d.ts +0 -141
  152. package/lib/Types/Product.d.ts +0 -79
  153. package/lib/Types/Signal.d.ts +0 -87
  154. package/lib/Types/Socket.d.ts +0 -136
  155. package/lib/Types/State.d.ts +0 -97
  156. package/lib/Types/USync.d.ts +0 -26
  157. package/lib/Types/index.d.ts +0 -66
  158. package/lib/Utils/auth-utils.d.ts +0 -24
  159. package/lib/Utils/browser-utils.d.ts +0 -4
  160. package/lib/Utils/business.d.ts +0 -23
  161. package/lib/Utils/chat-utils.d.ts +0 -100
  162. package/lib/Utils/companion-reg-client-utils.d.ts +0 -17
  163. package/lib/Utils/crypto.d.ts +0 -37
  164. package/lib/Utils/decode-wa-message.d.ts +0 -66
  165. package/lib/Utils/event-buffer.d.ts +0 -36
  166. package/lib/Utils/generics.d.ts +0 -92
  167. package/lib/Utils/history.d.ts +0 -24
  168. package/lib/Utils/identity-change-handler.d.ts +0 -44
  169. package/lib/Utils/identity-change-handler.js +0 -50
  170. package/lib/Utils/index.d.ts +0 -22
  171. package/lib/Utils/link-preview.d.ts +0 -21
  172. package/lib/Utils/logger.d.ts +0 -12
  173. package/lib/Utils/lt-hash.d.ts +0 -8
  174. package/lib/Utils/make-mutex.d.ts +0 -9
  175. package/lib/Utils/message-retry-manager.d.ts +0 -115
  176. package/lib/Utils/messages-media.d.ts +0 -133
  177. package/lib/Utils/messages.d.ts +0 -91
  178. package/lib/Utils/noise-handler.d.ts +0 -20
  179. package/lib/Utils/offline-node-processor.d.ts +0 -17
  180. package/lib/Utils/offline-node-processor.js +0 -40
  181. package/lib/Utils/pre-key-manager.d.ts +0 -28
  182. package/lib/Utils/process-message.d.ts +0 -60
  183. package/lib/Utils/reporting-utils.d.ts +0 -11
  184. package/lib/Utils/signal.d.ts +0 -47
  185. package/lib/Utils/stanza-ack.d.ts +0 -11
  186. package/lib/Utils/sync-action-utils.d.ts +0 -19
  187. package/lib/Utils/tc-token-utils.d.ts +0 -37
  188. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  189. package/lib/Utils/validate-connection.d.ts +0 -11
  190. package/lib/WABinary/constants.d.ts +0 -28
  191. package/lib/WABinary/decode.d.ts +0 -7
  192. package/lib/WABinary/encode.d.ts +0 -3
  193. package/lib/WABinary/generic-utils.d.ts +0 -15
  194. package/lib/WABinary/index.d.ts +0 -6
  195. package/lib/WABinary/jid-utils.d.ts +0 -48
  196. package/lib/WABinary/types.d.ts +0 -19
  197. package/lib/WAM/BinaryInfo.d.ts +0 -9
  198. package/lib/WAM/constants.d.ts +0 -40
  199. package/lib/WAM/encode.d.ts +0 -3
  200. package/lib/WAM/index.d.ts +0 -4
  201. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
  202. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -23
  203. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -13
  204. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -13
  205. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +0 -10
  206. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -26
  207. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -10
  208. package/lib/WAUSync/Protocols/index.d.ts +0 -6
  209. package/lib/WAUSync/USyncQuery.d.ts +0 -30
  210. package/lib/WAUSync/USyncUser.d.ts +0 -17
  211. package/lib/WAUSync/index.d.ts +0 -4
  212. package/lib/index.d.ts +0 -12
@@ -1,164 +1,143 @@
1
1
  import { getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidMetaAI, isLidUser, isPnUser, jidNormalizedUser } from '../WABinary/index.js';
2
- // Same phone-number pattern as WABinary's isJidBot, applied against the user
3
- // part so the check is invariant to @c.us ↔ @s.whatsapp.net normalization.
4
2
  const BOT_PHONE_REGEX = /^1313555\d{4}$|^131655500\d{2}$/;
5
- /**
6
- * Mirrors WA Web's `Wid.isRegularUser()` (user ∧ ¬PSA ∧ ¬Bot). Used to gate tctoken
7
- * storage against malformed notifications — WA Web filters server-side but we
8
- * defend here for parity with `WAWebSetTcTokenChatAction.handleIncomingTcToken`.
9
- * Works for both pre- and post-normalized JIDs (`@c.us` vs `@s.whatsapp.net`).
10
- */
11
3
  function isRegularUser(jid) {
12
- if (!jid)
13
- return false;
14
- const user = jid.split('@')[0] ?? '';
15
- if (user === '0')
16
- return false; // PSA
17
- if (BOT_PHONE_REGEX.test(user))
18
- return false; // Bot by phone pattern
19
- if (isJidMetaAI(jid))
20
- return false; // MetaAI (@bot server)
21
- return !!(isPnUser(jid) || isLidUser(jid) || isHostedPnUser(jid) || isHostedLidUser(jid) || jid.endsWith('@c.us'));
4
+ if (!jid) return false;
5
+ const user = jid.split('@')[0] ?? '';
6
+ if (user === '0') return false;
7
+ if (BOT_PHONE_REGEX.test(user)) return false;
8
+ if (isJidMetaAI(jid)) return false;
9
+ return !!(isPnUser(jid) || isLidUser(jid) || isHostedPnUser(jid) || isHostedLidUser(jid) || jid.endsWith('@c.us'));
22
10
  }
23
- const TC_TOKEN_BUCKET_DURATION = 604800; // 7 days
24
- const TC_TOKEN_NUM_BUCKETS = 4; // ~28-day rolling window
25
- /** Sentinel key under `tctoken` store holding a JSON array of tracked storage JIDs for cross-session pruning. */
11
+ const TC_TOKEN_BUCKET_DURATION = 604800;
12
+ const TC_TOKEN_NUM_BUCKETS = 4;
26
13
  export const TC_TOKEN_INDEX_KEY = '__index';
27
- /** Read the persisted tctoken JID index and return its entries (never contains the sentinel key itself). */
28
14
  export async function readTcTokenIndex(keys) {
29
- const data = await keys.get('tctoken', [TC_TOKEN_INDEX_KEY]);
30
- const entry = data[TC_TOKEN_INDEX_KEY];
31
- if (!entry?.token?.length)
32
- return [];
33
- try {
34
- const parsed = JSON.parse(Buffer.from(entry.token).toString());
35
- if (!Array.isArray(parsed))
36
- return [];
37
- return parsed.filter((j) => typeof j === 'string' && j.length > 0 && j !== TC_TOKEN_INDEX_KEY);
38
- }
39
- catch {
40
- return [];
41
- }
15
+ const data = await keys.get('tctoken', [TC_TOKEN_INDEX_KEY]);
16
+ const entry = data[TC_TOKEN_INDEX_KEY];
17
+ if (!entry?.token?.length) return [];
18
+ try {
19
+ const parsed = JSON.parse(Buffer.from(entry.token).toString());
20
+ if (!Array.isArray(parsed)) return [];
21
+ return parsed.filter(j => typeof j === 'string' && j.length > 0 && j !== TC_TOKEN_INDEX_KEY);
22
+ } catch {
23
+ return [];
24
+ }
42
25
  }
43
- /** Build a SignalDataSet fragment that writes the merged index (persisted ∪ added) under the sentinel key. */
44
26
  export async function buildMergedTcTokenIndexWrite(keys, addedJids) {
45
- const persisted = await readTcTokenIndex(keys);
46
- const merged = new Set(persisted);
47
- for (const jid of addedJids) {
48
- if (jid && jid !== TC_TOKEN_INDEX_KEY)
49
- merged.add(jid);
27
+ const persisted = await readTcTokenIndex(keys);
28
+ const merged = new Set(persisted);
29
+ for (const jid of addedJids) {
30
+ if (jid && jid !== TC_TOKEN_INDEX_KEY) merged.add(jid);
31
+ }
32
+ return {
33
+ [TC_TOKEN_INDEX_KEY]: {
34
+ token: Buffer.from(JSON.stringify([...merged]))
50
35
  }
51
- return {
52
- [TC_TOKEN_INDEX_KEY]: { token: Buffer.from(JSON.stringify([...merged])) }
53
- };
36
+ };
54
37
  }
55
- // WA Web has separate sender/receiver AB props for these but they're identical today
56
38
  export function isTcTokenExpired(timestamp) {
57
- if (timestamp === null || timestamp === undefined)
58
- return true;
59
- const ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp;
60
- if (isNaN(ts))
61
- return true;
62
- const now = Math.floor(Date.now() / 1000);
63
- const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
64
- const cutoffBucket = currentBucket - (TC_TOKEN_NUM_BUCKETS - 1);
65
- const cutoffTimestamp = cutoffBucket * TC_TOKEN_BUCKET_DURATION;
66
- return ts < cutoffTimestamp;
39
+ if (timestamp === null || timestamp === undefined) return true;
40
+ const ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp;
41
+ if (isNaN(ts)) return true;
42
+ const now = Math.floor(Date.now() / 1000);
43
+ const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
44
+ const cutoffBucket = currentBucket - (TC_TOKEN_NUM_BUCKETS - 1);
45
+ const cutoffTimestamp = cutoffBucket * TC_TOKEN_BUCKET_DURATION;
46
+ return ts < cutoffTimestamp;
67
47
  }
68
48
  export function shouldSendNewTcToken(senderTimestamp) {
69
- if (senderTimestamp === undefined)
70
- return true;
71
- const now = Math.floor(Date.now() / 1000);
72
- const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
73
- const senderBucket = Math.floor(senderTimestamp / TC_TOKEN_BUCKET_DURATION);
74
- return currentBucket > senderBucket;
49
+ if (senderTimestamp === undefined) return true;
50
+ const now = Math.floor(Date.now() / 1000);
51
+ const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
52
+ const senderBucket = Math.floor(senderTimestamp / TC_TOKEN_BUCKET_DURATION);
53
+ return currentBucket > senderBucket;
75
54
  }
76
- /** Resolve JID to LID for tctoken storage (WA Web stores under LID) */
77
55
  export async function resolveTcTokenJid(jid, getLIDForPN) {
78
- if (isLidUser(jid))
79
- return jid;
80
- const lid = await getLIDForPN(jid);
81
- return lid ?? jid;
56
+ if (isLidUser(jid)) return jid;
57
+ const lid = await getLIDForPN(jid);
58
+ return lid ?? jid;
82
59
  }
83
- /** Resolve target JID for issuing privacy token based on AB prop 14303 */
84
60
  export async function resolveIssuanceJid(jid, issueToLid, getLIDForPN, getPNForLID) {
85
- if (issueToLid) {
86
- if (isLidUser(jid))
87
- return jid;
88
- const lid = await getLIDForPN(jid);
89
- return lid ?? jid;
90
- }
91
- if (!isLidUser(jid))
92
- return jid;
93
- if (getPNForLID) {
94
- const pn = await getPNForLID(jid);
95
- return pn ?? jid;
96
- }
97
- return jid;
61
+ if (issueToLid) {
62
+ if (isLidUser(jid)) return jid;
63
+ const lid = await getLIDForPN(jid);
64
+ return lid ?? jid;
65
+ }
66
+ if (!isLidUser(jid)) return jid;
67
+ if (getPNForLID) {
68
+ const pn = await getPNForLID(jid);
69
+ return pn ?? jid;
70
+ }
71
+ return jid;
98
72
  }
99
- export async function buildTcTokenFromJid({ authState, jid, baseContent = [], getLIDForPN }) {
100
- try {
101
- const storageJid = await resolveTcTokenJid(jid, getLIDForPN);
102
- const tcTokenData = await authState.keys.get('tctoken', [storageJid]);
103
- const entry = tcTokenData?.[storageJid];
104
- const tcTokenBuffer = entry?.token;
105
- const timestamp = entry?.timestamp;
106
- if (!tcTokenBuffer?.length || timestamp === undefined || isTcTokenExpired(timestamp)) {
107
- if (tcTokenBuffer) {
108
- // Preserve senderTimestamp so shouldSendNewTcToken() keeps its dedupe state
109
- // after we drop the unusable peer token. Only wipe the record entirely when
110
- // there's nothing worth keeping.
111
- const cleared = entry?.senderTimestamp !== undefined
112
- ? { token: Buffer.alloc(0), senderTimestamp: entry.senderTimestamp }
113
- : null;
114
- await authState.keys.set({ tctoken: { [storageJid]: cleared } });
115
- }
116
- return baseContent.length > 0 ? baseContent : undefined;
117
- }
118
- baseContent.push({
119
- tag: 'tctoken',
120
- attrs: { t: String(timestamp) },
121
- content: tcTokenBuffer
73
+ export async function buildTcTokenFromJid({
74
+ authState,
75
+ jid,
76
+ baseContent = [],
77
+ getLIDForPN
78
+ }) {
79
+ try {
80
+ const storageJid = await resolveTcTokenJid(jid, getLIDForPN);
81
+ const tcTokenData = await authState.keys.get('tctoken', [storageJid]);
82
+ const entry = tcTokenData?.[storageJid];
83
+ const tcTokenBuffer = entry?.token;
84
+ const timestamp = entry?.timestamp;
85
+ if (!tcTokenBuffer?.length || timestamp === undefined || isTcTokenExpired(timestamp)) {
86
+ if (tcTokenBuffer) {
87
+ const cleared = entry?.senderTimestamp !== undefined ? {
88
+ token: Buffer.alloc(0),
89
+ senderTimestamp: entry.senderTimestamp
90
+ } : null;
91
+ await authState.keys.set({
92
+ tctoken: {
93
+ [storageJid]: cleared
94
+ }
122
95
  });
123
- return baseContent;
124
- }
125
- catch (error) {
126
- return baseContent.length > 0 ? baseContent : undefined;
96
+ }
97
+ return baseContent.length > 0 ? baseContent : undefined;
127
98
  }
99
+ baseContent.push({
100
+ tag: 'tctoken',
101
+ attrs: { t: String(timestamp) },
102
+ content: tcTokenBuffer
103
+ });
104
+ return baseContent;
105
+ } catch (error) {
106
+ return baseContent.length > 0 ? baseContent : undefined;
107
+ }
128
108
  }
129
- export async function storeTcTokensFromIqResult({ result, fallbackJid, keys, getLIDForPN, onNewJidStored }) {
130
- const tokensNode = getBinaryNodeChild(result, 'tokens');
131
- if (!tokensNode)
132
- return;
133
- const tokenNodes = getBinaryNodeChildren(tokensNode, 'token');
134
- for (const tokenNode of tokenNodes) {
135
- if (tokenNode.attrs.type !== 'trusted_contact' || !(tokenNode.content instanceof Uint8Array)) {
136
- continue;
137
- }
138
- // In notifications tokenNode.attrs.jid is your own device JID, not the sender's
139
- const rawJid = jidNormalizedUser(fallbackJid || tokenNode.attrs.jid);
140
- if (!isRegularUser(rawJid))
141
- continue;
142
- const storageJid = await resolveTcTokenJid(rawJid, getLIDForPN);
143
- const existingTcData = await keys.get('tctoken', [storageJid]);
144
- const existingEntry = existingTcData[storageJid];
145
- const existingTs = existingEntry?.timestamp ? Number(existingEntry.timestamp) : 0;
146
- const incomingTs = tokenNode.attrs.t ? Number(tokenNode.attrs.t) : 0;
147
- // timestamp-less tokens would be immediately expired
148
- if (!incomingTs)
149
- continue;
150
- if (existingTs > 0 && existingTs > incomingTs)
151
- continue;
152
- await keys.set({
153
- tctoken: {
154
- [storageJid]: {
155
- ...existingEntry,
156
- token: Buffer.from(tokenNode.content),
157
- timestamp: tokenNode.attrs.t
158
- }
159
- }
160
- });
161
- onNewJidStored?.(storageJid);
109
+ export async function storeTcTokensFromIqResult({
110
+ result,
111
+ fallbackJid,
112
+ keys,
113
+ getLIDForPN,
114
+ onNewJidStored
115
+ }) {
116
+ const tokensNode = getBinaryNodeChild(result, 'tokens');
117
+ if (!tokensNode) return;
118
+ const tokenNodes = getBinaryNodeChildren(tokensNode, 'token');
119
+ for (const tokenNode of tokenNodes) {
120
+ if (tokenNode.attrs.type !== 'trusted_contact' || !(tokenNode.content instanceof Uint8Array)) {
121
+ continue;
162
122
  }
123
+ const rawJid = jidNormalizedUser(fallbackJid || tokenNode.attrs.jid);
124
+ if (!isRegularUser(rawJid)) continue;
125
+ const storageJid = await resolveTcTokenJid(rawJid, getLIDForPN);
126
+ const existingTcData = await keys.get('tctoken', [storageJid]);
127
+ const existingEntry = existingTcData[storageJid];
128
+ const existingTs = existingEntry?.timestamp ? Number(existingEntry.timestamp) : 0;
129
+ const incomingTs = tokenNode.attrs.t ? Number(tokenNode.attrs.t) : 0;
130
+ if (!incomingTs) continue;
131
+ if (existingTs > 0 && existingTs > incomingTs) continue;
132
+ await keys.set({
133
+ tctoken: {
134
+ [storageJid]: {
135
+ ...existingEntry,
136
+ token: Buffer.from(tokenNode.content),
137
+ timestamp: tokenNode.attrs.t
138
+ }
139
+ }
140
+ });
141
+ onNewJidStored?.(storageJid);
142
+ }
163
143
  }
164
- //# sourceMappingURL=tc-token-utils.js.map
@@ -1,121 +1,103 @@
1
1
  import { Mutex } from 'async-mutex';
2
2
  import { mkdir, readFile, stat, unlink, writeFile } from 'fs/promises';
3
3
  import { join } from 'path';
4
- import { proto } from '../../WAProto/index.js';
4
+ import { proto } from '../../WAProto/compiler.js';
5
5
  import { initAuthCreds } from './auth-utils.js';
6
6
  import { BufferJSON } from './generics.js';
7
- // We need to lock files due to the fact that we are using async functions to read and write files
8
- // https://github.com/WhiskeySockets/Baileys/issues/794
9
- // https://github.com/nodejs/node/issues/26338
10
- // Use a Map to store mutexes for each file path
11
7
  const fileLocks = new Map();
12
- // Get or create a mutex for a specific file path
13
- const getFileLock = (path) => {
14
- let mutex = fileLocks.get(path);
15
- if (!mutex) {
16
- mutex = new Mutex();
17
- fileLocks.set(path, mutex);
18
- }
19
- return mutex;
8
+ const getFileLock = path => {
9
+ let mutex = fileLocks.get(path);
10
+ if (!mutex) {
11
+ mutex = new Mutex();
12
+ fileLocks.set(path, mutex);
13
+ }
14
+ return mutex;
20
15
  };
21
- /**
22
- * stores the full authentication state in a single folder.
23
- * Far more efficient than singlefileauthstate
24
- *
25
- * Again, I wouldn't endorse this for any production level use other than perhaps a bot.
26
- * Would recommend writing an auth state for use with a proper SQL or No-SQL DB
27
- * */
28
- export const useMultiFileAuthState = async (folder) => {
29
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
- const writeData = async (data, file) => {
31
- const filePath = join(folder, fixFileName(file));
32
- const mutex = getFileLock(filePath);
33
- return mutex.acquire().then(async (release) => {
34
- try {
35
- await writeFile(filePath, JSON.stringify(data, BufferJSON.replacer));
36
- }
37
- finally {
38
- release();
39
- }
40
- });
41
- };
42
- const readData = async (file) => {
16
+ export const useMultiFileAuthState = async folder => {
17
+ const writeData = async (data, file) => {
18
+ const filePath = join(folder, fixFileName(file));
19
+ const mutex = getFileLock(filePath);
20
+ return mutex.acquire().then(async release => {
21
+ try {
22
+ await writeFile(filePath, JSON.stringify(data, BufferJSON.replacer));
23
+ } finally {
24
+ release();
25
+ }
26
+ });
27
+ };
28
+ const readData = async file => {
29
+ try {
30
+ const filePath = join(folder, fixFileName(file));
31
+ const mutex = getFileLock(filePath);
32
+ return await mutex.acquire().then(async release => {
43
33
  try {
44
- const filePath = join(folder, fixFileName(file));
45
- const mutex = getFileLock(filePath);
46
- return await mutex.acquire().then(async (release) => {
47
- try {
48
- const data = await readFile(filePath, { encoding: 'utf-8' });
49
- return JSON.parse(data, BufferJSON.reviver);
50
- }
51
- finally {
52
- release();
53
- }
54
- });
34
+ const data = await readFile(filePath, {
35
+ encoding: 'utf-8'
36
+ });
37
+ return JSON.parse(data, BufferJSON.reviver);
38
+ } finally {
39
+ release();
55
40
  }
56
- catch (error) {
57
- return null;
58
- }
59
- };
60
- const removeData = async (file) => {
41
+ });
42
+ } catch (error) {
43
+ return null;
44
+ }
45
+ };
46
+ const removeData = async file => {
47
+ try {
48
+ const filePath = join(folder, fixFileName(file));
49
+ const mutex = getFileLock(filePath);
50
+ return mutex.acquire().then(async release => {
61
51
  try {
62
- const filePath = join(folder, fixFileName(file));
63
- const mutex = getFileLock(filePath);
64
- return mutex.acquire().then(async (release) => {
65
- try {
66
- await unlink(filePath);
67
- }
68
- catch {
69
- }
70
- finally {
71
- release();
72
- }
73
- });
52
+ await unlink(filePath);
53
+ } catch {} finally {
54
+ release();
74
55
  }
75
- catch { }
76
- };
77
- const folderInfo = await stat(folder).catch(() => { });
78
- if (folderInfo) {
79
- if (!folderInfo.isDirectory()) {
80
- throw new Error(`found something that is not a directory at ${folder}, either delete it or specify a different location`);
81
- }
82
- }
83
- else {
84
- await mkdir(folder, { recursive: true });
56
+ });
57
+ } catch {}
58
+ };
59
+ const folderInfo = await stat(folder).catch(() => {});
60
+ if (folderInfo) {
61
+ if (!folderInfo.isDirectory()) {
62
+ throw new Error(`found something that is not a directory at ${folder}, either delete it or specify a different location`);
85
63
  }
86
- const fixFileName = (file) => file?.replace(/\//g, '__')?.replace(/:/g, '-');
87
- const creds = (await readData('creds.json')) || initAuthCreds();
88
- return {
89
- state: {
90
- creds,
91
- keys: {
92
- get: async (type, ids) => {
93
- const data = {};
94
- await Promise.all(ids.map(async (id) => {
95
- let value = await readData(`${type}-${id}.json`);
96
- if (type === 'app-state-sync-key' && value) {
97
- value = proto.Message.AppStateSyncKeyData.fromObject(value);
98
- }
99
- data[id] = value;
100
- }));
101
- return data;
102
- },
103
- set: async (data) => {
104
- const tasks = [];
105
- for (const category in data) {
106
- for (const id in data[category]) {
107
- const value = data[category][id];
108
- const file = `${category}-${id}.json`;
109
- tasks.push(value ? writeData(value, file) : removeData(file));
110
- }
111
- }
112
- await Promise.all(tasks);
113
- }
64
+ } else {
65
+ await mkdir(folder, {
66
+ recursive: true
67
+ });
68
+ }
69
+ const fixFileName = file => file?.replace(/\//g, '__')?.replace(/:/g, '-');
70
+ const creds = (await readData('creds.json')) || initAuthCreds();
71
+ return {
72
+ state: {
73
+ creds,
74
+ keys: {
75
+ get: async (type, ids) => {
76
+ const data = {};
77
+ await Promise.all(ids.map(async id => {
78
+ let value = await readData(`${type}-${id}.json`);
79
+ if (type === 'app-state-sync-key' && value) {
80
+ value = proto.Message.AppStateSyncKeyData.fromObject(value);
114
81
  }
82
+ data[id] = value;
83
+ }));
84
+ return data;
115
85
  },
116
- saveCreds: async () => {
117
- return writeData(creds, 'creds.json');
86
+ set: async data => {
87
+ const tasks = [];
88
+ for (const category in data) {
89
+ for (const id in data[category]) {
90
+ const value = data[category][id];
91
+ const file = `${category}-${id}.json`;
92
+ tasks.push(value ? writeData(value, file) : removeData(file));
93
+ }
94
+ }
95
+ await Promise.all(tasks);
118
96
  }
119
- };
97
+ }
98
+ },
99
+ saveCreds: async () => {
100
+ return writeData(creds, 'creds.json');
101
+ }
102
+ };
120
103
  };
121
- //# sourceMappingURL=use-multi-file-auth-state.js.map
@@ -0,0 +1,162 @@
1
+ import { mkdir, readdir, readFile } from 'fs/promises';
2
+ import { dirname, join } from 'path';
3
+ import { proto } from '../../WAProto/compiler.js';
4
+ import { initAuthCreds } from './auth-utils.js';
5
+ export const useSqliteAuthState = async (pathOrFolder, options = {}) => {
6
+ const {
7
+ fileName = 'auth.db',
8
+ migrateFromFolder,
9
+ logger
10
+ } = options;
11
+ const dbPath = /\.(db|sqlite|sqlite3)$/i.test(pathOrFolder) ? pathOrFolder : join(pathOrFolder, fileName);
12
+ const bufReplacer = (_, value) => {
13
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array || value?.type === 'Buffer') {
14
+ return {
15
+ type: 'Buffer',
16
+ data: Buffer.from(value?.data || value).toString('base64')
17
+ };
18
+ }
19
+ return value;
20
+ };
21
+ const bufReviver = (_, value) => {
22
+ if (value && typeof value === 'object' && value.type === 'Buffer' && typeof value.data === 'string') {
23
+ return Buffer.from(value.data, 'base64');
24
+ }
25
+ return value;
26
+ };
27
+ const encode = value => {
28
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
29
+ return Buffer.concat([Buffer.from([1]), Buffer.from(value)]);
30
+ }
31
+ return Buffer.concat([Buffer.from([0]), Buffer.from(JSON.stringify(value, bufReplacer), 'utf8')]);
32
+ };
33
+ const decode = blob => {
34
+ if (!blob || blob.length === 0) return null;
35
+ if (blob[0] === 1) return Buffer.from(blob.subarray(1));
36
+ return JSON.parse(Buffer.from(blob.subarray(1)).toString('utf8'), bufReviver);
37
+ };
38
+ const fixName = s => s?.replace(/\//g, '__')?.replace(/:/g, '-');
39
+ const keyOf = (category, id) => fixName(`${category}-${id}`);
40
+ let DatabaseSync;
41
+ try {
42
+ ({
43
+ DatabaseSync
44
+ } = await import('node:sqlite'));
45
+ } catch (err) {
46
+ throw new Error("useSqliteAuthState needs the built-in 'node:sqlite' module (Node 22.5+). Upgrade Node, or use useMultiFileAuthState instead.");
47
+ }
48
+ await mkdir(dirname(dbPath), {
49
+ recursive: true
50
+ }).catch(() => {});
51
+ const db = new DatabaseSync(dbPath);
52
+ db.exec('PRAGMA journal_mode = TRUNCATE');
53
+ db.exec('PRAGMA synchronous = NORMAL');
54
+ db.exec('PRAGMA busy_timeout = 5000');
55
+ db.exec('CREATE TABLE IF NOT EXISTS auth_state (k TEXT PRIMARY KEY, v BLOB NOT NULL) WITHOUT ROWID');
56
+ const qGet = db.prepare('SELECT v FROM auth_state WHERE k = ?');
57
+ const qUpsert = db.prepare('INSERT INTO auth_state(k,v) VALUES(?,?) ON CONFLICT(k) DO UPDATE SET v=excluded.v');
58
+ const qDelete = db.prepare('DELETE FROM auth_state WHERE k = ?');
59
+ const runTx = fn => {
60
+ db.exec('BEGIN');
61
+ try {
62
+ const r = fn();
63
+ db.exec('COMMIT');
64
+ return r;
65
+ } catch (err) {
66
+ db.exec('ROLLBACK');
67
+ throw err;
68
+ }
69
+ };
70
+ const readRaw = k => {
71
+ const row = qGet.get(k);
72
+ if (!row) return null;
73
+ try {
74
+ return decode(row.v);
75
+ } catch (err) {
76
+ logger?.warn?.({
77
+ k,
78
+ err: err?.message
79
+ }, 'sqlite-auth: failed to decode row, treating as missing');
80
+ return null;
81
+ }
82
+ };
83
+ const runMigration = async folder => {
84
+ let files;
85
+ try {
86
+ files = await readdir(folder);
87
+ } catch {
88
+ return 0;
89
+ }
90
+ const rows = [];
91
+ for (const file of files) {
92
+ if (!file.endsWith('.json')) continue;
93
+ let value;
94
+ try {
95
+ value = JSON.parse(await readFile(join(folder, file), 'utf8'), bufReviver);
96
+ } catch {
97
+ continue;
98
+ }
99
+ if (value === null || value === undefined) continue;
100
+ rows.push([file.slice(0, -'.json'.length), encode(value)]);
101
+ }
102
+ runTx(() => {
103
+ for (const [k, v] of rows) qUpsert.run(k, v);
104
+ });
105
+ return rows.length;
106
+ };
107
+ const hasCreds = () => !!qGet.get('creds');
108
+ if (migrateFromFolder && !hasCreds()) {
109
+ const n = await runMigration(migrateFromFolder);
110
+ if (n > 0) logger?.info?.({
111
+ count: n,
112
+ from: migrateFromFolder
113
+ }, 'sqlite-auth: migrated legacy auth state');
114
+ }
115
+ let creds = readRaw('creds');
116
+ if (!creds) {
117
+ creds = initAuthCreds();
118
+ qUpsert.run('creds', encode(creds));
119
+ }
120
+ const keys = {
121
+ get: async (type, ids) => {
122
+ const data = {};
123
+ for (const id of ids) {
124
+ let value = readRaw(keyOf(type, id));
125
+ if (type === 'app-state-sync-key' && value) {
126
+ value = proto.Message.AppStateSyncKeyData.fromObject(value);
127
+ }
128
+ if (value !== null && value !== undefined) {
129
+ data[id] = value;
130
+ }
131
+ }
132
+ return data;
133
+ },
134
+ set: async data => {
135
+ const ops = [];
136
+ for (const category in data) {
137
+ for (const id in data[category]) {
138
+ ops.push([keyOf(category, id), data[category][id]]);
139
+ }
140
+ }
141
+ runTx(() => {
142
+ for (const [k, value] of ops) {
143
+ if (value === null || value === undefined) qDelete.run(k);else qUpsert.run(k, encode(value));
144
+ }
145
+ });
146
+ },
147
+ clear: async () => {
148
+ db.prepare("DELETE FROM auth_state WHERE k <> 'creds'").run();
149
+ }
150
+ };
151
+ return {
152
+ state: {
153
+ creds,
154
+ keys
155
+ },
156
+ saveCreds: async () => {
157
+ qUpsert.run('creds', encode(creds));
158
+ },
159
+ db,
160
+ close: () => db.close()
161
+ };
162
+ };