@badzz88/baileys 8.5.2 → 8.5.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 (110) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +1256 -75
  3. package/WAProto/index.d.ts +36042 -19649
  4. package/WAProto/index.js +181990 -135645
  5. package/engine-requirements.js +7 -15
  6. package/lib/Defaults/index.js +22 -17
  7. package/lib/Signal/Group/group_cipher.js +5 -5
  8. package/lib/Signal/Group/keyhelper.js +4 -4
  9. package/lib/Signal/Group/sender-chain-key.js +2 -2
  10. package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
  11. package/lib/Signal/Group/sender-key-message.js +3 -3
  12. package/lib/Signal/Group/sender-key-record.js +1 -1
  13. package/lib/Signal/Group/sender-message-key.js +5 -5
  14. package/lib/Signal/libsignal.js +39 -59
  15. package/lib/Signal/lid-mapping.js +28 -10
  16. package/lib/Socket/aigroups.js +5 -5
  17. package/lib/Socket/business.js +3 -11
  18. package/lib/Socket/chats.js +668 -319
  19. package/lib/Socket/communities.js +85 -89
  20. package/lib/Socket/graphql.js +435 -228
  21. package/lib/Socket/groups.js +132 -211
  22. package/lib/Socket/index.js +9 -7
  23. package/lib/Socket/interactive-handler.js +117 -60
  24. package/lib/Socket/interop.js +56 -175
  25. package/lib/Socket/managed-account.js +79 -48
  26. package/lib/Socket/messages-recv.js +898 -340
  27. package/lib/Socket/messages-send.js +462 -160
  28. package/lib/Socket/mex.js +40 -53
  29. package/lib/Socket/newsletter.js +291 -291
  30. package/lib/Socket/privacy.js +77 -265
  31. package/lib/Socket/registration.js +164 -157
  32. package/lib/Socket/socket.js +181 -199
  33. package/lib/Socket/username.js +144 -227
  34. package/lib/Store/make-cache-manager-store.js +2 -2
  35. package/lib/Store/make-in-memory-store.js +25 -141
  36. package/lib/Types/Auth.js +3 -3
  37. package/lib/Types/Label.js +1 -1
  38. package/lib/Types/LabelAssociation.js +1 -1
  39. package/lib/Types/Newsletter.js +96 -65
  40. package/lib/Types/State.js +4 -4
  41. package/lib/Types/index.js +1 -1
  42. package/lib/Utils/auth-utils.js +52 -57
  43. package/lib/Utils/browser-utils.js +1 -1
  44. package/lib/Utils/business.js +2 -6
  45. package/lib/Utils/chat-utils.js +102 -38
  46. package/lib/Utils/crypto.js +54 -84
  47. package/lib/Utils/decode-wa-message.js +316 -83
  48. package/lib/Utils/event-buffer.js +37 -61
  49. package/lib/Utils/generics.js +157 -103
  50. package/lib/Utils/group-history.js +3 -12
  51. package/lib/Utils/history.js +15 -15
  52. package/lib/Utils/index.js +1 -5
  53. package/lib/Utils/link-preview.js +3 -8
  54. package/lib/Utils/lt-hash.js +2 -35
  55. package/lib/Utils/make-mutex.js +1 -1
  56. package/lib/Utils/message-inspect.js +393 -0
  57. package/lib/Utils/message-retry-manager.js +27 -92
  58. package/lib/Utils/messages-media.js +159 -130
  59. package/lib/Utils/messages.js +144 -566
  60. package/lib/Utils/meta-ai-msmsg.js +62 -202
  61. package/lib/Utils/noise-handler.js +19 -21
  62. package/lib/Utils/offline-node-processor.js +3 -8
  63. package/lib/Utils/pre-key-manager.js +13 -23
  64. package/lib/Utils/process-message.js +197 -106
  65. package/lib/Utils/reporting-utils.js +2 -2
  66. package/lib/Utils/signal.js +28 -63
  67. package/lib/Utils/stanza-ack.js +39 -12
  68. package/lib/Utils/sync-action-utils.js +4 -7
  69. package/lib/Utils/tc-token-utils.js +20 -25
  70. package/lib/Utils/use-multi-file-auth-state.js +30 -14
  71. package/lib/Utils/validate-connection.js +59 -19
  72. package/lib/WABinary/decode.js +50 -16
  73. package/lib/WABinary/encode.js +54 -224
  74. package/lib/WABinary/generic-utils.js +7 -97
  75. package/lib/WABinary/jid-utils.js +27 -14
  76. package/lib/WAM/encode.js +7 -7
  77. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +58 -1
  78. package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -1
  79. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +13 -5
  80. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -4
  81. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +20 -7
  82. package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +865 -0
  83. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
  84. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
  85. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -2
  86. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
  87. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +2 -1
  88. package/lib/WAUSync/Protocols/index.js +1 -0
  89. package/lib/WAUSync/USyncBackoff.js +26 -0
  90. package/lib/WAUSync/USyncQuery.js +77 -6
  91. package/lib/WAUSync/USyncUser.js +16 -8
  92. package/lib/WAUSync/index.js +1 -0
  93. package/lib/antiban.js +608 -854
  94. package/lib/index.js +3 -3
  95. package/package.json +16 -19
  96. package/lib/Socket/luxu.js +0 -387
  97. package/lib/Socket/text-router.js +0 -83
  98. package/lib/Store/keyed-db.js +0 -108
  99. package/lib/Types/Mex.js +0 -112
  100. package/lib/Utils/command-loader.d.ts +0 -31
  101. package/lib/Utils/command-loader.js +0 -100
  102. package/lib/Utils/companion-reg-client-utils.js +0 -42
  103. package/lib/Utils/curve25519-js.js +0 -275
  104. package/lib/Utils/native-bridge.js +0 -82
  105. package/lib/Utils/session-pool.d.ts +0 -16
  106. package/lib/Utils/session-pool.js +0 -94
  107. package/lib/Utils/sticker.d.ts +0 -17
  108. package/lib/Utils/sticker.js +0 -145
  109. package/lib/Utils/view-once-cache.d.ts +0 -9
  110. package/lib/Utils/view-once-cache.js +0 -79
