@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
@@ -11,16 +11,12 @@ exports.decryptMessageNode =
11
11
  void 0
12
12
  exports.decodeMessageNode = decodeMessageNode
13
13
  const boom_1 = require('@hapi/boom')
14
- const index_js_1 = require('../../WAProto/index.js')
15
14
  const WAProto_1 = require('../../WAProto/index.js')
16
15
  const WABinary_1 = require('../WABinary')
17
16
  const generics_1 = require('./generics')
18
17
  const meta_ai_msmsg_1 = require('./meta-ai-msmsg')
19
18
  const messages_1 = require('./messages')
20
19
  const MAX_SECRETS_PER_CHAT = 20
21
- // Module-level map: outgoing @bot message ID → messageSecret
22
- // Populated when we receive the outgoing pkmsg/msg to @bot (which contains messageContextInfo.messageSecret)
23
- // Consumed when the msmsg response from @bot arrives and needs decryption
24
20
  const botMessageSecrets = new Map()
25
21
  const botRecentSecretsByChat = new Map()
26
22
  const pushRecentChatSecret = (chatJid, id, secretBuf) => {
@@ -57,7 +53,7 @@ const getDecryptionJid = async (sender, repository) => {
57
53
  (0, WABinary_1.isHostedLidUser)(sender) ||
58
54
  (0, WABinary_1.isInteropUser)(sender)
59
55
  ) {
60
- // LID and interop JIDs are session keys themselves — no PN mapping lookup needed
56
+
61
57
  return sender
62
58
  }
63
59
  const mapped = await repository.lidMapping.getLIDForPN(sender)
@@ -65,12 +61,11 @@ const getDecryptionJid = async (sender, repository) => {
65
61
  }
66
62
  exports.getDecryptionJid = getDecryptionJid
67
63
  const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
68
- // TODO: Handle hosted IDs
69
64
  const { senderAlt } = (0, exports.extractAddressingContext)(stanza)
70
65
  if (
71
66
  senderAlt &&
72
- (0, WABinary_1.isLidUser)(senderAlt) &&
73
- (0, WABinary_1.isPnUser)(sender) &&
67
+ ((0, WABinary_1.isLidUser)(senderAlt) || (0, WABinary_1.isHostedLidUser)(senderAlt)) &&
68
+ ((0, WABinary_1.isPnUser)(sender) || (0, WABinary_1.isHostedPnUser)(sender)) &&
74
69
  decryptionJid === sender
75
70
  ) {
76
71
  try {
@@ -84,17 +79,14 @@ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJi
84
79
  }
85
80
  exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node'
86
81
  exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled'
87
- /**
88
- * Server-side error codes returned in ack stanzas (server → client).
89
- * Distinct from the client-side NackReason enum.
90
- */
82
+
91
83
  exports.SERVER_ERROR_CODES = {
92
- /** 1:1 message missing privacy token (tctoken) */
84
+
93
85
  MissingTcToken: '463',
94
- /** Stanza validation failure (SMAX_INVALID) — likely stale device session */
86
+
95
87
  SmaxInvalid: '479'
96
88
  }
97
- // Retry configuration for failed decryption
89
+
98
90
  exports.DECRYPTION_RETRY_CONFIG = {
99
91
  maxRetries: 3,
100
92
  baseDelayMs: 100,
@@ -121,19 +113,19 @@ const extractAddressingContext = stanza => {
121
113
  const sender = stanza.attrs.participant || stanza.attrs.from
122
114
  const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
123
115
  if (addressingMode === 'lid') {
124
- // Message is LID-addressed: sender is LID, extract corresponding PN
125
- // without device data
116
+
117
+
126
118
  senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
127
119
  recipientAlt = stanza.attrs.recipient_pn
128
- // with device data
129
- //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
120
+
121
+
130
122
  } else {
131
- // Message is PN-addressed: sender is PN, extract corresponding LID
132
- // without device data
123
+
124
+
133
125
  senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
134
126
  recipientAlt = stanza.attrs.recipient_lid
135
- //with device data
136
- //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
127
+
128
+
137
129
  }
138
130
  return {
139
131
  addressingMode,
@@ -142,15 +134,50 @@ const extractAddressingContext = stanza => {
142
134
  }
143
135
  }
144
136
  exports.extractAddressingContext = extractAddressingContext
145
- /**
146
- * Decode the received node as a message.
147
- * @note this will only parse the message, not decrypt it
148
- */
137
+
149
138
  function decodeMessageNode(stanza, meId, meLid) {
139
+ let nodey = []
150
140
  let msgType
151
141
  let chatId
152
142
  let author
153
143
  let fromMe = false
144
+ for (const { tag, attrs, content } of stanza.content) {
145
+ const clean = v => {
146
+ if (Array.isArray(v)) return v.map(clean);
147
+
148
+ if (v && typeof v === "object") {
149
+ const keys = Object.keys(v);
150
+
151
+ if (
152
+ keys.length &&
153
+ keys.every(k => /^\d+$/.test(k))
154
+ ) {
155
+ return "[bytes]";
156
+ }
157
+
158
+ if (
159
+ v.type === "Buffer" &&
160
+ Array.isArray(v.data)
161
+ ) {
162
+ return "[bytes]";
163
+ }
164
+
165
+ return Object.fromEntries(
166
+ Object.entries(v).map(([k, val]) => [k, clean(val)])
167
+ );
168
+ }
169
+
170
+ return v;
171
+ }
172
+ if (tag !== "plaintext" && tag !== "enc") {
173
+ nodey.push(clean({
174
+ tag: tag,
175
+ attrs: attrs,
176
+ content: content
177
+ }))
178
+ }
179
+ }
180
+
154
181
  const msgId = stanza.attrs.id
155
182
  const from = stanza.attrs.from
156
183
  const participant = stanza.attrs.participant
@@ -209,9 +236,9 @@ function decodeMessageNode(stanza, meId, meLid) {
209
236
  msgType = 'newsletter'
210
237
  chatId = from
211
238
  author = from
212
- // if (isMe(from) || isMeLid(from)) {
213
- // fromMe = true
214
- // }
239
+
240
+
241
+
215
242
 
216
243
  fromMe = (0, WABinary_1.isJidNewsletter)(from)
217
244
  ? !!stanza.attrs?.is_sender
@@ -219,8 +246,8 @@ function decodeMessageNode(stanza, meId, meLid) {
219
246
  ? (0, WABinary_1.areJidsSameUser)(from, meLid)
220
247
  : (0, WABinary_1.areJidsSameUser)(from, meId)
221
248
  } else if ((0, WABinary_1.isInteropUser)(from)) {
222
- // Message from an interop contact (Facebook Messenger / Instagram via WA bridge).
223
- // Treat as regular 1:1 chat — same Signal decrypt path as @s.whatsapp.net / @lid.
249
+
250
+
224
251
  msgType = 'chat'
225
252
  chatId = from
226
253
  author = from
@@ -228,7 +255,7 @@ function decodeMessageNode(stanza, meId, meLid) {
228
255
  } else {
229
256
  throw new boom_1.Boom('Unknown message type', { data: stanza })
230
257
  }
231
- // Interop stanzas (BirdyChat/Haiket) use display_name instead of notify
258
+
232
259
  const pushname = stanza?.attrs?.notify ?? stanza?.attrs?.display_name
233
260
  const key = {
234
261
  remoteJid: chatId,
@@ -252,10 +279,12 @@ function decodeMessageNode(stanza, meId, meLid) {
252
279
  broadcast: (0, WABinary_1.isJidBroadcast)(from),
253
280
  newsletter: (0, WABinary_1.isJidNewsletter)(from),
254
281
  StanzaAttrs: stanza.attrs,
255
- Owner: 'xazbails' // Non-WhatsApp attribute
282
+ nodes: nodey,
283
+ Owner: 'badzz88'
284
+
256
285
  }
257
286
  if (key.fromMe) {
258
- fullMessage.status = index_js_1.proto.WebMessageInfo.Status.SERVER_ACK
287
+ fullMessage.status = WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK
259
288
  }
260
289
  if (msgType === 'newsletter') {
261
290
  fullMessage.newsletter_server_id = +stanza.attrs?.server_id
@@ -298,7 +327,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
298
327
  metaTargetSenderJid = attrs.target_sender_jid
299
328
  }
300
329
  if (tag === 'bot' && attrs && 'edit_target_id' in attrs) {
301
- botEditTargetId = attrs.edit_target_id // Can be '' for 'first' type
330
+ botEditTargetId = attrs.edit_target_id
302
331
  }
303
332
  if (tag === 'bot' && (attrs === null || attrs === void 0 ? void 0 : attrs.edit)) {
304
333
  botType = attrs.edit
@@ -306,14 +335,27 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
306
335
  }
307
336
  }
308
337
 
309
- for (const { tag, attrs, content } of stanza.content) {
338
+
339
+
340
+
341
+ const _isGroupEnc = n => n.tag === 'enc' && (n.attrs?.type === 'skmsg' || n.attrs?.type === 'frskmsg')
342
+ const _stanzaContent = [
343
+ ...stanza.content.filter(n => !_isGroupEnc(n)),
344
+ ...stanza.content.filter(n => _isGroupEnc(n))
345
+ ]
346
+ for (const { tag, attrs, content } of _stanzaContent) {
310
347
  if (tag === 'verified_name' && content instanceof Uint8Array) {
311
- const cert = index_js_1.proto.VerifiedNameCertificate.decode(content)
312
- const details = index_js_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
348
+ const cert = WAProto_1.proto.VerifiedNameCertificate.decode(content)
349
+ const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
313
350
  fullMessage.verifiedBizName = details.verifiedName
351
+
352
+ if (attrs?.verified_level) {
353
+ fullMessage.verifiedNameLevel = attrs.verified_level
354
+ }
314
355
  }
315
356
  if (tag === 'unavailable' && attrs.type === 'view_once') {
316
- fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
357
+ fullMessage.key.isViewOnce = true
358
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.VIEWED_ONCE
317
359
  }
318
360
  if (attrs.count && tag === 'enc') {
319
361
  fullMessage.retryCount = Number(attrs.count)
@@ -328,12 +370,15 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
328
370
  let msgBuffer
329
371
  const decryptionJid = await (0, exports.getDecryptionJid)(author, repository)
330
372
  if (tag !== 'plaintext') {
331
- // TODO: Handle hosted devices
373
+ if ((0, WABinary_1.isHostedPnUser)(decryptionJid) || (0, WABinary_1.isHostedLidUser)(decryptionJid)) {
374
+ fullMessage.isHostedDevice = true
375
+ }
332
376
  await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
333
377
  }
334
378
  try {
335
379
  const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
336
380
  switch (e2eType) {
381
+ case 'frskmsg':
337
382
  case 'skmsg':
338
383
  msgBuffer = await repository.decryptGroupMessage({
339
384
  group: sender,
@@ -342,17 +387,39 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
342
387
  })
343
388
  break
344
389
 
390
+ case 'story_reply':
391
+ case 'feed_reshare':
392
+ case 'native_flow_response':
393
+ case 'companion_enc_static':
394
+ case 'avatar_sticker':
395
+ case 'genai_sticker':
396
+ case 'account_authentication_request':
397
+ case 'motion_video':
398
+ case 'motion_photo':
345
399
  case 'pkmsg':
346
- case 'msg':
400
+ case 'msg': {
401
+ const _unicastType =
402
+ e2eType === 'story_reply' ||
403
+ e2eType === 'feed_reshare' ||
404
+ e2eType === 'native_flow_response' ||
405
+ e2eType === 'companion_enc_static' ||
406
+ e2eType === 'avatar_sticker' ||
407
+ e2eType === 'genai_sticker' ||
408
+ e2eType === 'account_authentication_request' ||
409
+ e2eType === 'motion_video' ||
410
+ e2eType === 'motion_photo'
411
+ ? 'msg'
412
+ : e2eType
347
413
  msgBuffer = await repository.decryptMessage({
348
414
  jid: decryptionJid,
349
- type: e2eType,
415
+ type: _unicastType,
350
416
  ciphertext: content
351
417
  })
352
418
  break
353
- case 'msmsg': //Message Secret Message
354
- // null = no bot node (non-streaming), 'full'/'last' = complete response
355
- // 'first' = streaming partial response, intentionally skipped
419
+ }
420
+ case 'msmsg':
421
+
422
+
356
423
  if (botType !== null && !['full', 'last'].includes(botType)) break
357
424
  const secretIdCandidates = [botEditTargetId, metaTargetId, fullMessage.key?.id].filter(Boolean)
358
425
  const secretCandidates = []
@@ -388,17 +455,11 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
388
455
  participant: author,
389
456
  meId: metaTargetSenderJid || `${meLid.split(`:`)[0]}@lid`,
390
457
  meLid,
391
- conversationJid: sender,
392
- senderJid: metaTargetSenderJid,
393
- botType,
394
458
  botEditTargetId,
395
459
  metaTargetId,
396
- stanzaId: stanza.attrs?.id,
397
- targetId: botEditTargetId || metaTargetId || stanza.attrs?.id,
398
- targetIdCandidates: secretIdCandidates
460
+ stanzaId: stanza.attrs?.id
399
461
  }
400
462
  let decryptErr
401
- const candidateAttemptSummaries = []
402
463
  for (const candidate of secretCandidates) {
403
464
  try {
404
465
  msgBuffer = await (0, meta_ai_msmsg_1.decryptMsmsgBotMessage)(candidate.secret, helperKey, msMsg)
@@ -406,24 +467,16 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
406
467
  break
407
468
  } catch (e) {
408
469
  decryptErr = e
409
- if (Array.isArray(e?.attemptedStrategies) && e.attemptedStrategies.length) {
410
- candidateAttemptSummaries.push({
411
- secretSource: candidate.source,
412
- attemptedStrategies: e.attemptedStrategies
413
- })
414
- }
415
470
  }
416
471
  }
417
- if (!msgBuffer && candidateAttemptSummaries.length) {
472
+ if (!msgBuffer && decryptErr) {
418
473
  logger.warn(
419
474
  {
420
475
  secretCandidateSources: secretCandidates.map(candidate => candidate.source),
421
- attemptsBySecret: candidateAttemptSummaries
476
+ cause: decryptErr?.message
422
477
  },
423
478
  'msmsg: helper decryption failed for all candidate secrets'
424
479
  )
425
- }
426
- if (!msgBuffer && decryptErr) {
427
480
  throw decryptErr
428
481
  }
429
482
  }
@@ -446,18 +499,16 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
446
499
  let msg =
447
500
  e2eType === 'msmsg'
448
501
  ? (0, meta_ai_msmsg_1.decodeDecryptedMsmsgMessage)(msgBuffer)
449
- : index_js_1.proto.Message.decode(msgToDecode)
450
- if (false) {
451
- }
502
+ : WAProto_1.proto.Message.decode(msgToDecode)
452
503
  const outerMessageContextInfo = msg.messageContextInfo
453
504
  msg = msg.deviceSentMessage?.message || msg
454
- // deviceSentMessage.message may not carry messageContextInfo (e.g. messageSecret for @bot)
455
- // even though the outer wrapper does — preserve it
505
+
506
+
456
507
  if (outerMessageContextInfo && !msg.messageContextInfo) {
457
508
  msg.messageContextInfo = outerMessageContextInfo
458
509
  }
459
510
  if (msg.senderKeyDistributionMessage) {
460
- //eslint-disable-next-line max-depth
511
+
461
512
  try {
462
513
  await repository.processSenderKeyDistributionMessage({
463
514
  authorJid: author,
@@ -467,12 +518,200 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
467
518
  logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message')
468
519
  }
469
520
  }
521
+ if (msg.fastRatchetKeySenderKeyDistributionMessage) {
522
+
523
+ try {
524
+ await repository.processSenderKeyDistributionMessage({
525
+ authorJid: author,
526
+ item: msg.fastRatchetKeySenderKeyDistributionMessage
527
+ })
528
+ } catch (err) {
529
+ logger.error(
530
+ { key: fullMessage.key, err },
531
+ 'failed to process fast ratchet sender key distribution message'
532
+ )
533
+ }
534
+ }
470
535
  if (fullMessage.message) {
471
536
  Object.assign(fullMessage.message, msg)
472
537
  } else {
473
538
  fullMessage.message = msg
474
539
  }
475
- // Auto-decode richResponseMessage text so m.msg.text is populated
540
+
541
+ if (e2eType === 'story_reply') {
542
+ fullMessage.storyReply = true
543
+
544
+ const quotedJid = msg.extendedTextMessage?.contextInfo?.remoteJid
545
+ if (quotedJid && (0, WABinary_1.isJidStatusBroadcast)(quotedJid)) {
546
+ fullMessage.storyReply = true
547
+ }
548
+ }
549
+
550
+ if (e2eType === 'feed_reshare') {
551
+ fullMessage.feedReshare = true
552
+ }
553
+
554
+ if (attrs.view_once === 'read' || attrs.view_once === 'write') {
555
+ fullMessage.viewOnceType = attrs.view_once
556
+ }
557
+
558
+ if (msg.xmaMessage) {
559
+ fullMessage.xma = msg.xmaMessage
560
+ fullMessage.messageType = 'xma'
561
+ }
562
+
563
+ if (e2eType === 'native_flow_response' || msg.nativeFlowResponseMessage) {
564
+ fullMessage.messageType = 'native_flow_response'
565
+ if (msg.nativeFlowResponseMessage) {
566
+ fullMessage.nativeFlowResponse = msg.nativeFlowResponseMessage
567
+
568
+ if (msg.nativeFlowResponseMessage.name === 'md_smb_quick_reply') {
569
+ fullMessage.smbQuickReply = true
570
+ }
571
+ }
572
+ }
573
+
574
+ if (msg.callPermissionRequestMessage) {
575
+ fullMessage.messageType = 'call_permission_request'
576
+ fullMessage.callPermissionRequest = msg.callPermissionRequestMessage
577
+ }
578
+
579
+ if (msg.productMessage) {
580
+ fullMessage.messageType = 'product'
581
+ } else if (msg.orderMessage) {
582
+ fullMessage.messageType = 'order'
583
+ } else if (msg.catalogMessage || msg.listMessage?.catalogType) {
584
+ fullMessage.messageType = 'catalog'
585
+ }
586
+
587
+ if (msg.paymentMessage) {
588
+ fullMessage.messageType = 'payment'
589
+ const pm = msg.paymentMessage
590
+ fullMessage.paymentInfo = {
591
+ amount: pm.amount1000 ? pm.amount1000 / 1000 : null,
592
+ currency: pm.currencyCodeIso4217 || null,
593
+ status: pm.status || null,
594
+ transactionTimestamp: pm.transactionTimestamp
595
+ ? pm.transactionTimestamp.toNumber?.() || pm.transactionTimestamp
596
+ : null,
597
+ type: pm.type || null,
598
+ method: pm.paymentMethod || null,
599
+ futureProofed: pm.futureProofed || false
600
+ }
601
+ }
602
+ if (msg.requestPaymentMessage) {
603
+ fullMessage.messageType = 'request_payment'
604
+ fullMessage.paymentRequest = {
605
+ amount: msg.requestPaymentMessage.amount || null,
606
+ currency: msg.requestPaymentMessage.currencyCodeIso4217 || null,
607
+ expiry: msg.requestPaymentMessage.expiryTimestamp || null
608
+ }
609
+ }
610
+ if (msg.sendPaymentMessage) {
611
+ fullMessage.messageType = 'send_payment'
612
+ }
613
+ if (msg.cancelPaymentRequestMessage) {
614
+ fullMessage.messageType = 'cancel_payment'
615
+ }
616
+
617
+ if (msg.stickerMessage) {
618
+ if (msg.stickerMessage.isAvatar) {
619
+ fullMessage.isAvatarSticker = true
620
+ }
621
+ if (msg.stickerMessage.isAiSticker || msg.stickerMessage.isGenAI) {
622
+ fullMessage.isAiSticker = true
623
+ }
624
+ }
625
+
626
+ if (msg.stickerPackMessage) {
627
+ fullMessage.messageType = 'sticker_pack'
628
+ const sp = msg.stickerPackMessage
629
+ fullMessage.stickerPack = {
630
+ id: sp.stickerPackId,
631
+ name: sp.name,
632
+
633
+ origin: sp.stickerPackOrigin,
634
+ size: sp.stickerPackSize,
635
+ stickers: sp.stickers || []
636
+ }
637
+ }
638
+
639
+ if (msg.messageContextInfo?.botMetadata?.aiMediaCollectionMetadata) {
640
+ fullMessage.aiMediaCollectionMetadata = {
641
+ collectionId: msg.messageContextInfo.botMetadata.aiMediaCollectionMetadata.collectionId,
642
+ uploadOrderIndex: msg.messageContextInfo.botMetadata.aiMediaCollectionMetadata.uploadOrderIndex
643
+ }
644
+ }
645
+
646
+ if (msg.protocolMessage?.aiMediaCollectionMessage) {
647
+ fullMessage.messageType = 'ai_media_collection'
648
+ const amc = msg.protocolMessage.aiMediaCollectionMessage
649
+ fullMessage.aiMediaCollection = {
650
+ collectionId: amc.collectionId,
651
+ expectedMediaCount: amc.expectedMediaCount
652
+ }
653
+ }
654
+
655
+ if (msg.splitPaymentMessage) {
656
+ fullMessage.messageType = 'split_payment'
657
+ const sp = msg.splitPaymentMessage
658
+ fullMessage.splitPayment = {
659
+ splitId: sp.splitId,
660
+ totalAmount: sp.totalAmount,
661
+ description: sp.description,
662
+ requesterJid: sp.requesterJid,
663
+ participants: (sp.participants || []).map(p => ({
664
+ jid: p.jid,
665
+ amount: p.amount,
666
+
667
+ status: p.status
668
+ })),
669
+ createdAtMs: sp.createdAtMs ? sp.createdAtMs.toNumber?.() || sp.createdAtMs : null
670
+ }
671
+ }
672
+
673
+ if (msg.paymentInviteMessage) {
674
+ fullMessage.messageType = 'payment_invite'
675
+ const SERVICE_TYPE = { 0: 'UNKNOWN', 1: 'FBPAY', 2: 'NOVI', 3: 'UPI' }
676
+ fullMessage.paymentInvite = {
677
+ serviceType: SERVICE_TYPE[msg.paymentInviteMessage.serviceType] || 'UNKNOWN',
678
+ expiry: msg.paymentInviteMessage.expiryTimestamp
679
+ ? msg.paymentInviteMessage.expiryTimestamp.toNumber?.() || msg.paymentInviteMessage.expiryTimestamp
680
+ : null,
681
+ incentiveEligible: msg.paymentInviteMessage.incentiveEligible || false
682
+ }
683
+ }
684
+
685
+ if (msg.paymentReminderMessage) {
686
+ fullMessage.messageType = 'payment_reminder'
687
+ }
688
+
689
+ if (e2eType === 'companion_enc_static') {
690
+ fullMessage.companionEncStatic = true
691
+ }
692
+
693
+ if (e2eType === 'avatar_sticker' || e2eType === 'genai_sticker') {
694
+ fullMessage.stickerType = e2eType
695
+ }
696
+
697
+ if (e2eType === 'account_authentication_request' || msg.accountAuthRequestMessage) {
698
+ fullMessage.messageType = 'account_auth_request'
699
+ }
700
+
701
+ if (e2eType === 'motion_video' || (msg.videoMessage && msg.videoMessage.motionVideo)) {
702
+ fullMessage.messageType = 'motion_video'
703
+ fullMessage.motionVideo = true
704
+ }
705
+
706
+ if (e2eType === 'motion_photo' || (msg.imageMessage && msg.imageMessage.motionPhoto)) {
707
+ fullMessage.messageType = 'motion_photo'
708
+ fullMessage.motionPhoto = true
709
+ }
710
+
711
+ if (e2eType === 'plaintext') {
712
+ fullMessage.isNonE2EE = true
713
+ }
714
+
476
715
  {
477
716
  const rich = fullMessage.message?.richResponseMessage
478
717
  if (rich && !rich.text) {
@@ -485,7 +724,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
485
724
  if (decoded) editedRich.text = decoded
486
725
  }
487
726
  }
488
- // Save messageSecret for any message (AI group server may set it on any message)
727
+
489
728
  {
490
729
  const secret = msg.messageContextInfo?.messageSecret
491
730
  if (secret) {
@@ -505,25 +744,21 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
505
744
  isSessionRecordError: isSessionRecordError(err)
506
745
  }
507
746
  logger.error(errorContext, 'failed to decrypt message')
508
- fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT
747
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
509
748
  fullMessage.messageStubParameters = [err.message.toString()]
510
749
  }
511
750
  }
512
751
  }
513
- // if nothing was found to decrypt
752
+
514
753
  if (!decryptables && !fullMessage.key?.isViewOnce) {
515
- fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT
754
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
516
755
  fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT]
517
756
  }
518
757
  }
519
758
  }
520
759
  }
521
760
  exports.decryptMessageNode = decryptMessageNode
522
- /**
523
- * Decode text content from a richResponseMessage (Meta AI).
524
- * Tries submessages first, then parses base64 JSON from unifiedResponse.data.
525
- * Returns the extracted text string or '' on failure.
526
- */
761
+
527
762
  function decodeRichResponseMessage(richMsg) {
528
763
  try {
529
764
  if (!richMsg) return ''
@@ -547,13 +782,11 @@ function decodeRichResponseMessage(richMsg) {
547
782
  }
548
783
  }
549
784
  return texts.join('\n')
550
- } catch (e) {
785
+ } catch {
551
786
  return ''
552
787
  }
553
788
  }
554
- /**
555
- * Utility function to check if an error is related to missing session record
556
- */
789
+
557
790
  function isSessionRecordError(error) {
558
791
  const errorMessage = error?.message || error?.toString() || ''
559
792
  return exports.DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern))