@badzz88/baileys 8.5.6 → 8.5.8

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 (225) hide show
  1. package/README.md +337 -1055
  2. package/WAProto/WAProto.proto +28 -1189
  3. package/WAProto/fix-imports.js +79 -69
  4. package/WAProto/index.d.ts +71491 -15254
  5. package/WAProto/index.js +126436 -19814
  6. package/engine-requirements.js +8 -15
  7. package/lib/Defaults/index.js +130 -0
  8. package/{src → lib}/Signal/Group/ciphertext-message.js +2 -5
  9. package/lib/Signal/Group/group-session-builder.js +30 -0
  10. package/{src → lib}/Signal/Group/group_cipher.js +11 -11
  11. package/lib/Signal/Group/index.js +12 -0
  12. package/lib/Signal/Group/keyhelper.js +18 -0
  13. package/{src → lib}/Signal/Group/sender-chain-key.js +6 -9
  14. package/{src → lib}/Signal/Group/sender-key-distribution-message.js +6 -9
  15. package/{src → lib}/Signal/Group/sender-key-message.js +9 -12
  16. package/{src → lib}/Signal/Group/sender-key-name.js +2 -5
  17. package/{src → lib}/Signal/Group/sender-key-record.js +8 -11
  18. package/{src → lib}/Signal/Group/sender-key-state.js +6 -9
  19. package/lib/Signal/Group/sender-message-key.js +26 -0
  20. package/{src → lib}/Signal/libsignal.js +131 -155
  21. package/{src → lib}/Signal/lid-mapping.js +27 -23
  22. package/lib/Socket/Client/index.js +3 -0
  23. package/lib/Socket/Client/types.js +11 -0
  24. package/{src → lib}/Socket/Client/websocket.js +11 -18
  25. package/{src → lib}/Socket/business.js +35 -67
  26. package/{src → lib}/Socket/chats.js +294 -550
  27. package/{src → lib}/Socket/communities.js +82 -114
  28. package/lib/Socket/graphql.js +716 -0
  29. package/lib/Socket/groups.js +374 -0
  30. package/lib/Socket/index.js +18 -0
  31. package/lib/Socket/interop.js +463 -0
  32. package/{src → lib}/Socket/luxu.js +120 -82
  33. package/lib/Socket/messages-recv.js +1916 -0
  34. package/lib/Socket/messages-send.js +1436 -0
  35. package/lib/Socket/mex.js +54 -0
  36. package/lib/Socket/newsletter.js +757 -0
  37. package/lib/Socket/privacy.js +318 -0
  38. package/{src → lib}/Socket/socket.js +356 -244
  39. package/lib/Socket/username.js +236 -0
  40. package/lib/Store/index.js +10 -0
  41. package/{src → lib}/Store/keyed-db.js +11 -21
  42. package/lib/Store/make-cache-manager-store.js +85 -0
  43. package/lib/Store/make-in-memory-store.js +244 -0
  44. package/{src → lib}/Store/make-ordered-dictionary.js +19 -25
  45. package/{src → lib}/Store/object-repository.js +11 -5
  46. package/lib/Types/Auth.js +2 -0
  47. package/lib/Types/Bussines.js +2 -0
  48. package/lib/Types/Call.js +2 -0
  49. package/lib/Types/Chat.js +8 -0
  50. package/lib/Types/Contact.js +2 -0
  51. package/lib/Types/Events.js +2 -0
  52. package/lib/Types/GroupMetadata.js +2 -0
  53. package/lib/Types/Label.js +25 -0
  54. package/lib/Types/LabelAssociation.js +7 -0
  55. package/lib/Types/Message.js +11 -0
  56. package/lib/Types/Mex.js +111 -0
  57. package/lib/Types/Product.js +2 -0
  58. package/lib/Types/Signal.js +2 -0
  59. package/lib/Types/Socket.js +3 -0
  60. package/lib/Types/State.js +56 -0
  61. package/lib/Types/USync.js +2 -0
  62. package/lib/Types/index.js +26 -0
  63. package/{src → lib}/Utils/auth-utils.js +91 -43
  64. package/lib/Utils/browser-utils.js +48 -0
  65. package/lib/Utils/business.js +231 -0
  66. package/lib/Utils/chat-utils.js +872 -0
  67. package/lib/Utils/companion-reg-client-utils.js +35 -0
  68. package/lib/Utils/crypto.js +118 -0
  69. package/lib/Utils/decode-wa-message.js +350 -0
  70. package/{src → lib}/Utils/event-buffer.js +81 -39
  71. package/lib/Utils/generics.js +403 -0
  72. package/lib/Utils/history.js +134 -0
  73. package/{src → lib}/Utils/identity-change-handler.js +9 -11
  74. package/lib/Utils/index.js +23 -0
  75. package/lib/Utils/link-preview.js +85 -0
  76. package/lib/Utils/logger.js +3 -0
  77. package/lib/Utils/lt-hash.js +8 -0
  78. package/{src → lib}/Utils/make-mutex.js +7 -10
  79. package/lib/Utils/message-composer.js +273 -0
  80. package/{src → lib}/Utils/message-retry-manager.js +76 -28
  81. package/lib/Utils/messages-media.js +870 -0
  82. package/lib/Utils/messages.js +1337 -0
  83. package/lib/Utils/noise-handler.js +201 -0
  84. package/{src → lib}/Utils/offline-node-processor.js +10 -4
  85. package/{src → lib}/Utils/pre-key-manager.js +27 -11
  86. package/lib/Utils/process-message.js +630 -0
  87. package/{src → lib}/Utils/reporting-utils.js +12 -15
  88. package/lib/Utils/signal.js +201 -0
  89. package/{src → lib}/Utils/stanza-ack.js +12 -4
  90. package/lib/Utils/sticker.js +110 -0
  91. package/{src → lib}/Utils/sync-action-utils.js +14 -10
  92. package/{src → lib}/Utils/tc-token-utils.js +48 -43
  93. package/{src → lib}/Utils/use-multi-file-auth-state.js +35 -25
  94. package/lib/Utils/validate-connection.js +203 -0
  95. package/{src → lib}/WABinary/constants.js +9 -12
  96. package/{src → lib}/WABinary/decode.js +38 -118
  97. package/{src → lib}/WABinary/encode.js +6 -11
  98. package/lib/WABinary/generic-utils.js +204 -0
  99. package/lib/WABinary/index.js +6 -0
  100. package/lib/WABinary/jid-utils.js +98 -0
  101. package/lib/WABinary/types.js +2 -0
  102. package/{src → lib}/WAM/BinaryInfo.js +2 -5
  103. package/{src → lib}/WAM/constants.js +4 -16635
  104. package/{src → lib}/WAM/encode.js +18 -17
  105. package/lib/WAM/index.js +4 -0
  106. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +53 -0
  107. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  108. package/lib/WAUSync/Protocols/USyncContactProtocol.js +54 -0
  109. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
  110. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
  111. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +58 -0
  112. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
  113. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  114. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +28 -0
  115. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +39 -0
  116. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  117. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +27 -0
  118. package/lib/WAUSync/Protocols/index.js +12 -0
  119. package/lib/WAUSync/USyncQuery.js +151 -0
  120. package/lib/WAUSync/USyncUser.js +56 -0
  121. package/lib/WAUSync/index.js +3 -0
  122. package/{src → lib}/index.js +16 -51
  123. package/package.json +129 -99
  124. package/LICENSE +0 -21
  125. package/src/Defaults/index.js +0 -186
  126. package/src/Defaults/phonenumber-mcc.json +0 -223
  127. package/src/Signal/Group/group-session-builder.js +0 -86
  128. package/src/Signal/Group/index.js +0 -140
  129. package/src/Signal/Group/keyhelper.js +0 -77
  130. package/src/Signal/Group/sender-message-key.js +0 -29
  131. package/src/Socket/Client/index.js +0 -31
  132. package/src/Socket/Client/types.js +0 -13
  133. package/src/Socket/aigroups.js +0 -221
  134. package/src/Socket/graphql.js +0 -523
  135. package/src/Socket/groups.js +0 -516
  136. package/src/Socket/index.js +0 -31
  137. package/src/Socket/interactive-handler.js +0 -527
  138. package/src/Socket/interop.js +0 -339
  139. package/src/Socket/managed-account.js +0 -98
  140. package/src/Socket/messages-recv.js +0 -2685
  141. package/src/Socket/messages-send.js +0 -2047
  142. package/src/Socket/mex.js +0 -57
  143. package/src/Socket/newsletter.js +0 -455
  144. package/src/Socket/privacy.js +0 -125
  145. package/src/Socket/registration.js +0 -236
  146. package/src/Socket/text-router.js +0 -65
  147. package/src/Socket/username.js +0 -130
  148. package/src/Store/index.js +0 -33
  149. package/src/Store/make-cache-manager-store.js +0 -84
  150. package/src/Store/make-in-memory-store.js +0 -551
  151. package/src/Types/Auth.js +0 -31
  152. package/src/Types/Bussines.js +0 -2
  153. package/src/Types/Call.js +0 -2
  154. package/src/Types/Chat.js +0 -4
  155. package/src/Types/Contact.js +0 -2
  156. package/src/Types/Events.js +0 -2
  157. package/src/Types/GroupMetadata.js +0 -2
  158. package/src/Types/Label.js +0 -26
  159. package/src/Types/LabelAssociation.js +0 -8
  160. package/src/Types/Message.js +0 -93
  161. package/src/Types/Mex.js +0 -112
  162. package/src/Types/Newsletter.js +0 -109
  163. package/src/Types/Product.js +0 -2
  164. package/src/Types/Signal.js +0 -2
  165. package/src/Types/Socket.js +0 -2
  166. package/src/Types/State.js +0 -62
  167. package/src/Types/USync.js +0 -2
  168. package/src/Types/index.js +0 -56
  169. package/src/Utils/browser-utils.js +0 -112
  170. package/src/Utils/business.js +0 -240
  171. package/src/Utils/chat-utils.js +0 -1230
  172. package/src/Utils/command-loader.d.ts +0 -27
  173. package/src/Utils/command-loader.js +0 -89
  174. package/src/Utils/companion-reg-client-utils.js +0 -40
  175. package/src/Utils/consumer-application.js +0 -105
  176. package/src/Utils/crypto.js +0 -118
  177. package/src/Utils/curve25519-js.js +0 -242
  178. package/src/Utils/decode-wa-message.js +0 -529
  179. package/src/Utils/generics.js +0 -483
  180. package/src/Utils/group-history.js +0 -44
  181. package/src/Utils/history.js +0 -232
  182. package/src/Utils/index.js +0 -58
  183. package/src/Utils/jid-display-normalization.js +0 -195
  184. package/src/Utils/link-preview.js +0 -135
  185. package/src/Utils/logger.js +0 -8
  186. package/src/Utils/lt-hash.js +0 -25
  187. package/src/Utils/message-composer.js +0 -471
  188. package/src/Utils/messages-media.js +0 -843
  189. package/src/Utils/messages.js +0 -2817
  190. package/src/Utils/meta-ai-msmsg.js +0 -222
  191. package/src/Utils/native-bridge.js +0 -68
  192. package/src/Utils/noise-handler.js +0 -169
  193. package/src/Utils/process-message.js +0 -950
  194. package/src/Utils/session-pool.d.ts +0 -14
  195. package/src/Utils/session-pool.js +0 -70
  196. package/src/Utils/signal.js +0 -217
  197. package/src/Utils/sticker.d.ts +0 -13
  198. package/src/Utils/sticker.js +0 -123
  199. package/src/Utils/validate-connection.js +0 -209
  200. package/src/Utils/view-once-cache.d.ts +0 -12
  201. package/src/Utils/view-once-cache.js +0 -63
  202. package/src/Utils/voip-rekey.js +0 -22
  203. package/src/WABinary/generic-utils.js +0 -238
  204. package/src/WABinary/index.js +0 -34
  205. package/src/WABinary/jid-utils.js +0 -351
  206. package/src/WABinary/types.js +0 -2
  207. package/src/WAM/index.js +0 -32
  208. package/src/WAUSync/Protocols/USyncBotProfileProtocol.js +0 -53
  209. package/src/WAUSync/Protocols/USyncBusinessProtocol.js +0 -44
  210. package/src/WAUSync/Protocols/USyncContactProtocol.js +0 -55
  211. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +0 -55
  212. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +0 -31
  213. package/src/WAUSync/Protocols/USyncFeatureProtocol.js +0 -54
  214. package/src/WAUSync/Protocols/USyncLIDProtocol.js +0 -32
  215. package/src/WAUSync/Protocols/USyncNewsletterProtocol.js +0 -473
  216. package/src/WAUSync/Protocols/USyncPictureProtocol.js +0 -34
  217. package/src/WAUSync/Protocols/USyncSidelistProtocol.js +0 -29
  218. package/src/WAUSync/Protocols/USyncStatusProtocol.js +0 -42
  219. package/src/WAUSync/Protocols/USyncTextStatusProtocol.js +0 -38
  220. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +0 -28
  221. package/src/WAUSync/Protocols/index.js +0 -40
  222. package/src/WAUSync/USyncQuery.js +0 -126
  223. package/src/WAUSync/USyncUser.js +0 -50
  224. package/src/WAUSync/index.js +0 -32
  225. package/src/antiban.js +0 -4152
@@ -1,8 +1,6 @@
1
- 'use strict';
2
- Object.defineProperty(exports, '__esModule', { value: true });
3
- exports.getMessageReportingToken = exports.shouldIncludeReportingToken = void 0;
4
- const Crypto_1 = require('./crypto');
5
- const crypto_2 = require('./crypto');
1
+ import { createHmac } from 'crypto';
2
+ import { proto } from '../../WAProto/index.js';
3
+ import { hkdf } from './crypto.js';
6
4
  const reportingFields = [
7
5
  { f: 1 },
8
6
  {
@@ -59,7 +57,7 @@ const reportingFields = [
59
57
  { f: 93, s: [{ f: 1, m: true }] },
60
58
  { f: 94, s: [{ f: 1, m: true }] }
61
59
  ];
62
- const compileReportingFields = fields => {
60
+ const compileReportingFields = (fields) => {
63
61
  const map = new Map();
64
62
  for (const f of fields) {
65
63
  map.set(f.f, {
@@ -78,11 +76,10 @@ const WIRE = {
78
76
  BYTES: 2,
79
77
  FIXED32: 5
80
78
  };
81
- const shouldIncludeReportingToken = message => !message.reactionMessage &&
79
+ export const shouldIncludeReportingToken = (message) => !message.reactionMessage &&
82
80
  !message.encReactionMessage &&
83
81
  !message.encEventResponseMessage &&
84
82
  !message.pollUpdateMessage;
85
- exports.shouldIncludeReportingToken = shouldIncludeReportingToken;
86
83
  const generateMsgSecretKey = (modificationType, origMsgId, origMsgSender, modificationSender, origMsgSecret) => {
87
84
  const useCaseSecret = Buffer.concat([
88
85
  Buffer.from(origMsgId, 'utf8'),
@@ -90,7 +87,7 @@ const generateMsgSecretKey = (modificationType, origMsgId, origMsgSender, modifi
90
87
  Buffer.from(modificationSender, 'utf8'),
91
88
  Buffer.from(modificationType, 'utf8')
92
89
  ]);
93
- return (0, crypto_2.hkdf)(origMsgSecret, 32, { info: useCaseSecret.toString('latin1') });
90
+ return hkdf(origMsgSecret, 32, { info: useCaseSecret.toString('latin1') });
94
91
  };
95
92
  const extractReportingTokenContent = (data, cfg) => {
96
93
  const out = [];
@@ -105,7 +102,7 @@ const extractReportingTokenContent = (data, cfg) => {
105
102
  const fieldStart = i;
106
103
  i += tag.bytes;
107
104
  const fieldCfg = cfg.get(fieldNum);
108
- const pushSlice = end => {
105
+ const pushSlice = (end) => {
109
106
  if (end > data.length) {
110
107
  return false;
111
108
  }
@@ -113,7 +110,7 @@ const extractReportingTokenContent = (data, cfg) => {
113
110
  i = end;
114
111
  return true;
115
112
  };
116
- const skip = end => {
113
+ const skip = (end) => {
117
114
  if (end > data.length) {
118
115
  return false;
119
116
  }
@@ -223,7 +220,7 @@ const decodeVarint = (buffer, offset) => {
223
220
  }
224
221
  return { value: 0, bytes: 0, ok: false };
225
222
  };
226
- const encodeVarint = value => {
223
+ const encodeVarint = (value) => {
227
224
  const parts = [];
228
225
  let remaining = value >>> 0;
229
226
  while (remaining > 0x7f) {
@@ -233,7 +230,7 @@ const encodeVarint = value => {
233
230
  parts.push(remaining);
234
231
  return Buffer.from(parts);
235
232
  };
236
- const getMessageReportingToken = async (msgProtobuf, message, key) => {
233
+ export const getMessageReportingToken = async (msgProtobuf, message, key) => {
237
234
  const msgSecret = message.messageContextInfo?.messageSecret;
238
235
  if (!msgSecret || !key.id) {
239
236
  return null;
@@ -245,7 +242,7 @@ const getMessageReportingToken = async (msgProtobuf, message, key) => {
245
242
  if (!content || content.length === 0) {
246
243
  return null;
247
244
  }
248
- const reportingToken = Buffer.from(Crypto_1.hmacSign(content, reportingSecret)).subarray(0, 16);
245
+ const reportingToken = createHmac('sha256', reportingSecret).update(content).digest().subarray(0, 16);
249
246
  return {
250
247
  tag: 'reporting',
251
248
  attrs: {},
@@ -258,4 +255,4 @@ const getMessageReportingToken = async (msgProtobuf, message, key) => {
258
255
  ]
259
256
  };
260
257
  };
261
- exports.getMessageReportingToken = getMessageReportingToken;
258
+ //# sourceMappingURL=reporting-utils.js.map
@@ -0,0 +1,201 @@
1
+ import { KEY_BUNDLE_TYPE } from '../Defaults/index.js';
2
+ import { assertNodeErrorFree, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildUInt, getServerFromDomainType, jidDecode, S_WHATSAPP_NET, WAJIDDomains } from '../WABinary/index.js';
3
+ import { Curve, generateSignalPubKey } from './crypto.js';
4
+ import { encodeBigEndian } from './generics.js';
5
+ function chunk(array, size) {
6
+ const chunks = [];
7
+ for (let i = 0; i < array.length; i += size) {
8
+ chunks.push(array.slice(i, i + size));
9
+ }
10
+ return chunks;
11
+ }
12
+ export const createSignalIdentity = (wid, accountSignatureKey) => {
13
+ return {
14
+ identifier: { name: wid, deviceId: 0 },
15
+ identifierKey: generateSignalPubKey(accountSignatureKey)
16
+ };
17
+ };
18
+ export const getPreKeys = async ({ get }, min, limit) => {
19
+ const idList = [];
20
+ for (let id = min; id < limit; id++) {
21
+ idList.push(id.toString());
22
+ }
23
+ return get('pre-key', idList);
24
+ };
25
+ export const generateOrGetPreKeys = (creds, range) => {
26
+ const avaliable = creds.nextPreKeyId - creds.firstUnuploadedPreKeyId;
27
+ const remaining = range - avaliable;
28
+ const lastPreKeyId = creds.nextPreKeyId + remaining - 1;
29
+ const newPreKeys = {};
30
+ if (remaining > 0) {
31
+ for (let i = creds.nextPreKeyId; i <= lastPreKeyId; i++) {
32
+ newPreKeys[i] = Curve.generateKeyPair();
33
+ }
34
+ }
35
+ return {
36
+ newPreKeys,
37
+ lastPreKeyId,
38
+ preKeysRange: [creds.firstUnuploadedPreKeyId, range]
39
+ };
40
+ };
41
+ export const xmppSignedPreKey = (key) => ({
42
+ tag: 'skey',
43
+ attrs: {},
44
+ content: [
45
+ { tag: 'id', attrs: {}, content: encodeBigEndian(key.keyId, 3) },
46
+ { tag: 'value', attrs: {}, content: key.keyPair.public },
47
+ { tag: 'signature', attrs: {}, content: key.signature }
48
+ ]
49
+ });
50
+ export const xmppPreKey = (pair, id) => ({
51
+ tag: 'key',
52
+ attrs: {},
53
+ content: [
54
+ { tag: 'id', attrs: {}, content: encodeBigEndian(id, 3) },
55
+ { tag: 'value', attrs: {}, content: pair.public }
56
+ ]
57
+ });
58
+ const isValidUInt = (n) => typeof n === 'number' && Number.isInteger(n);
59
+ export const extractE2ESessionFromRetryReceipt = (receipt) => {
60
+ const keysNode = getBinaryNodeChild(receipt, 'keys');
61
+ if (!keysNode)
62
+ return null;
63
+ const typeBuf = getBinaryNodeChildBuffer(keysNode, 'type');
64
+ if (!typeBuf || typeBuf.length !== 1 || typeBuf[0] !== KEY_BUNDLE_TYPE[0])
65
+ return null;
66
+ const identity = getBinaryNodeChildBuffer(keysNode, 'identity');
67
+ const skey = getBinaryNodeChild(keysNode, 'skey');
68
+ if (!identity || identity.length !== 32 || !skey)
69
+ return null;
70
+ const registrationId = getBinaryNodeChildUInt(receipt, 'registration', 4);
71
+ if (!isValidUInt(registrationId))
72
+ return null;
73
+ const signedPubKey = getBinaryNodeChildBuffer(skey, 'value');
74
+ const signedSig = getBinaryNodeChildBuffer(skey, 'signature');
75
+ const signedKeyId = getBinaryNodeChildUInt(skey, 'id', 3);
76
+ if (!signedPubKey || signedPubKey.length !== 32 || !signedSig || !isValidUInt(signedKeyId)) {
77
+ return null;
78
+ }
79
+ const preKeyNode = getBinaryNodeChild(keysNode, 'key');
80
+ let preKey;
81
+ if (preKeyNode) {
82
+ const preKeyPub = getBinaryNodeChildBuffer(preKeyNode, 'value');
83
+ const preKeyId = getBinaryNodeChildUInt(preKeyNode, 'id', 3);
84
+ if (!preKeyPub || preKeyPub.length !== 32 || !isValidUInt(preKeyId)) {
85
+ return null;
86
+ }
87
+ preKey = { keyId: preKeyId, publicKey: generateSignalPubKey(preKeyPub) };
88
+ }
89
+ return {
90
+ registrationId,
91
+ identityKey: generateSignalPubKey(identity),
92
+ signedPreKey: {
93
+ keyId: signedKeyId,
94
+ publicKey: generateSignalPubKey(signedPubKey),
95
+ signature: signedSig
96
+ },
97
+ preKey
98
+ };
99
+ };
100
+ export const parseAndInjectE2ESessions = async (node, repository) => {
101
+ const extractKey = (key) => key
102
+ ? {
103
+ keyId: getBinaryNodeChildUInt(key, 'id', 3),
104
+ publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, 'value')),
105
+ signature: getBinaryNodeChildBuffer(key, 'signature')
106
+ }
107
+ : undefined;
108
+ const nodes = getBinaryNodeChildren(getBinaryNodeChild(node, 'list'), 'user');
109
+ for (const node of nodes) {
110
+ assertNodeErrorFree(node);
111
+ }
112
+ // Most of the work in repository.injectE2ESession is CPU intensive, not IO
113
+ // So Promise.all doesn't really help here,
114
+ // but blocks even loop if we're using it inside keys.transaction, and it makes it "sync" actually
115
+ // This way we chunk it in smaller parts and between those parts we can yield to the event loop
116
+ // It's rare case when you need to E2E sessions for so many users, but it's possible
117
+ const chunkSize = 100;
118
+ const chunks = chunk(nodes, chunkSize);
119
+ for (const nodesChunk of chunks) {
120
+ for (const node of nodesChunk) {
121
+ const signedKey = getBinaryNodeChild(node, 'skey');
122
+ const key = getBinaryNodeChild(node, 'key');
123
+ const identity = getBinaryNodeChildBuffer(node, 'identity');
124
+ const jid = node.attrs.jid;
125
+ const registrationId = getBinaryNodeChildUInt(node, 'registration', 4);
126
+ await repository.injectE2ESession({
127
+ jid,
128
+ session: {
129
+ registrationId: registrationId,
130
+ identityKey: generateSignalPubKey(identity),
131
+ signedPreKey: extractKey(signedKey),
132
+ preKey: extractKey(key)
133
+ }
134
+ });
135
+ }
136
+ }
137
+ };
138
+ export const extractDeviceJids = (result, myJid, myLid, excludeZeroDevices) => {
139
+ const { user: myUser, device: myDevice } = jidDecode(myJid);
140
+ const extracted = [];
141
+ for (const userResult of result) {
142
+ const { devices, id } = userResult;
143
+ const decoded = jidDecode(id), { user, server } = decoded;
144
+ let { domainType } = decoded;
145
+ const deviceList = devices?.deviceList;
146
+ if (!Array.isArray(deviceList))
147
+ continue;
148
+ for (const { id: device, keyIndex, isHosted } of deviceList) {
149
+ if ((!excludeZeroDevices || device !== 0) && // if zero devices are not-excluded, or device is non zero
150
+ ((myUser !== user && myLid !== user) || myDevice !== device) && // either different user or if me user, not this device
151
+ (device === 0 || !!keyIndex) // ensure that "key-index" is specified for "non-zero" devices, produces a bad req otherwise
152
+ ) {
153
+ if (isHosted) {
154
+ domainType = domainType === WAJIDDomains.LID ? WAJIDDomains.HOSTED_LID : WAJIDDomains.HOSTED;
155
+ }
156
+ extracted.push({
157
+ user,
158
+ device,
159
+ domainType,
160
+ server: getServerFromDomainType(server, domainType)
161
+ });
162
+ }
163
+ }
164
+ }
165
+ return extracted;
166
+ };
167
+ /**
168
+ * get the next N keys for upload or processing
169
+ * @param count number of pre-keys to get or generate
170
+ */
171
+ export const getNextPreKeys = async ({ creds, keys }, count) => {
172
+ const { newPreKeys, lastPreKeyId, preKeysRange } = generateOrGetPreKeys(creds, count);
173
+ const update = {
174
+ nextPreKeyId: Math.max(lastPreKeyId + 1, creds.nextPreKeyId),
175
+ firstUnuploadedPreKeyId: Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId + 1)
176
+ };
177
+ await keys.set({ 'pre-key': newPreKeys });
178
+ const preKeys = await getPreKeys(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1]);
179
+ return { update, preKeys };
180
+ };
181
+ export const getNextPreKeysNode = async (state, count) => {
182
+ const { creds } = state;
183
+ const { update, preKeys } = await getNextPreKeys(state, count);
184
+ const node = {
185
+ tag: 'iq',
186
+ attrs: {
187
+ xmlns: 'encrypt',
188
+ type: 'set',
189
+ to: S_WHATSAPP_NET
190
+ },
191
+ content: [
192
+ { tag: 'registration', attrs: {}, content: encodeBigEndian(creds.registrationId) },
193
+ { tag: 'type', attrs: {}, content: KEY_BUNDLE_TYPE },
194
+ { tag: 'identity', attrs: {}, content: creds.signedIdentityKey.public },
195
+ { tag: 'list', attrs: {}, content: Object.keys(preKeys).map(k => xmppPreKey(preKeys[+k], +k)) },
196
+ xmppSignedPreKey(creds.signedPreKey)
197
+ ]
198
+ };
199
+ return { update, node };
200
+ };
201
+ //# sourceMappingURL=signal.js.map
@@ -1,7 +1,12 @@
1
- 'use strict';
2
- Object.defineProperty(exports, '__esModule', { value: true });
3
- exports.buildAckStanza = buildAckStanza;
4
- function buildAckStanza(node, errorCode, meId) {
1
+ /**
2
+ * Builds an ACK stanza for a received node.
3
+ * Pure function -- no I/O, no side effects.
4
+ *
5
+ * Mirrors WhatsApp Web's ACK construction:
6
+ * - WAWebHandleMsgSendAck.sendAck / sendNack
7
+ * - WAWebCreateNackFromStanza.createNackFromStanza
8
+ */
9
+ export function buildAckStanza(node, errorCode, meId) {
5
10
  const { tag, attrs } = node;
6
11
  const stanza = {
7
12
  tag: 'ack',
@@ -20,11 +25,14 @@ function buildAckStanza(node, errorCode, meId) {
20
25
  if (attrs.recipient) {
21
26
  stanza.attrs.recipient = attrs.recipient;
22
27
  }
28
+ // WA Web always includes type when present: `n.type || DROP_ATTR`
23
29
  if (attrs.type) {
24
30
  stanza.attrs.type = attrs.type;
25
31
  }
32
+ // WA Web WAWebHandleMsgSendAck.sendAck/sendNack always include `from` for message-class ACKs
26
33
  if (tag === 'message' && meId) {
27
34
  stanza.attrs.from = meId;
28
35
  }
29
36
  return stanza;
30
37
  }
38
+ //# sourceMappingURL=stanza-ack.js.map
@@ -0,0 +1,110 @@
1
+ import { Boom } from '@hapi/boom';
2
+ import { spawn } from 'child_process';
3
+ import { randomUUID } from 'crypto';
4
+
5
+ const runFfmpeg = (input, args) => new Promise((resolve, reject) => {
6
+ const proc = spawn('ffmpeg', ['-hide_banner', '-loglevel', 'error', '-i', 'pipe:0', ...args, 'pipe:1'], { stdio: ['pipe', 'pipe', 'pipe'] });
7
+ const outChunks = [];
8
+ const errChunks = [];
9
+ proc.stdout.on('data', chunk => outChunks.push(chunk));
10
+ proc.stderr.on('data', chunk => errChunks.push(chunk));
11
+ proc.on('error', err => reject(new Boom(`ffmpeg failed to start: ${err.message}`, { statusCode: 500 })));
12
+ proc.on('close', code => {
13
+ if (code !== 0) {
14
+ reject(new Boom(`ffmpeg exited with code ${code}: ${Buffer.concat(errChunks).toString('utf8').slice(0, 500)}`, { statusCode: 500 }));
15
+ return;
16
+ }
17
+ resolve(Buffer.concat(outChunks));
18
+ });
19
+ proc.stdin.on('error', () => { });
20
+ proc.stdin.end(input);
21
+ });
22
+ export const convertToWebp = async (buffer, { animated = false, quality = 60 } = {}) => {
23
+ const scalePad = "scale='min(512,iw)':'min(512,ih)':force_original_aspect_ratio=decrease,format=rgba,pad=512:512:-1:-1:color=#00000000";
24
+ const args = animated
25
+ ? ['-vf', `${scalePad},fps=15`, '-loop', '0', '-preset', 'default', '-an', '-vsync', '0', '-vcodec', 'libwebp', '-q:v', String(quality), '-f', 'webp']
26
+ : ['-vf', `${scalePad}`, '-vframes', '1', '-vcodec', 'libwebp', '-q:v', String(quality), '-f', 'webp'];
27
+ return runFfmpeg(buffer, args);
28
+ };
29
+ const readChunks = (buf) => {
30
+ const chunks = [];
31
+ let offset = 12;
32
+ while (offset + 8 <= buf.length) {
33
+ const fourCC = buf.toString('ascii', offset, offset + 4);
34
+ const size = buf.readUInt32LE(offset + 4);
35
+ const dataStart = offset + 8;
36
+ const data = buf.subarray(dataStart, dataStart + size);
37
+ chunks.push({ fourCC, data });
38
+ offset = dataStart + size + (size % 2);
39
+ }
40
+ return chunks;
41
+ };
42
+ const buildChunk = (fourCC, data) => {
43
+ const header = Buffer.alloc(8);
44
+ header.write(fourCC, 0, 4, 'ascii');
45
+ header.writeUInt32LE(data.length, 4);
46
+ const pad = data.length % 2 === 1 ? Buffer.from([0]) : Buffer.alloc(0);
47
+ return Buffer.concat([header, data, pad]);
48
+ };
49
+ const buildExifChunkData = (json) => {
50
+ const header = Buffer.from([0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
51
+ const payload = Buffer.from(JSON.stringify(json), 'utf8');
52
+ header.writeUInt32LE(payload.length, 14);
53
+ return Buffer.concat([header, payload]);
54
+ };
55
+ export const writeExifToWebp = (webpBuffer, { packId, packName = '', publisher = '', emojis = [], isAvatar = false } = {}) => {
56
+ if (webpBuffer.toString('ascii', 0, 4) !== 'RIFF' || webpBuffer.toString('ascii', 8, 12) !== 'WEBP') {
57
+ throw new Boom('writeExifToWebp: not a valid webp buffer', { statusCode: 400 });
58
+ }
59
+ const chunks = readChunks(webpBuffer);
60
+ const exifData = buildExifChunkData({
61
+ 'sticker-pack-id': packId || randomUUID(),
62
+ 'sticker-pack-name': packName,
63
+ 'sticker-pack-publisher': publisher,
64
+ emojis: emojis.length ? emojis : ['🤖'],
65
+ 'is-avatar-sticker': isAvatar ? 1 : 0
66
+ });
67
+ let vp8x = chunks.find(c => c.fourCC === 'VP8X');
68
+ const otherChunks = chunks.filter(c => c.fourCC !== 'VP8X' && c.fourCC !== 'EXIF');
69
+ if (!vp8x) {
70
+ const img = otherChunks.find(c => c.fourCC === 'VP8 ' || c.fourCC === 'VP8L');
71
+ if (!img) {
72
+ throw new Boom('writeExifToWebp: no VP8/VP8L image data found', { statusCode: 400 });
73
+ }
74
+ let width;
75
+ let height;
76
+ if (img.fourCC === 'VP8 ') {
77
+ width = (img.data.readUInt16LE(6) & 0x3fff);
78
+ height = (img.data.readUInt16LE(8) & 0x3fff);
79
+ }
80
+ else {
81
+ const b = img.data;
82
+ width = 1 + (((b[2] & 0x3f) << 8) | b[1]);
83
+ height = 1 + (((b[4] & 0xf) << 10) | (b[3] << 2) | ((b[2] & 0xc0) >> 6));
84
+ }
85
+ const flags = Buffer.alloc(4);
86
+ flags[0] = 0x08;
87
+ const dims = Buffer.alloc(6);
88
+ dims.writeUIntLE(width - 1, 0, 3);
89
+ dims.writeUIntLE(height - 1, 3, 3);
90
+ vp8x = { fourCC: 'VP8X', data: Buffer.concat([flags, dims]) };
91
+ }
92
+ else {
93
+ const flagsByte = vp8x.data[0] | 0x08;
94
+ vp8x = { fourCC: 'VP8X', data: Buffer.concat([Buffer.from([flagsByte]), vp8x.data.subarray(1)]) };
95
+ }
96
+ const rebuilt = [vp8x, ...otherChunks, { fourCC: 'EXIF', data: exifData }];
97
+ const chunkBuffers = rebuilt.map(c => buildChunk(c.fourCC, c.data));
98
+ const payload = Buffer.concat(chunkBuffers);
99
+ const riffSize = 4 + payload.length;
100
+ const out = Buffer.alloc(8 + 4 + payload.length);
101
+ out.write('RIFF', 0, 4, 'ascii');
102
+ out.writeUInt32LE(riffSize, 4);
103
+ out.write('WEBP', 8, 4, 'ascii');
104
+ payload.copy(out, 12);
105
+ return out;
106
+ };
107
+ export const makeSticker = async (buffer, { pack = '', author = '', emojis = [], isPrivate = false, animated = false, quality = 60 } = {}) => {
108
+ const webp = await convertToWebp(buffer, { animated, quality });
109
+ return writeExifToWebp(webp, { packName: pack, publisher: author, emojis, isAvatar: isPrivate });
110
+ };
@@ -1,16 +1,20 @@
1
- 'use strict';
2
- Object.defineProperty(exports, '__esModule', { value: true });
3
- exports.emitSyncActionResults = exports.processContactAction = void 0;
4
- const WABinary_1 = require('../WABinary');
5
- const processContactAction = (action, id, logger) => {
1
+ import { proto } from '../../WAProto/index.js';
2
+ import { isLidUser, isPnUser } from '../WABinary/index.js';
3
+ /**
4
+ * Process contactAction and return events to emit.
5
+ * Pure function - no side effects.
6
+ */
7
+ export const processContactAction = (action, id, logger) => {
6
8
  const results = [];
7
9
  if (!id) {
8
10
  logger?.warn({ hasFullName: !!action.fullName, hasLidJid: !!action.lidJid, hasPnJid: !!action.pnJid }, 'contactAction sync: missing id in index');
9
11
  return results;
10
12
  }
11
13
  const lidJid = action.lidJid;
12
- const idIsPn = (0, WABinary_1.isPnUser)(id);
14
+ const idIsPn = isPnUser(id);
15
+ // PN is in index[1], not in contactAction.pnJid which is usually null
13
16
  const phoneNumber = idIsPn ? id : action.pnJid || undefined;
17
+ // Always emit contacts.upsert
14
18
  results.push({
15
19
  event: 'contacts.upsert',
16
20
  data: [
@@ -23,7 +27,8 @@ const processContactAction = (action, id, logger) => {
23
27
  }
24
28
  ]
25
29
  });
26
- if (lidJid && (0, WABinary_1.isLidUser)(lidJid) && idIsPn) {
30
+ // Emit lid-mapping.update if we have valid LID-PN pair
31
+ if (lidJid && isLidUser(lidJid) && idIsPn) {
27
32
  results.push({
28
33
  event: 'lid-mapping.update',
29
34
  data: { lid: lidJid, pn: id }
@@ -31,8 +36,7 @@ const processContactAction = (action, id, logger) => {
31
36
  }
32
37
  return results;
33
38
  };
34
- exports.processContactAction = processContactAction;
35
- const emitSyncActionResults = (ev, results) => {
39
+ export const emitSyncActionResults = (ev, results) => {
36
40
  for (const result of results) {
37
41
  if (result.event === 'contacts.upsert') {
38
42
  ev.emit('contacts.upsert', result.data);
@@ -42,4 +46,4 @@ const emitSyncActionResults = (ev, results) => {
42
46
  }
43
47
  }
44
48
  };
45
- exports.emitSyncActionResults = emitSyncActionResults;
49
+ //# sourceMappingURL=sync-action-utils.js.map
@@ -1,62 +1,59 @@
1
- 'use strict';
2
- Object.defineProperty(exports, '__esModule', { value: true });
3
- exports.TC_TOKEN_INDEX_KEY = void 0;
4
- exports.readTcTokenIndex = readTcTokenIndex;
5
- exports.buildMergedTcTokenIndexWrite = buildMergedTcTokenIndexWrite;
6
- exports.isTcTokenExpired = isTcTokenExpired;
7
- exports.shouldSendNewTcToken = shouldSendNewTcToken;
8
- exports.resolveTcTokenJid = resolveTcTokenJid;
9
- exports.resolveIssuanceJid = resolveIssuanceJid;
10
- exports.buildTcTokenFromJid = buildTcTokenFromJid;
11
- exports.storeTcTokensFromIqResult = storeTcTokensFromIqResult;
12
- const WABinary_1 = require('../WABinary');
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.
13
4
  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
+ */
14
11
  function isRegularUser(jid) {
15
12
  if (!jid)
16
13
  return false;
17
14
  const user = jid.split('@')[0] ?? '';
18
15
  if (user === '0')
19
- return false;
16
+ return false; // PSA
20
17
  if (BOT_PHONE_REGEX.test(user))
21
- return false;
22
- if ((0, WABinary_1.isJidMetaAI)(jid))
23
- return false;
24
- return !!((0, WABinary_1.isPnUser)(jid) ||
25
- (0, WABinary_1.isLidUser)(jid) ||
26
- (0, WABinary_1.isHostedPnUser)(jid) ||
27
- (0, WABinary_1.isHostedLidUser)(jid) ||
28
- jid.endsWith('@c.us'));
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'));
29
22
  }
30
- const TC_TOKEN_BUCKET_DURATION = 604800;
31
- const TC_TOKEN_NUM_BUCKETS = 4;
32
- exports.TC_TOKEN_INDEX_KEY = '__index';
33
- async function readTcTokenIndex(keys) {
34
- const data = await keys.get('tctoken', [exports.TC_TOKEN_INDEX_KEY]);
35
- const entry = data[exports.TC_TOKEN_INDEX_KEY];
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. */
26
+ 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
+ export async function readTcTokenIndex(keys) {
29
+ const data = await keys.get('tctoken', [TC_TOKEN_INDEX_KEY]);
30
+ const entry = data[TC_TOKEN_INDEX_KEY];
36
31
  if (!entry?.token?.length)
37
32
  return [];
38
33
  try {
39
34
  const parsed = JSON.parse(Buffer.from(entry.token).toString());
40
35
  if (!Array.isArray(parsed))
41
36
  return [];
42
- return parsed.filter(j => typeof j === 'string' && j.length > 0 && j !== exports.TC_TOKEN_INDEX_KEY);
37
+ return parsed.filter((j) => typeof j === 'string' && j.length > 0 && j !== TC_TOKEN_INDEX_KEY);
43
38
  }
44
39
  catch {
45
40
  return [];
46
41
  }
47
42
  }
48
- async function buildMergedTcTokenIndexWrite(keys, addedJids) {
43
+ /** Build a SignalDataSet fragment that writes the merged index (persisted ∪ added) under the sentinel key. */
44
+ export async function buildMergedTcTokenIndexWrite(keys, addedJids) {
49
45
  const persisted = await readTcTokenIndex(keys);
50
46
  const merged = new Set(persisted);
51
47
  for (const jid of addedJids) {
52
- if (jid && jid !== exports.TC_TOKEN_INDEX_KEY)
48
+ if (jid && jid !== TC_TOKEN_INDEX_KEY)
53
49
  merged.add(jid);
54
50
  }
55
51
  return {
56
- [exports.TC_TOKEN_INDEX_KEY]: { token: Buffer.from(JSON.stringify([...merged])) }
52
+ [TC_TOKEN_INDEX_KEY]: { token: Buffer.from(JSON.stringify([...merged])) }
57
53
  };
58
54
  }
59
- function isTcTokenExpired(timestamp) {
55
+ // WA Web has separate sender/receiver AB props for these but they're identical today
56
+ export function isTcTokenExpired(timestamp) {
60
57
  if (timestamp === null || timestamp === undefined)
61
58
  return true;
62
59
  const ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp;
@@ -68,7 +65,7 @@ function isTcTokenExpired(timestamp) {
68
65
  const cutoffTimestamp = cutoffBucket * TC_TOKEN_BUCKET_DURATION;
69
66
  return ts < cutoffTimestamp;
70
67
  }
71
- function shouldSendNewTcToken(senderTimestamp) {
68
+ export function shouldSendNewTcToken(senderTimestamp) {
72
69
  if (senderTimestamp === undefined)
73
70
  return true;
74
71
  const now = Math.floor(Date.now() / 1000);
@@ -76,20 +73,22 @@ function shouldSendNewTcToken(senderTimestamp) {
76
73
  const senderBucket = Math.floor(senderTimestamp / TC_TOKEN_BUCKET_DURATION);
77
74
  return currentBucket > senderBucket;
78
75
  }
79
- async function resolveTcTokenJid(jid, getLIDForPN) {
80
- if ((0, WABinary_1.isLidUser)(jid))
76
+ /** Resolve JID to LID for tctoken storage (WA Web stores under LID) */
77
+ export async function resolveTcTokenJid(jid, getLIDForPN) {
78
+ if (isLidUser(jid))
81
79
  return jid;
82
80
  const lid = await getLIDForPN(jid);
83
81
  return lid ?? jid;
84
82
  }
85
- async function resolveIssuanceJid(jid, issueToLid, getLIDForPN, getPNForLID) {
83
+ /** Resolve target JID for issuing privacy token based on AB prop 14303 */
84
+ export async function resolveIssuanceJid(jid, issueToLid, getLIDForPN, getPNForLID) {
86
85
  if (issueToLid) {
87
- if ((0, WABinary_1.isLidUser)(jid))
86
+ if (isLidUser(jid))
88
87
  return jid;
89
88
  const lid = await getLIDForPN(jid);
90
89
  return lid ?? jid;
91
90
  }
92
- if (!(0, WABinary_1.isLidUser)(jid))
91
+ if (!isLidUser(jid))
93
92
  return jid;
94
93
  if (getPNForLID) {
95
94
  const pn = await getPNForLID(jid);
@@ -97,7 +96,7 @@ async function resolveIssuanceJid(jid, issueToLid, getLIDForPN, getPNForLID) {
97
96
  }
98
97
  return jid;
99
98
  }
100
- async function buildTcTokenFromJid({ authState, jid, baseContent = [], getLIDForPN }) {
99
+ export async function buildTcTokenFromJid({ authState, jid, baseContent = [], getLIDForPN }) {
101
100
  try {
102
101
  const storageJid = await resolveTcTokenJid(jid, getLIDForPN);
103
102
  const tcTokenData = await authState.keys.get('tctoken', [storageJid]);
@@ -105,6 +104,9 @@ async function buildTcTokenFromJid({ authState, jid, baseContent = [], getLIDFor
105
104
  const tcTokenBuffer = entry?.token;
106
105
  if (!tcTokenBuffer?.length || isTcTokenExpired(entry?.timestamp)) {
107
106
  if (tcTokenBuffer) {
107
+ // Preserve senderTimestamp so shouldSendNewTcToken() keeps its dedupe state
108
+ // after we drop the unusable peer token. Only wipe the record entirely when
109
+ // there's nothing worth keeping.
108
110
  const cleared = entry?.senderTimestamp !== undefined
109
111
  ? { token: Buffer.alloc(0), senderTimestamp: entry.senderTimestamp }
110
112
  : null;
@@ -123,16 +125,17 @@ async function buildTcTokenFromJid({ authState, jid, baseContent = [], getLIDFor
123
125
  return baseContent.length > 0 ? baseContent : undefined;
124
126
  }
125
127
  }
126
- async function storeTcTokensFromIqResult({ result, fallbackJid, keys, getLIDForPN, onNewJidStored }) {
127
- const tokensNode = (0, WABinary_1.getBinaryNodeChild)(result, 'tokens');
128
+ export async function storeTcTokensFromIqResult({ result, fallbackJid, keys, getLIDForPN, onNewJidStored }) {
129
+ const tokensNode = getBinaryNodeChild(result, 'tokens');
128
130
  if (!tokensNode)
129
131
  return;
130
- const tokenNodes = (0, WABinary_1.getBinaryNodeChildren)(tokensNode, 'token');
132
+ const tokenNodes = getBinaryNodeChildren(tokensNode, 'token');
131
133
  for (const tokenNode of tokenNodes) {
132
134
  if (tokenNode.attrs.type !== 'trusted_contact' || !(tokenNode.content instanceof Uint8Array)) {
133
135
  continue;
134
136
  }
135
- const rawJid = (0, WABinary_1.jidNormalizedUser)(fallbackJid || tokenNode.attrs.jid);
137
+ // In notifications tokenNode.attrs.jid is your own device JID, not the sender's
138
+ const rawJid = jidNormalizedUser(fallbackJid || tokenNode.attrs.jid);
136
139
  if (!isRegularUser(rawJid))
137
140
  continue;
138
141
  const storageJid = await resolveTcTokenJid(rawJid, getLIDForPN);
@@ -140,6 +143,7 @@ async function storeTcTokensFromIqResult({ result, fallbackJid, keys, getLIDForP
140
143
  const existingEntry = existingTcData[storageJid];
141
144
  const existingTs = existingEntry?.timestamp ? Number(existingEntry.timestamp) : 0;
142
145
  const incomingTs = tokenNode.attrs.t ? Number(tokenNode.attrs.t) : 0;
146
+ // timestamp-less tokens would be immediately expired
143
147
  if (!incomingTs)
144
148
  continue;
145
149
  if (existingTs > 0 && existingTs > incomingTs)
@@ -156,3 +160,4 @@ async function storeTcTokensFromIqResult({ result, fallbackJid, keys, getLIDForP
156
160
  onNewJidStored?.(storageJid);
157
161
  }
158
162
  }
163
+ //# sourceMappingURL=tc-token-utils.js.map