@@ -59,9 +59,9 @@ const REAL_MSG_STUB_TYPES = new Set([
59
59
  Types_1.WAMessageStubType.CALL_MISSED_VOICE
60
60
  ])
61
61
  const REAL_MSG_REQ_ME_STUB_TYPES = new Set([Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD])
62
- /** Cleans a received message to further processing */
62
+
63
63
  const cleanMessage = (message, meId, meLid) => {
64
- // ensure remoteJid and participant doesn't have device or agent in it
64
+
65
65
  if ((0, WABinary_1.isHostedPnUser)(message.key.remoteJid) || (0, WABinary_1.isHostedLidUser)(message.key.remoteJid)) {
66
66
  message.key.remoteJid = (0, WABinary_1.jidEncode)(
67
67
  (0, WABinary_1.jidDecode)(message.key?.remoteJid)?.user,
@@ -82,7 +82,7 @@ const cleanMessage = (message, meId, meLid) => {
82
82
  message.key.participant = (0, WABinary_1.jidNormalizedUser)(message.key.participant)
83
83
  }
84
84
  const content = (0, messages_1.normalizeMessageContent)(message.message)
85
- // if the message has a reaction, ensure fromMe & remoteJid are from our perspective
85
+
86
86
  if (content?.reactionMessage) {
87
87
  normaliseKey(content.reactionMessage.key)
88
88
  }
@@ -90,47 +90,48 @@ const cleanMessage = (message, meId, meLid) => {
90
90
  normaliseKey(content.pollUpdateMessage.pollCreationMessageKey)
91
91
  }
92
92
  function normaliseKey(msgKey) {
93
- // if the reaction is from another user
94
- // we've to correctly map the key to this user's perspective
93
+
94
+
95
95
  if (!message.key.fromMe) {
96
- // if the sender believed the message being reacted to is not from them
97
- // we've to correct the key to be from them, or some other participant
96
+
97
+
98
98
  msgKey.fromMe = !msgKey.fromMe
99
99
  ? (0, WABinary_1.areJidsSameUser)(msgKey.participant || msgKey.remoteJid, meId) ||
100
100
  (0, WABinary_1.areJidsSameUser)(msgKey.participant || msgKey.remoteJid, meLid)
101
- : // if the message being reacted to, was from them
102
- // fromMe automatically becomes false
101
+ :
102
+
103
103
  false
104
- // set the remoteJid to being the same as the chat the message came from
105
- // TODO: investigate inconsistencies
104
+
105
+
106
106
  msgKey.remoteJid = message.key.remoteJid
107
- // set participant of the message
107
+
108
108
  msgKey.participant = msgKey.participant || message.key.participant
109
109
  }
110
110
  }
111
111
  }
112
112
  exports.cleanMessage = cleanMessage
113
- // TODO: target:audit AUDIT THIS FUNCTION AGAIN
114
113
  const isRealMessage = message => {
114
+
115
+
116
+
117
+ if (REAL_MSG_STUB_TYPES.has(message.messageStubType) || REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) {
118
+ return true
119
+ }
115
120
  const normalizedContent = (0, messages_1.normalizeMessageContent)(message.message)
116
121
  const hasSomeContent = !!(0, messages_1.getContentType)(normalizedContent)
117
122
  return (
118
- (!!normalizedContent ||
119
- REAL_MSG_STUB_TYPES.has(message.messageStubType) ||
120
- REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) &&
123
+ !!normalizedContent &&
121
124
  hasSomeContent &&
122
125
  !normalizedContent?.protocolMessage &&
123
126
  !normalizedContent?.reactionMessage &&
124
- !normalizedContent?.pollUpdateMessage
127
+ !normalizedContent?.pollUpdateMessage &&
128
+ !normalizedContent?.secretEncryptedMessage
125
129
  )
126
130
  }
127
131
  exports.isRealMessage = isRealMessage
128
132
  const shouldIncrementChatUnread = message => !message.key.fromMe && !message.messageStubType
129
133
  exports.shouldIncrementChatUnread = shouldIncrementChatUnread
130
- /**
131
- * Get the ID of the chat from the given key.
132
- * Typically -- that'll be the remoteJid, but for broadcasts, it'll be the participant
133
- */
134
+
134
135
  const getChatId = ({ remoteJid, participant, fromMe }) => {
135
136
  if ((0, WABinary_1.isJidBroadcast)(remoteJid) && !(0, WABinary_1.isJidStatusBroadcast)(remoteJid) && !fromMe) {
136
137
  return participant
@@ -138,12 +139,7 @@ const getChatId = ({ remoteJid, participant, fromMe }) => {
138
139
  return remoteJid
139
140
  }
140
141
  exports.getChatId = getChatId
141
- /**
142
- * Decrypt a poll vote
143
- * @param vote encrypted vote
144
- * @param ctx additional info about the poll required for decryption
145
- * @returns list of SHA256 options
146
- */
142
+
147
143
  function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pollEncKey, voterJid }) {
148
144
  const sign = Buffer.concat([
149
145
  toBinary(pollMsgId),
@@ -161,12 +157,7 @@ function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pol
161
157
  return Buffer.from(txt)
162
158
  }
163
159
  }
164
- /**
165
- * Decrypt an event response
166
- * @param response encrypted event response
167
- * @param ctx additional info about the event required for decryption
168
- * @returns event response message
169
- */
160
+
170
161
  function decryptEventResponse({ encPayload, encIv }, { eventCreatorJid, eventMsgId, eventEncKey, responderJid }) {
171
162
  const sign = Buffer.concat([
172
163
  toBinary(eventMsgId),
@@ -184,6 +175,108 @@ function decryptEventResponse({ encPayload, encIv }, { eventCreatorJid, eventMsg
184
175
  return Buffer.from(txt)
185
176
  }
186
177
  }
178
+
179
+ function decryptMessageEdit({ encPayload, encIv }, { origMsgId, origMsgSenderJid, editorJid, msgEncKey }) {
180
+ const sign = Buffer.concat([
181
+ toBinary(origMsgId),
182
+ toBinary(origMsgSenderJid),
183
+ toBinary(editorJid),
184
+ toBinary('Message Edit'),
185
+ new Uint8Array([1])
186
+ ])
187
+ const key0 = (0, crypto_1.hmacSign)(msgEncKey, new Uint8Array(32), 'sha256')
188
+ const decKey = (0, crypto_1.hmacSign)(sign, key0, 'sha256')
189
+
190
+ const decrypted = (0, crypto_1.aesDecryptGCM)(encPayload, decKey, encIv, new Uint8Array(0))
191
+ return index_js_1.proto.Message.decode(decrypted)
192
+ function toBinary(txt) {
193
+ return Buffer.from(txt)
194
+ }
195
+ }
196
+ exports.decryptMessageEdit = decryptMessageEdit
197
+
198
+ const unwrapSecretEncryptedMessage = async (message, { creds, getMessage, logger }) => {
199
+ const content = (0, messages_1.normalizeMessageContent)(message.message)
200
+ const secretEnc = content?.secretEncryptedMessage
201
+ if (
202
+ !secretEnc?.encPayload ||
203
+ !secretEnc.encIv ||
204
+ secretEnc.secretEncType !== index_js_1.proto.Message.SecretEncryptedMessage.SecretEncType.MESSAGE_EDIT
205
+ ) {
206
+ return
207
+ }
208
+ const targetKey = secretEnc.targetMessageKey
209
+ if (!targetKey?.id) {
210
+ return
211
+ }
212
+ try {
213
+
214
+
215
+ const origMsg = await getMessage({
216
+ ...targetKey,
217
+ remoteJid: message.key.remoteJid,
218
+ fromMe: message.key.fromMe,
219
+ participant: message.key.participant
220
+ })
221
+ let msgEncKey = origMsg?.messageContextInfo?.messageSecret
222
+ if (typeof msgEncKey === 'string') {
223
+
224
+ msgEncKey = Buffer.from(msgEncKey, 'base64')
225
+ }
226
+ if (!msgEncKey?.length) {
227
+ logger?.warn({ targetKey }, 'message edit: missing messageSecret for decryption')
228
+ return
229
+ }
230
+
231
+
232
+ const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(creds.me.id)
233
+ const candidates = [
234
+ ...(message.key.fromMe
235
+ ? [meIdNormalised, creds.me?.lid]
236
+ : [message.key.participant || message.key.remoteJid, message.key.participantAlt || message.key.remoteJidAlt]),
237
+ targetKey.remoteJid
238
+ ]
239
+ .filter(jid => !!jid)
240
+ .map(jid => (0, WABinary_1.jidNormalizedUser)(jid))
241
+ .filter((jid, i, arr) => arr.indexOf(jid) === i)
242
+ let decoded
243
+ let lastError
244
+ for (const authorJid of candidates) {
245
+ try {
246
+ decoded = decryptMessageEdit(secretEnc, {
247
+ origMsgId: targetKey.id,
248
+ origMsgSenderJid: authorJid,
249
+ editorJid: authorJid,
250
+ msgEncKey
251
+ })
252
+ break
253
+ } catch (err) {
254
+ lastError = err
255
+ }
256
+ }
257
+ if (!decoded) {
258
+ throw lastError
259
+ }
260
+ if (!decoded.protocolMessage) {
261
+
262
+ decoded = index_js_1.proto.Message.fromObject({
263
+ protocolMessage: {
264
+ key: targetKey,
265
+ type: index_js_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
266
+ editedMessage: decoded
267
+ }
268
+ })
269
+ }
270
+ if (!decoded.messageContextInfo && content?.messageContextInfo) {
271
+ decoded.messageContextInfo = content.messageContextInfo
272
+ }
273
+ message.message = decoded
274
+ logger?.debug({ targetKey }, 'decrypted secretEncryptedMessage edit')
275
+ } catch (err) {
276
+ logger?.warn({ err, targetKey }, 'failed to decrypt secretEncryptedMessage edit')
277
+ }
278
+ }
279
+ exports.unwrapSecretEncryptedMessage = unwrapSecretEncryptedMessage
187
280
  const processMessage = async (
188
281
  message,
189
282
  {
@@ -205,7 +298,7 @@ const processMessage = async (
205
298
  if (isRealMsg) {
206
299
  chat.messages = [{ message }]
207
300
  chat.conversationTimestamp = (0, generics_1.toNumber)(message.messageTimestamp)
208
- // only increment unread count if not CIPHERTEXT and from another person
301
+
209
302
  if ((0, exports.shouldIncrementChatUnread)(message)) {
210
303
  chat.unreadCount = (chat.unreadCount || 0) + 1
211
304
  }
@@ -236,8 +329,8 @@ const processMessage = async (
236
329
  })
237
330
  }
238
331
  const content = (0, messages_1.normalizeMessageContent)(message.message)
239
- // unarchive chat if it's a real message, or someone reacted to our message
240
- // and we've the unarchive chats setting on
332
+
333
+
241
334
  if ((isRealMsg || content?.reactionMessage?.key?.fromMe) && accountSettings?.unarchiveChats) {
242
335
  chat.archived = false
243
336
  chat.readOnly = false
@@ -259,7 +352,7 @@ const processMessage = async (
259
352
  'got history notification'
260
353
  )
261
354
  if (process) {
262
- // TODO: investigate
355
+
263
356
  if (histNotification.syncType !== index_js_1.proto.HistorySync.HistorySyncType.ON_DEMAND) {
264
357
  ev.emit('creds.update', {
265
358
  processedHistoryMessages: [
@@ -325,31 +418,31 @@ const processMessage = async (
325
418
  case index_js_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
326
419
  const response = protocolMsg.peerDataOperationRequestResponseMessage
327
420
  if (response) {
328
- // TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
421
+
329
422
  const peerDataOperationResult = response.peerDataOperationResult || []
330
423
  for (const result of peerDataOperationResult) {
331
424
  const retryResponse = result?.placeholderMessageResendResponse
332
- //eslint-disable-next-line max-depth
425
+
333
426
  if (!retryResponse?.webMessageInfoBytes) {
334
427
  continue
335
428
  }
336
- //eslint-disable-next-line max-depth
429
+
337
430
  try {
338
431
  const webMessageInfo = index_js_1.proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes)
339
432
  const msgId = webMessageInfo.key?.id
340
- // Retrieve cached original message data (preserves LID details,
341
- // timestamps, etc. that the phone may omit in its PDO response)
433
+
434
+
342
435
  const cachedData = msgId ? await placeholderResendCache?.get(msgId) : undefined
343
- //eslint-disable-next-line max-depth
436
+
344
437
  if (msgId) {
345
438
  await placeholderResendCache?.del(msgId)
346
439
  }
347
440
  let finalMsg
348
- //eslint-disable-next-line max-depth
441
+
349
442
  if (cachedData && typeof cachedData === 'object') {
350
- // Apply decoded message content onto cached metadata (preserves LID etc.)
443
+
351
444
  cachedData.message = webMessageInfo.message
352
- //eslint-disable-next-line max-depth
445
+
353
446
  if (webMessageInfo.messageTimestamp) {
354
447
  cachedData.messageTimestamp = webMessageInfo.messageTimestamp
355
448
  }
@@ -372,7 +465,7 @@ const processMessage = async (
372
465
  case index_js_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT:
373
466
  ev.emit('messages.update', [
374
467
  {
375
- // flip the sender / fromMe properties because they're in the perspective of the sender
468
+
376
469
  key: { ...message.key, id: protocolMsg.key?.id },
377
470
  update: {
378
471
  message: {
@@ -389,10 +482,12 @@ const processMessage = async (
389
482
  break
390
483
  case index_js_1.proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE:
391
484
  const labelAssociationMsg = protocolMsg.memberLabel
392
- if (labelAssociationMsg?.label) {
485
+ if (labelAssociationMsg) {
486
+
487
+
393
488
  ev.emit('group.member-tag.update', {
394
489
  groupId: chat.id,
395
- label: labelAssociationMsg.label,
490
+ label: labelAssociationMsg.label || '',
396
491
  participant: message.key.participant,
397
492
  participantAlt: message.key.participantAlt,
398
493
  messageTimestamp: Number(message.messageTimestamp)
@@ -616,12 +711,12 @@ const processMessage = async (
616
711
  } else if (content?.encEventResponseMessage) {
617
712
  const encEventResponse = content.encEventResponseMessage
618
713
  const creationMsgKey = encEventResponse.eventCreationMessageKey
619
- // we need to fetch the event creation message to get the event enc key
714
+
620
715
  const eventMsg = await getMessage(creationMsgKey)
621
716
  if (eventMsg) {
622
717
  try {
623
718
  const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(meId)
624
- // all jids need to be PN
719
+
625
720
  const eventCreatorKey = creationMsgKey.participant || creationMsgKey.remoteJid
626
721
  const eventCreatorPn = (0, WABinary_1.isLidUser)(eventCreatorKey)
627
722
  ? await signalRepository.lidMapping.getPNForLID(eventCreatorKey)
@@ -663,7 +758,7 @@ const processMessage = async (
663
758
  }
664
759
  } else if (message.messageStubType) {
665
760
  const jid = message.key?.remoteJid
666
- //let actor = whatsappID (message.participant)
761
+
667
762
  let participants
668
763
  const emitParticipantsUpdate = action =>
669
764
  ev.emit('group-participants.update', {
@@ -679,7 +774,7 @@ const processMessage = async (
679
774
  {
680
775
  id: jid,
681
776
  ...update,
682
- author: message.key.participant ?? undefined,
777
+ author: message.key.participant,
683
778
  authorPn: message.key.participantAlt,
684
779
  authorUsername: message.key.participantUsername
685
780
  }
@@ -698,7 +793,7 @@ const processMessage = async (
698
793
  })
699
794
  }
700
795
  const participantsIncludesMe = () =>
701
- participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid.phoneNumber)) // ADD SUPPORT FOR LID
796
+ participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid.phoneNumber))
702
797
  switch (message.messageStubType) {
703
798
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
704
799
  participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
@@ -708,7 +803,7 @@ const processMessage = async (
708
803
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
709
804
  participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
710
805
  emitParticipantsUpdate('remove')
711
- // mark the chat read only if you left the group
806
+
712
807
  if (participantsIncludesMe()) {
713
808
  chat.readOnly = true
714
809
  }
@@ -760,7 +855,7 @@ const processMessage = async (
760
855
  const approvalMode = message.messageStubParameters?.[0]
761
856
  emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' })
762
857
  break
763
- case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: // TODO: Add other events
858
+ case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD:
764
859
  const participant = JSON.parse(message.messageStubParameters?.[0])
765
860
  const action = message.messageStubParameters?.[1]
766
861
  const method = message.messageStubParameters?.[2]
@@ -850,7 +945,7 @@ const processMessage = async (
850
945
  ev.emit('chats.update', [{ id: jid, psa: { urlParams: message.messageStubParameters } }])
851
946
  break
852
947
  case Types_1.WAMessageStubType.CHAT_POLL_CREATION_MESSAGE:
853
- // poll was created, no special action needed beyond message processing
948
+
854
949
  break
855
950
  case Types_1.WAMessageStubType.BIZ_CHAT_ASSIGNMENT:
856
951
  ev.emit('chats.update', [
@@ -992,55 +1087,51 @@ const processMessage = async (
992
1087
  emitGroupUpdate({ hidden: true })
993
1088
  break
994
1089
  }
995
- } /* else if(content?.pollUpdateMessage) {
996
- const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey!
997
- // we need to fetch the poll creation message to get the poll enc key
998
- // TODO: make standalone, remove getMessage reference
999
- // TODO: Remove entirely
1000
- const pollMsg = await getMessage(creationMsgKey)
1001
- if(pollMsg) {
1002
- const meIdNormalised = jidNormalizedUser(meId)
1003
- const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
1004
- const voterJid = getKeyAuthor(message.key, meIdNormalised)
1005
- const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
1006
-
1007
- try {
1008
- const voteMsg = decryptPollVote(
1009
- content.pollUpdateMessage.vote!,
1010
- {
1011
- pollEncKey,
1012
- pollCreatorJid,
1013
- pollMsgId: creationMsgKey.id!,
1014
- voterJid,
1015
- }
1016
- )
1017
- ev.emit('messages.update', [
1018
- {
1019
- key: creationMsgKey,
1020
- update: {
1021
- pollUpdates: [
1022
- {
1023
- pollUpdateMessageKey: message.key,
1024
- vote: voteMsg,
1025
- senderTimestampMs: (content.pollUpdateMessage.senderTimestampMs! as Long).toNumber(),
1026
- }
1027
- ]
1028
- }
1029
- }
1030
- ])
1031
- } catch(err) {
1032
- logger?.warn(
1033
- { err, creationMsgKey },
1034
- 'failed to decrypt poll vote'
1035
- )
1036
- }
1037
- } else {
1038
- logger?.warn(
1039
- { creationMsgKey },
1040
- 'poll creation message not found, cannot decrypt update'
1041
- )
1042
- }
1043
- } */
1090
+ } else if (content?.pollUpdateMessage) {
1091
+ const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey
1092
+ const pollMsg = await getMessage(creationMsgKey)
1093
+ if (pollMsg) {
1094
+
1095
+ const inner = pollMsg.viewOnceMessage?.message || pollMsg.botInvokeMessage?.message || pollMsg
1096
+ const pollEncKey = inner.messageContextInfo?.messageSecret || pollMsg.messageContextInfo?.messageSecret || null
1097
+ if (!pollEncKey) {
1098
+ logger?.warn({ creationMsgKey }, 'poll: messageSecret missing, cannot decrypt vote')
1099
+ } else {
1100
+
1101
+ const rawLid = creds.me?.lid
1102
+ const meLidNorm = rawLid ? `${rawLid.split(':')[0]}@lid` : ''
1103
+ const pollCreatorJid = meLidNorm || (0, WABinary_1.jidNormalizedUser)(meId)
1104
+
1105
+ const voterJid = message.key.fromMe ? pollCreatorJid : message.key.participant || message.key.remoteJid
1106
+ try {
1107
+ const voteMsg = decryptPollVote(content.pollUpdateMessage.vote, {
1108
+ pollEncKey,
1109
+ pollCreatorJid,
1110
+ pollMsgId: creationMsgKey.id,
1111
+ voterJid
1112
+ })
1113
+ ev.emit('messages.update', [
1114
+ {
1115
+ key: creationMsgKey,
1116
+ update: {
1117
+ pollUpdates: [
1118
+ {
1119
+ pollUpdateMessageKey: message.key,
1120
+ vote: voteMsg,
1121
+ senderTimestampMs: (0, generics_1.toNumber)(content.pollUpdateMessage.senderTimestampMs)
1122
+ }
1123
+ ]
1124
+ }
1125
+ }
1126
+ ])
1127
+ } catch (err) {
1128
+ logger?.warn({ err, creationMsgKey, pollCreatorJid, voterJid }, 'failed to decrypt poll vote')
1129
+ }
1130
+ }
1131
+ } else {
1132
+ logger?.warn({ creationMsgKey }, 'poll: creation message not found, cannot decrypt vote')
1133
+ }
1134
+ }
1044
1135
  if (Object.keys(chat).length > 1) {
1045
1136
  ev.emit('chats.update', [chat])
1046
1137
  }
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.getMessageReportingToken = exports.shouldIncludeReportingToken = void 0
4
- const Crypto_1 = require('./crypto')
4
+ const rb = require('whatsapp-rust-bridge')
5
5
  const crypto_2 = require('./crypto')
6
6
  const reportingFields = [
7
7
  { f: 1 },
@@ -246,7 +246,7 @@ const getMessageReportingToken = async (msgProtobuf, message, key) => {
246
246
  if (!content || content.length === 0) {
247
247
  return null
248
248
  }
249
- const reportingToken = Buffer.from(Crypto_1.hmacSign(content, reportingSecret)).subarray(0, 16)
249
+ const reportingToken = Buffer.from(rb.hmacSign(content, reportingSecret)).subarray(0, 16)
250
250
  return {
251
251
  tag: 'reporting',
252
252
  attrs: {},
@@ -4,7 +4,6 @@ exports.getNextPreKeysNode =
4
4
  exports.getNextPreKeys =
5
5
  exports.extractDeviceJids =
6
6
  exports.parseAndInjectE2ESessions =
7
- exports.extractE2ESessionFromRetryReceipt =
8
7
  exports.xmppPreKey =
9
8
  exports.xmppSignedPreKey =
10
9
  exports.generateOrGetPreKeys =
@@ -54,9 +53,11 @@ const generateOrGetPreKeys = (creds, range) => {
54
53
  }
55
54
  }
56
55
  exports.generateOrGetPreKeys = generateOrGetPreKeys
57
- const xmppSignedPreKey = key => ({
56
+
57
+
58
+ const xmppSignedPreKey = (key, cipherSuite) => ({
58
59
  tag: 'skey',
59
- attrs: {},
60
+ attrs: cipherSuite !== undefined ? { key_cipher_suite: cipherSuite } : {},
60
61
  content: [
61
62
  { tag: 'id', attrs: {}, content: (0, generics_1.encodeBigEndian)(key.keyId, 3) },
62
63
  { tag: 'value', attrs: {}, content: key.keyPair.public },
@@ -64,72 +65,36 @@ const xmppSignedPreKey = key => ({
64
65
  ]
65
66
  })
66
67
  exports.xmppSignedPreKey = xmppSignedPreKey
67
- const xmppPreKey = (pair, id) => ({
68
+ const xmppPreKey = (pair, id, cipherSuite) => ({
68
69
  tag: 'key',
69
- attrs: {},
70
+ attrs: cipherSuite !== undefined ? { key_cipher_suite: cipherSuite } : {},
70
71
  content: [
71
72
  { tag: 'id', attrs: {}, content: (0, generics_1.encodeBigEndian)(id, 3) },
72
73
  { tag: 'value', attrs: {}, content: pair.public }
73
74
  ]
74
75
  })
75
76
  exports.xmppPreKey = xmppPreKey
76
- const isValidUInt = n => typeof n === 'number' && Number.isInteger(n)
77
- const extractE2ESessionFromRetryReceipt = receipt => {
78
- const keysNode = (0, WABinary_1.getBinaryNodeChild)(receipt, 'keys')
79
- if (!keysNode) return null
80
- const typeBuf = (0, WABinary_1.getBinaryNodeChildBuffer)(keysNode, 'type')
81
- if (!typeBuf || typeBuf.length !== 1 || typeBuf[0] !== Defaults_1.KEY_BUNDLE_TYPE[0]) return null
82
- const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(keysNode, 'identity')
83
- const skey = (0, WABinary_1.getBinaryNodeChild)(keysNode, 'skey')
84
- if (!identity || identity.length !== 32 || !skey) return null
85
- const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(receipt, 'registration', 4)
86
- if (!isValidUInt(registrationId)) return null
87
- const signedPubKey = (0, WABinary_1.getBinaryNodeChildBuffer)(skey, 'value')
88
- const signedSig = (0, WABinary_1.getBinaryNodeChildBuffer)(skey, 'signature')
89
- const signedKeyId = (0, WABinary_1.getBinaryNodeChildUInt)(skey, 'id', 3)
90
- if (!signedPubKey || signedPubKey.length !== 32 || !signedSig || !isValidUInt(signedKeyId)) {
91
- return null
92
- }
93
- const preKeyNode = (0, WABinary_1.getBinaryNodeChild)(keysNode, 'key')
94
- let preKey
95
- if (preKeyNode) {
96
- const preKeyPub = (0, WABinary_1.getBinaryNodeChildBuffer)(preKeyNode, 'value')
97
- const preKeyId = (0, WABinary_1.getBinaryNodeChildUInt)(preKeyNode, 'id', 3)
98
- if (!preKeyPub || preKeyPub.length !== 32 || !isValidUInt(preKeyId)) {
99
- return null
77
+ const parseAndInjectE2ESessions = async (node, repository) => {
78
+ const extractKey = key => {
79
+ if (!key) return undefined
80
+ const cipherSuite = key.attrs?.key_cipher_suite
81
+ return {
82
+ keyId: (0, WABinary_1.getBinaryNodeChildUInt)(key, 'id', 3),
83
+ publicKey: (0, crypto_1.generateSignalPubKey)((0, WABinary_1.getBinaryNodeChildBuffer)(key, 'value')),
84
+ signature: (0, WABinary_1.getBinaryNodeChildBuffer)(key, 'signature'),
85
+
86
+ ...(cipherSuite !== undefined ? { cipherSuite } : {})
100
87
  }
101
- preKey = { keyId: preKeyId, publicKey: (0, crypto_1.generateSignalPubKey)(preKeyPub) }
102
- }
103
- return {
104
- registrationId,
105
- identityKey: (0, crypto_1.generateSignalPubKey)(identity),
106
- signedPreKey: {
107
- keyId: signedKeyId,
108
- publicKey: (0, crypto_1.generateSignalPubKey)(signedPubKey),
109
- signature: signedSig
110
- },
111
- preKey
112
88
  }
113
- }
114
- exports.extractE2ESessionFromRetryReceipt = extractE2ESessionFromRetryReceipt
115
- const parseAndInjectE2ESessions = async (node, repository) => {
116
- const extractKey = key =>
117
- key
118
- ? {
119
- keyId: (0, WABinary_1.getBinaryNodeChildUInt)(key, 'id', 3),
120
- publicKey: (0, crypto_1.generateSignalPubKey)((0, WABinary_1.getBinaryNodeChildBuffer)(key, 'value')),
121
- signature: (0, WABinary_1.getBinaryNodeChildBuffer)(key, 'signature')
122
- }
123
- : undefined
124
89
  const nodes = (0, WABinary_1.getBinaryNodeChildren)((0, WABinary_1.getBinaryNodeChild)(node, 'list'), 'user')
125
90
  for (const node of nodes) {
126
91
  ;(0, WABinary_1.assertNodeErrorFree)(node)
127
92
  }
128
- // Most of the work in repository.injectE2ESession is CPU intensive, not IO
129
- // So Promise.all doesn't really help here,
130
- // but blocks even loop if we're using it inside keys.transaction, and it makes it "sync" actually
131
- // This way we chunk it in smaller parts and between those parts we can yield to the event loop
132
- // It's rare case when you need to E2E sessions for so many users, but it's possible
93
+
94
+
95
+
96
+
97
+
133
98
  const chunkSize = 100
134
99
  const chunks = chunk(nodes, chunkSize)
135
100
  for (const nodesChunk of chunks) {
@@ -164,9 +129,9 @@ const extractDeviceJids = (result, myJid, myLid, excludeZeroDevices) => {
164
129
  if (!Array.isArray(deviceList)) continue
165
130
  for (const { id: device, keyIndex, isHosted } of deviceList) {
166
131
  if (
167
- (!excludeZeroDevices || device !== 0) && // if zero devices are not-excluded, or device is non zero
168
- ((myUser !== user && myLid !== user) || myDevice !== device) && // either different user or if me user, not this device
169
- (device === 0 || !!keyIndex) // ensure that "key-index" is specified for "non-zero" devices, produces a bad req otherwise
132
+ (!excludeZeroDevices || device !== 0) &&
133
+ ((myUser !== user && myLid !== user) || myDevice !== device) &&
134
+ (device === 0 || !!keyIndex)
170
135
  ) {
171
136
  if (isHosted) {
172
137
  domainType =
@@ -186,10 +151,7 @@ const extractDeviceJids = (result, myJid, myLid, excludeZeroDevices) => {
186
151
  return extracted
187
152
  }
188
153
  exports.extractDeviceJids = extractDeviceJids
189
- /**
190
- * get the next N keys for upload or processing
191
- * @param count number of pre-keys to get or generate
192
- */
154
+
193
155
  const getNextPreKeys = async ({ creds, keys }, count) => {
194
156
  const { newPreKeys, lastPreKeyId, preKeysRange } = (0, exports.generateOrGetPreKeys)(creds, count)
195
157
  const update = {
@@ -215,6 +177,9 @@ const getNextPreKeysNode = async (state, count) => {
215
177
  { tag: 'registration', attrs: {}, content: (0, generics_1.encodeBigEndian)(creds.registrationId) },
216
178
  { tag: 'type', attrs: {}, content: Defaults_1.KEY_BUNDLE_TYPE },
217
179
  { tag: 'identity', attrs: {}, content: creds.signedIdentityKey.public },
180
+
181
+
182
+
218
183
  { tag: 'list', attrs: {}, content: Object.keys(preKeys).map(k => (0, exports.xmppPreKey)(preKeys[+k], +k)) },
219
184
  (0, exports.xmppSignedPreKey)(creds.signedPreKey)
220
185
  ]