kage-baileys 3.0.6 → 3.2.3

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 (216) hide show
  1. package/Example/connection.cjs +4 -0
  2. package/README.MD +4726 -48
  3. package/WAProto/WAProto.proto +3395 -415
  4. package/WAProto/compat.cjs +12 -0
  5. package/WAProto/index.d.ts +47104 -19888
  6. package/WAProto/index.js +131979 -57361
  7. package/lib/Addon/http-error.js +43 -0
  8. package/lib/Addon/index.js +32 -0
  9. package/lib/Addon/keyed-db.js +250 -0
  10. package/lib/Addon/link-preview.js +82 -0
  11. package/lib/Defaults/baileys-version.json +3 -0
  12. package/lib/Defaults/connection.js +110 -0
  13. package/lib/Defaults/constants.js +156 -0
  14. package/lib/Defaults/history.js +46 -0
  15. package/lib/Defaults/index.js +230 -0
  16. package/lib/Defaults/media.js +104 -0
  17. package/lib/Defaults/phonenumber-mcc.json +223 -0
  18. package/lib/Defaults/prefix.js +44 -0
  19. package/lib/Extensions/business-advanced.js +382 -0
  20. package/lib/Extensions/business.js +159 -0
  21. package/lib/Extensions/chats-advanced.js +1106 -0
  22. package/lib/Extensions/chats.js +349 -0
  23. package/lib/Extensions/communities-advanced.js +430 -0
  24. package/lib/Extensions/community.js +94 -0
  25. package/lib/Extensions/groups-advanced.js +343 -0
  26. package/lib/Extensions/index.js +30 -0
  27. package/lib/Extensions/messages-recv-advanced.js +1690 -0
  28. package/lib/Extensions/messages-send-advanced.js +622 -0
  29. package/lib/Extensions/messages-send.js +1380 -0
  30. package/lib/Extensions/newsletter-advanced.js +228 -0
  31. package/lib/Extensions/newsletter.js +72 -0
  32. package/lib/Extensions/socket.js +389 -0
  33. package/lib/Modded/message_builder.js +2084 -4
  34. package/lib/Signal/Group/ciphertext-message.js +54 -0
  35. package/lib/Signal/Group/group-session-builder.js +124 -0
  36. package/lib/Signal/Group/group_cipher.js +216 -0
  37. package/lib/Signal/Group/index.js +124 -0
  38. package/lib/Signal/Group/keyhelper.js +108 -0
  39. package/lib/Signal/Group/sender-chain-key.js +83 -0
  40. package/lib/Signal/Group/sender-key-distribution-message.js +157 -0
  41. package/lib/Signal/Group/sender-key-message.js +166 -0
  42. package/lib/Signal/Group/sender-key-name.js +130 -0
  43. package/lib/Signal/Group/sender-key-record.js +113 -0
  44. package/lib/Signal/Group/sender-key-state.js +208 -0
  45. package/lib/Signal/Group/sender-message-key.js +82 -0
  46. package/lib/Signal/libsignal.js +935 -0
  47. package/lib/Signal/lid-mapping.js +545 -1
  48. package/lib/Socket/Client/index.js +60 -0
  49. package/lib/Socket/Client/types.js +51 -0
  50. package/lib/Socket/Client/websocket.js +152 -0
  51. package/lib/Socket/business.js +831 -0
  52. package/lib/Socket/chats.js +2535 -49
  53. package/lib/Socket/communities.js +450 -1
  54. package/lib/Socket/community.js +1022 -0
  55. package/lib/Socket/dugong.js +1 -1
  56. package/lib/Socket/groups.js +747 -0
  57. package/lib/Socket/index.js +60 -2
  58. package/lib/Socket/messages-recv.js +3450 -5
  59. package/lib/Socket/messages-send.js +3123 -0
  60. package/lib/Socket/mex.js +126 -1
  61. package/lib/Socket/newsletter.js +465 -0
  62. package/lib/Socket/socket.js +2217 -1
  63. package/lib/Store/index.js +79 -0
  64. package/lib/Store/make-cache-manager-store.js +186 -0
  65. package/lib/Store/make-in-memory-store.js +878 -0
  66. package/lib/Store/make-ordered-dictionary.js +187 -0
  67. package/lib/Store/object-repository.js +78 -0
  68. package/lib/Types/Auth.js +25 -0
  69. package/lib/Types/Bussines.js +25 -1
  70. package/lib/Types/Call.js +25 -0
  71. package/lib/Types/Chat.js +39 -0
  72. package/lib/Types/Contact.js +25 -0
  73. package/lib/Types/Events.js +25 -0
  74. package/lib/Types/GroupMetadata.js +25 -0
  75. package/lib/Types/Label.js +76 -0
  76. package/lib/Types/LabelAssociation.js +40 -0
  77. package/lib/Types/Message.js +57 -0
  78. package/lib/Types/Mex.js +56 -1
  79. package/lib/Types/MexUpdates.js +46 -0
  80. package/lib/Types/Newsletter.js +56 -0
  81. package/lib/Types/Product.js +25 -0
  82. package/lib/Types/RichType.js +23 -0
  83. package/lib/Types/Signal.js +25 -0
  84. package/lib/Types/Socket.js +25 -0
  85. package/lib/Types/State.js +92 -0
  86. package/lib/Types/USync.js +25 -0
  87. package/lib/Types/index.js +133 -0
  88. package/lib/Utils/auth-utils.js +703 -0
  89. package/lib/Utils/automation-tools.js +51 -16
  90. package/lib/Utils/baileys-event-stream.js +146 -0
  91. package/lib/Utils/browser-utils.js +95 -0
  92. package/lib/Utils/business.js +525 -0
  93. package/lib/Utils/chat-utils.js +1861 -0
  94. package/lib/Utils/companion-reg-client-utils.js +55 -1
  95. package/lib/Utils/crypto.js +355 -0
  96. package/lib/Utils/decode-wa-message.js +709 -0
  97. package/lib/Utils/event-buffer.js +1323 -8
  98. package/lib/Utils/generics.js +945 -1
  99. package/lib/Utils/history.js +266 -0
  100. package/lib/Utils/identity-change-handler.js +62 -1
  101. package/lib/Utils/index.js +114 -0
  102. package/lib/Utils/link-preview.js +179 -0
  103. package/lib/Utils/logger.js +42 -0
  104. package/lib/Utils/lt-hash.js +73 -0
  105. package/lib/Utils/make-mutex.js +104 -0
  106. package/lib/Utils/message-inspector.js +110 -0
  107. package/lib/Utils/message-retry-manager.js +507 -2
  108. package/lib/Utils/messages-media.js +1931 -1
  109. package/lib/Utils/messages.js +3748 -0
  110. package/lib/Utils/noise-handler.js +423 -0
  111. package/lib/Utils/offline-node-processor.js +53 -1
  112. package/lib/Utils/pre-key-manager.js +255 -1
  113. package/lib/Utils/process-message.js +1592 -0
  114. package/lib/Utils/reporting-utils.js +272 -1
  115. package/lib/Utils/rich-message-utils.js +377 -0
  116. package/lib/Utils/rich-messages.js +1 -1
  117. package/lib/Utils/signal.js +437 -0
  118. package/lib/Utils/stanza-ack.js +51 -1
  119. package/lib/Utils/status-refresh.js +37 -0
  120. package/lib/Utils/status-tools.js +4 -2
  121. package/lib/Utils/sync-action-utils.js +63 -1
  122. package/lib/Utils/tc-token-utils.js +185 -1
  123. package/lib/Utils/terminal-banner.js +31 -0
  124. package/lib/Utils/use-multi-file-auth-state.js +271 -0
  125. package/lib/Utils/use-single-file-auth-state.js +108 -0
  126. package/lib/Utils/use-sqlite-auth-state.js +142 -0
  127. package/lib/Utils/validate-connection.js +497 -1
  128. package/lib/Utils/view-once-compat.js +13 -5
  129. package/lib/VoIP/audio-feeder.js +150 -0
  130. package/lib/VoIP/index.js +289 -0
  131. package/lib/VoIP/relay-transport.js +608 -0
  132. package/lib/VoIP/signaling.js +583 -0
  133. package/lib/VoIP/types.js +30 -0
  134. package/lib/VoIP/wasm-engine.js +1261 -2
  135. package/lib/VoIP/worker-bootstrap.js +1090 -2
  136. package/lib/WABinary/constants.js +2805 -0
  137. package/lib/WABinary/decode.js +649 -2
  138. package/lib/WABinary/encode.js +564 -2
  139. package/lib/WABinary/generic-utils.js +401 -0
  140. package/lib/WABinary/index.js +82 -0
  141. package/lib/WABinary/jid-utils.js +290 -0
  142. package/lib/WABinary/types.js +25 -0
  143. package/lib/WAM/BinaryInfo.js +50 -0
  144. package/lib/WAM/constants.js +45747 -0
  145. package/lib/WAM/encode.js +393 -0
  146. package/lib/WAM/index.js +78 -0
  147. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +135 -0
  148. package/lib/WAUSync/Protocols/USyncContactProtocol.js +110 -0
  149. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +142 -0
  150. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +85 -0
  151. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +69 -0
  152. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +107 -0
  153. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +38 -1
  154. package/lib/WAUSync/Protocols/index.js +83 -0
  155. package/lib/WAUSync/USyncQuery.js +241 -2
  156. package/lib/WAUSync/USyncUser.js +86 -0
  157. package/lib/WAUSync/index.js +78 -0
  158. package/lib/assets/wasm/loader.js +1875 -1
  159. package/lib/assets/wasm/worker-modules.js +11047 -1
  160. package/lib/index.d.ts +126 -0
  161. package/lib/index.js +53 -21
  162. package/lib/index.mjs +437 -0
  163. package/licenses/upstream-MIT.txt +22 -0
  164. package/maintenance/api-coverage.json +1642 -0
  165. package/maintenance/archivos-sha256.json +207 -0
  166. package/maintenance/consumer-validation.log +3 -0
  167. package/maintenance/dependency-audit.json +4 -4
  168. package/maintenance/extension-inventory.json +57 -0
  169. package/maintenance/protocol-update.json +1101 -0
  170. package/maintenance/protocol-wire-audit.json +4 -0
  171. package/maintenance/reference-socket-surface.json +209 -0
  172. package/maintenance/resumen-validacion.json +50 -0
  173. package/maintenance/validation.log +2725 -0
  174. package/maintenance/verification.json +566 -0
  175. package/package.json +107 -9
  176. package/scripts/check-imports.cjs +10 -0
  177. package/scripts/check-package.cjs +40 -0
  178. package/scripts/check-syntax.cjs +1 -1
  179. package/scripts/generate-protobuf.cjs +6 -1
  180. package/scripts/generate-public-types.cjs +9 -0
  181. package/scripts/kage-base64-fix.cjs +45 -0
  182. package/scripts/maintenance.cjs +10 -0
  183. package/test/advanced.test.cjs +24 -0
  184. package/test/base64-fix.test.cjs +49 -0
  185. package/test/maintenance.test.cjs +1 -1
  186. package/test/npm-publication.test.cjs +141 -0
  187. package/test/recepcion-reparada.test.cjs +98 -0
  188. package/test/resilience-binary.test.cjs +69 -0
  189. package/test/resilience-transport.test.cjs +34 -0
  190. package/test/types.test.ts +5 -0
  191. package/test/upgrade.test.cjs +104 -0
  192. package/tsconfig.json +20 -0
  193. package/WAProto/p.html +0 -1
  194. package/lib/KageExtra/Modded/message_builder.js +0 -2330
  195. package/lib/KageExtra/VoIP/audio-feeder.js +0 -136
  196. package/lib/KageExtra/VoIP/index.js +0 -282
  197. package/lib/KageExtra/VoIP/relay-transport.js +0 -559
  198. package/lib/KageExtra/VoIP/signaling.js +0 -603
  199. package/lib/KageExtra/VoIP/types.js +0 -17
  200. package/lib/KageExtra/VoIP/wasm-engine.js +0 -1214
  201. package/lib/KageExtra/VoIP/worker-bootstrap.js +0 -1042
  202. package/lib/KageExtra/assets/wasm/loader.js +0 -5
  203. package/lib/KageExtra/assets/wasm/whatsapp.wasm +0 -0
  204. package/lib/KageExtra/assets/wasm/worker-modules.js +0 -273
  205. package/lib/KageExtra/index.js +0 -3
  206. package/lib/KageExtra/package.json +0 -1
  207. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -53
  208. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -24
  209. package/maintenance/revision-full-check.txt +0 -1097
  210. package/maintenance/revision-library-tests.tap +0 -1088
  211. package/maintenance/revision-protobuf.txt +0 -5
  212. package/maintenance/revision-syntax.txt +0 -5
  213. package/maintenance/schema-coverage.json +0 -23
  214. package/maintenance/schema-merge.json +0 -30
  215. package/maintenance/validation-node20.txt +0 -191
  216. package/maintenance/validation-node22.txt +0 -237
@@ -215,3 +215,712 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
215
215
  };
216
216
  };
217
217
  exports.decryptMessageNode = decryptMessageNode;
218
+
219
+ // Kage: compatibilidad de API.
220
+ const __kageModule63 = (() => {
221
+ const module = { exports: {} }; const exports = module.exports;
222
+ "use strict"
223
+
224
+ Object.defineProperty(exports, "__esModule", { value: true })
225
+
226
+ const { Boom } = require("@hapi/boom")
227
+ const { proto } = require("../../WAProto")
228
+ const {
229
+ areJidsSameUser,
230
+ isHostedLidUser,
231
+ isHostedPnUser,
232
+ isJidBroadcast,
233
+ isJidGroup,
234
+ isJidMetaAI,
235
+ isJidNewsletter,
236
+ isJidStatusBroadcast,
237
+ isLidUser,
238
+ isPnUser
239
+ } = require("../WABinary")
240
+ const { unpadRandomMax16 } = require("./generics")
241
+ const { getDevice } = require("./messages")
242
+
243
+ const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node'
244
+
245
+ const MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled'
246
+
247
+ // Retry configuration for failed decryption
248
+ const DECRYPTION_RETRY_CONFIG = {
249
+ maxRetries: 3,
250
+ baseDelayMs: 100,
251
+ sessionRecordErrors: ['No session record', 'SessionError: No session record']
252
+ }
253
+
254
+ const NACK_REASONS = {
255
+ ParsingError: 487,
256
+ UnrecognizedStanza: 488,
257
+ UnrecognizedStanzaClass: 489,
258
+ UnrecognizedStanzaType: 490,
259
+ InvalidProtobuf: 491,
260
+ InvalidHostedCompanionStanza: 493,
261
+ MissingMessageSecret: 495,
262
+ SignalErrorOldCounter: 496,
263
+ MessageDeletedOnPeer: 499,
264
+ UnhandledError: 500,
265
+ UnsupportedAdminRevoke: 550,
266
+ UnsupportedLIDGroup: 551,
267
+ DBOperationFailed: 552
268
+ }
269
+
270
+ const extractAddressingContext = (stanza) => {
271
+ let senderAlt
272
+ let recipientAlt
273
+
274
+ const sender = stanza.attrs.participant || stanza.attrs.from
275
+ const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
276
+
277
+ if (addressingMode === 'lid') {
278
+ // Message is LID-addressed: sender is LID, extract corresponding PN
279
+ // without device data
280
+ senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
281
+ recipientAlt = stanza.attrs.recipient_pn
282
+ // with device data
283
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
284
+ }
285
+ else {
286
+ // Message is PN-addressed: sender is PN, extract corresponding LID
287
+ // without device data
288
+ senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
289
+ recipientAlt = stanza.attrs.recipient_lid
290
+ //with device data
291
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
292
+ }
293
+
294
+ return {
295
+ addressingMode,
296
+ senderAlt,
297
+ recipientAlt
298
+ }
299
+ }
300
+
301
+ const getDecryptionJid = async (sender, repository) => {
302
+ if (isLidUser(sender) || isHostedLidUser(sender)) {
303
+ return sender
304
+ }
305
+ const mapped = await repository.lidMapping.getLIDForPN(sender)
306
+ return mapped || sender
307
+ }
308
+
309
+ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
310
+ // TODO: Handle hosted IDs
311
+ const { senderAlt } = extractAddressingContext(stanza)
312
+
313
+ if (senderAlt && isLidUser(senderAlt) && isPnUser(sender) && decryptionJid === sender) {
314
+ try {
315
+ await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }])
316
+ await repository.migrateSession(sender, senderAlt)
317
+ logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope')
318
+ }
319
+ catch (error) {
320
+ logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping')
321
+ }
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Decode the received node as a message.
327
+ * @note this will only parse the message, not decrypt it
328
+ */
329
+ function decodeMessageNode(stanza, meId, meLid) {
330
+ let msgType
331
+ let chatId
332
+ let author
333
+ let fromMe = false
334
+
335
+ const msgId = stanza.attrs.id
336
+ const from = stanza.attrs.from
337
+ const participant = stanza.attrs.participant
338
+ const recipient = stanza.attrs.recipient
339
+ const addressingContext = extractAddressingContext(stanza)
340
+ const isMe = (jid) => areJidsSameUser(jid, meId)
341
+ const isMeLid = (jid) => areJidsSameUser(jid, meLid)
342
+
343
+ if (isPnUser(from) || isLidUser(from) || isHostedLidUser(from) || isHostedPnUser(from)) {
344
+ if (recipient && !isJidMetaAI(recipient)) {
345
+ if (!isMe(from) && !isMeLid(from)) {
346
+ throw new Boom('receipient present, but msg not from me', { data: stanza })
347
+ }
348
+
349
+ if (isMe(from) || isMeLid(from)) {
350
+ fromMe = true
351
+ }
352
+
353
+ chatId = recipient
354
+ }
355
+ else {
356
+ chatId = from
357
+ }
358
+
359
+ msgType = 'chat'
360
+ author = from
361
+ }
362
+
363
+ else if (isJidGroup(from)) {
364
+ if (!participant) {
365
+ throw new Boom('No participant in group message')
366
+ }
367
+
368
+ if (isMe(participant) || isMeLid(participant)) {
369
+ fromMe = true
370
+ }
371
+
372
+ msgType = 'group'
373
+ author = participant
374
+ chatId = from
375
+ }
376
+
377
+ else if (isJidBroadcast(from)) {
378
+ if (!participant) {
379
+ throw new Boom('No participant in group message')
380
+ }
381
+
382
+ const isParticipantMe = isMe(participant)
383
+
384
+ if (isJidStatusBroadcast(from)) {
385
+ msgType = isParticipantMe ? 'direct_peer_status' : 'other_status'
386
+ }
387
+
388
+ else {
389
+ msgType = isParticipantMe ? 'peer_broadcast' : 'other_broadcast'
390
+ }
391
+
392
+ fromMe = isParticipantMe
393
+ chatId = from
394
+ author = participant
395
+ }
396
+
397
+ else if (isJidNewsletter(from)) {
398
+ msgType = 'newsletter'
399
+ chatId = from
400
+ author = from
401
+
402
+ if (isMe(from) || isMeLid(from)) {
403
+ fromMe = true
404
+ }
405
+ }
406
+
407
+ else {
408
+ throw new Boom('Unknown message type', { data: stanza })
409
+ }
410
+
411
+ const pushname = stanza?.attrs?.notify
412
+
413
+ const key = {
414
+ remoteJid: chatId,
415
+ remoteJidAlt: !isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
416
+ fromMe,
417
+ id: msgId,
418
+ participant,
419
+ participantAlt: isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
420
+ addressingMode: addressingContext.addressingMode,
421
+ ...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {})
422
+ }
423
+
424
+ const fullMessage = {
425
+ key,
426
+ category: stanza.attrs.category,
427
+ messageTimestamp: +stanza.attrs.t,
428
+ pushName: pushname,
429
+ platform: getDevice(key.id),
430
+ broadcast: isJidBroadcast(from),
431
+ newsletter: isJidNewsletter(from)
432
+ }
433
+
434
+ if (key.fromMe) {
435
+ fullMessage.status = proto.WebMessageInfo.Status.SERVER_ACK
436
+ }
437
+
438
+ return {
439
+ fullMessage,
440
+ author,
441
+ sender: msgType === 'chat' ? author : chatId
442
+ }
443
+ }
444
+
445
+ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
446
+ const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid)
447
+ return {
448
+ fullMessage,
449
+ category: stanza.attrs.category,
450
+ author,
451
+ async decrypt() {
452
+ let decryptables = 0
453
+
454
+ if (Array.isArray(stanza.content)) {
455
+ for (const { tag, attrs, content } of stanza.content) {
456
+ if (tag === 'verified_name' && content instanceof Uint8Array) {
457
+ const cert = proto.VerifiedNameCertificate.decode(content)
458
+ const details = proto.VerifiedNameCertificate.Details.decode(cert.details)
459
+
460
+ fullMessage.verifiedBizName = details.verifiedName
461
+ }
462
+
463
+ if (tag === 'unavailable' && attrs.type === 'view_once') {
464
+ fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
465
+ }
466
+
467
+ if (attrs.count && tag === 'enc') {
468
+ fullMessage.retryCount = Number(attrs.count)
469
+ }
470
+
471
+ if (tag !== 'enc' && tag !== 'plaintext') {
472
+ continue
473
+ }
474
+
475
+ if (!(content instanceof Uint8Array)) {
476
+ continue
477
+ }
478
+
479
+ decryptables += 1
480
+
481
+ let msgBuffer
482
+
483
+ const decryptionJid = await getDecryptionJid(author, repository)
484
+
485
+ if (tag !== 'plaintext') {
486
+ // TODO: Handle hosted devices
487
+ await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
488
+ }
489
+
490
+ try {
491
+ const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
492
+ switch (e2eType) {
493
+ case 'skmsg':
494
+ msgBuffer = await repository.decryptGroupMessage({
495
+ group: sender,
496
+ authorJid: author,
497
+ msg: content
498
+ })
499
+ break
500
+ case 'pkmsg':
501
+ case 'msg':
502
+ msgBuffer = await repository.decryptMessage({
503
+ jid: decryptionJid,
504
+ type: e2eType,
505
+ ciphertext: content
506
+ })
507
+ break
508
+ case 'plaintext':
509
+ msgBuffer = content
510
+ break
511
+ default:
512
+ throw new Error(`Unknown e2e type: ${e2eType}`)
513
+ }
514
+
515
+ let msg = proto.Message.decode(e2eType !== 'plaintext' ? unpadRandomMax16(msgBuffer) : msgBuffer)
516
+
517
+ msg = msg.deviceSentMessage?.message || msg
518
+
519
+ if (msg.senderKeyDistributionMessage) {
520
+ try {
521
+ await repository.processSenderKeyDistributionMessage({
522
+ authorJid: author,
523
+ item: msg.senderKeyDistributionMessage
524
+ })
525
+ }
526
+
527
+ catch (err) {
528
+ logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message')
529
+ }
530
+ }
531
+
532
+ if (fullMessage.message) {
533
+ Object.assign(fullMessage.message, msg)
534
+ }
535
+
536
+ else {
537
+ fullMessage.message = msg
538
+ }
539
+ }
540
+
541
+ catch (err) {
542
+ const errorContext = {
543
+ key: fullMessage.key,
544
+ err,
545
+ messageType: tag === 'plaintext' ? 'plaintext' : attrs.type,
546
+ sender,
547
+ author,
548
+ isSessionRecordError: isSessionRecordError(err)
549
+ }
550
+
551
+ logger.error(errorContext, 'failed to decrypt message')
552
+ fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT
553
+ fullMessage.messageStubParameters = [err.message.toString()]
554
+ }
555
+ }
556
+ }
557
+
558
+ // if nothing was found to decrypt
559
+ if (!decryptables && !fullMessage.key?.isViewOnce) {
560
+ fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT
561
+ fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT]
562
+ }
563
+ }
564
+ }
565
+ }
566
+
567
+ /**
568
+ * Utility function to check if an error is related to missing session record
569
+ */
570
+ function isSessionRecordError(error) {
571
+ const errorMessage = error?.message || error?.toString() || ''
572
+ return DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern))
573
+ }
574
+
575
+ module.exports = {
576
+ NACK_REASONS,
577
+ decodeMessageNode,
578
+ decryptMessageNode,
579
+ extractAddressingContext,
580
+ MISSING_KEYS_ERROR_TEXT,
581
+ DECRYPTION_RETRY_CONFIG,
582
+ NO_MESSAGE_FOUND_ERROR_TEXT
583
+ }
584
+ return module.exports;
585
+ })();
586
+ for (const key of Object.keys(__kageModule63)) {
587
+ if (key !== '__esModule' && !Object.prototype.hasOwnProperty.call(exports,key)) Object.defineProperty(exports,key,{enumerable:true,configurable:true,get:()=>__kageModule63[key]});
588
+ }
589
+
590
+ // Kage: funciones avanzadas.
591
+ const __kageModule167 = (() => {
592
+ const module = { exports: {} }; const exports = module.exports;
593
+ "use strict";
594
+ Object.defineProperty(exports, "__esModule", { value: true });
595
+ exports.decryptMessageNode = exports.extractAddressingContext = exports.SERVER_ERROR_CODES = exports.NACK_REASONS = exports.DECRYPTION_RETRY_CONFIG = exports.ACCOUNT_RESTRICTED_TEXT = exports.MISSING_KEYS_ERROR_TEXT = exports.NO_MESSAGE_FOUND_ERROR_TEXT = exports.getDecryptionJid = void 0;
596
+ exports.decodeMessageNode = decodeMessageNode;
597
+ const index_js_1 = require("../../WAProto/index.js");
598
+ const index_js_2 = require("../Addon/index.js");
599
+ const index_js_3 = require("../WABinary/index.js");
600
+ const generics_js_1 = require("./generics.js");
601
+ const getDecryptionJid = async (sender, repository) => {
602
+ if ((0, index_js_3.isLidUser)(sender) || (0, index_js_3.isHostedLidUser)(sender)) {
603
+ return sender;
604
+ }
605
+ const mapped = await repository.lidMapping.getLIDForPN(sender);
606
+ return mapped || sender;
607
+ };
608
+ exports.getDecryptionJid = getDecryptionJid;
609
+ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
610
+ // TODO: Handle hosted IDs
611
+ const { senderAlt } = (0, exports.extractAddressingContext)(stanza);
612
+ if (senderAlt && (0, index_js_3.isLidUser)(senderAlt) && (0, index_js_3.isPnUser)(sender) && decryptionJid === sender) {
613
+ try {
614
+ await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }]);
615
+ await repository.migrateSession(sender, senderAlt);
616
+ logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope');
617
+ }
618
+ catch (error) {
619
+ logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping');
620
+ }
621
+ }
622
+ };
623
+ exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
624
+ exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled';
625
+ exports.ACCOUNT_RESTRICTED_TEXT = 'Your account has been restricted';
626
+ // Retry configuration for failed decryption
627
+ exports.DECRYPTION_RETRY_CONFIG = {
628
+ maxRetries: 3,
629
+ baseDelayMs: 100,
630
+ sessionRecordErrors: ['No session record', 'SessionError: No session record']
631
+ };
632
+ /** NACK reason codes we send to the server (client → server) */
633
+ exports.NACK_REASONS = {
634
+ SenderReachoutTimelocked: 463,
635
+ ParsingError: 487,
636
+ UnrecognizedStanza: 488,
637
+ UnrecognizedStanzaClass: 489,
638
+ UnrecognizedStanzaType: 490,
639
+ InvalidProtobuf: 491,
640
+ InvalidHostedCompanionStanza: 493,
641
+ MissingMessageSecret: 495,
642
+ SignalErrorOldCounter: 496,
643
+ MessageDeletedOnPeer: 499,
644
+ UnhandledError: 500,
645
+ UnsupportedAdminRevoke: 550,
646
+ UnsupportedLIDGroup: 551,
647
+ DBOperationFailed: 552
648
+ };
649
+ /**
650
+ * Server-side error codes returned in ack stanzas (server → client) that we
651
+ * currently have dedicated handlers for. Extend as more handlers are added.
652
+ * Distinct from the client-side NackReason enum (WAWebCreateNackFromStanza).
653
+ */
654
+ exports.SERVER_ERROR_CODES = {
655
+ /**
656
+ * 1:1 message missing privacy token (tctoken). Usually means the account is
657
+ * restricted: WhatsApp blocks starting new chats but preserves existing ones,
658
+ * since established chats already carry a tctoken.
659
+ */
660
+ MessageAccountRestriction: '463',
661
+ /** Stanza validation failure (SMAX_INVALID) — likely stale device session */
662
+ SmaxInvalid: '479'
663
+ };
664
+ const extractAddressingContext = (stanza) => {
665
+ let senderAlt;
666
+ let recipientAlt;
667
+ const sender = stanza.attrs.participant || stanza.attrs.from;
668
+ const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn');
669
+ if (addressingMode === 'lid') {
670
+ // Message is LID-addressed: sender is LID, extract corresponding PN
671
+ // without device data
672
+ senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn;
673
+ recipientAlt = stanza.attrs.recipient_pn;
674
+ // with device data
675
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
676
+ }
677
+ else {
678
+ // Message is PN-addressed: sender is PN, extract corresponding LID
679
+ // without device data
680
+ senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid;
681
+ recipientAlt = stanza.attrs.recipient_lid;
682
+ //with device data
683
+ //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
684
+ }
685
+ return {
686
+ addressingMode,
687
+ senderAlt,
688
+ recipientAlt
689
+ };
690
+ };
691
+ exports.extractAddressingContext = extractAddressingContext;
692
+ /**
693
+ * Decode the received node as a message.
694
+ * @note this will only parse the message, not decrypt it
695
+ */
696
+ function decodeMessageNode(stanza, meId, meLid) {
697
+ let msgType;
698
+ let chatId;
699
+ let author;
700
+ let fromMe = false;
701
+ const msgId = stanza.attrs.id;
702
+ const from = stanza.attrs.from;
703
+ const participant = stanza.attrs.participant;
704
+ const recipient = stanza.attrs.recipient;
705
+ if (!msgId) {
706
+ throw new index_js_2.HttpError('Invalid message stanza: missing id attribute', { data: stanza });
707
+ }
708
+ if (!from) {
709
+ throw new index_js_2.HttpError('Invalid message stanza: missing from attribute', { data: stanza });
710
+ }
711
+ const addressingContext = (0, exports.extractAddressingContext)(stanza);
712
+ const isMe = (jid) => (0, index_js_3.areJidsSameUser)(jid, meId);
713
+ const isMeLid = (jid) => (0, index_js_3.areJidsSameUser)(jid, meLid);
714
+ if ((0, index_js_3.isPnUser)(from) || (0, index_js_3.isLidUser)(from) || (0, index_js_3.isHostedLidUser)(from) || (0, index_js_3.isHostedPnUser)(from)) {
715
+ if (recipient && !(0, index_js_3.isJidMetaAI)(recipient)) {
716
+ if (!isMe(from) && !isMeLid(from)) {
717
+ throw new index_js_2.HttpError('receipient present, but msg not from me', { data: stanza });
718
+ }
719
+ if (isMe(from) || isMeLid(from)) {
720
+ fromMe = true;
721
+ }
722
+ chatId = recipient;
723
+ }
724
+ else {
725
+ // Peer-routed self stanzas (history sync, app-state sync, etc.) arrive
726
+ // with `from` set to our own device but no `recipient` attribute —
727
+ // still mark as fromMe so self-only protocolMessage handlers run.
728
+ if (isMe(from) || isMeLid(from)) {
729
+ fromMe = true;
730
+ }
731
+ chatId = from;
732
+ }
733
+ msgType = 'chat';
734
+ author = from;
735
+ }
736
+ else if ((0, index_js_3.isJidGroup)(from)) {
737
+ if (!participant) {
738
+ throw new index_js_2.HttpError('No participant in group message');
739
+ }
740
+ if (isMe(participant) || isMeLid(participant)) {
741
+ fromMe = true;
742
+ }
743
+ msgType = 'group';
744
+ author = participant;
745
+ chatId = from;
746
+ }
747
+ else if ((0, index_js_3.isJidBroadcast)(from)) {
748
+ if (!participant) {
749
+ throw new index_js_2.HttpError('No participant in group message');
750
+ }
751
+ const isParticipantMe = isMe(participant);
752
+ if ((0, index_js_3.isJidStatusBroadcast)(from)) {
753
+ msgType = isParticipantMe ? 'direct_peer_status' : 'other_status';
754
+ }
755
+ else {
756
+ msgType = isParticipantMe ? 'peer_broadcast' : 'other_broadcast';
757
+ }
758
+ fromMe = isParticipantMe;
759
+ chatId = from;
760
+ author = participant;
761
+ }
762
+ else if ((0, index_js_3.isJidNewsletter)(from)) {
763
+ msgType = 'newsletter';
764
+ chatId = from;
765
+ author = from;
766
+ if (isMe(from) || isMeLid(from)) {
767
+ fromMe = true;
768
+ }
769
+ }
770
+ else {
771
+ throw new index_js_2.HttpError('Unknown message type', { data: stanza });
772
+ }
773
+ const pushname = stanza?.attrs?.notify;
774
+ const key = {
775
+ remoteJid: chatId,
776
+ remoteJidAlt: !(0, index_js_3.isJidGroup)(chatId) ? addressingContext.senderAlt : undefined,
777
+ remoteJidUsername: !(0, index_js_3.isJidGroup)(chatId)
778
+ ? stanza.attrs.peer_recipient_username || stanza.attrs.recipient_username
779
+ : undefined,
780
+ fromMe,
781
+ id: msgId,
782
+ participant,
783
+ participantAlt: (0, index_js_3.isJidGroup)(chatId) ? addressingContext.senderAlt : undefined,
784
+ participantUsername: stanza.attrs.participant ? stanza.attrs.participant_username : undefined,
785
+ addressingMode: addressingContext.addressingMode,
786
+ ...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {})
787
+ };
788
+ const fullMessage = {
789
+ key,
790
+ category: stanza.attrs.category,
791
+ messageTimestamp: +stanza.attrs.t,
792
+ pushName: pushname,
793
+ broadcast: (0, index_js_3.isJidBroadcast)(from)
794
+ };
795
+ if (key.fromMe) {
796
+ fullMessage.status = index_js_1.proto.WebMessageInfo.Status.SERVER_ACK;
797
+ }
798
+ return {
799
+ fullMessage,
800
+ author,
801
+ sender: msgType === 'chat' ? author : chatId
802
+ };
803
+ }
804
+ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
805
+ const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid);
806
+ return {
807
+ fullMessage,
808
+ category: stanza.attrs.category,
809
+ author,
810
+ async decrypt() {
811
+ let decryptables = 0;
812
+ if (Array.isArray(stanza.content)) {
813
+ for (const { tag, attrs, content } of stanza.content) {
814
+ if (tag === 'verified_name' && content instanceof Uint8Array) {
815
+ const cert = index_js_1.proto.VerifiedNameCertificate.decode(content);
816
+ const details = index_js_1.proto.VerifiedNameCertificate.Details.decode(cert.details);
817
+ fullMessage.verifiedBizName = details.verifiedName;
818
+ }
819
+ if (tag === 'unavailable' && attrs.type === 'view_once') {
820
+ fullMessage.key.isViewOnce = true; // TODO: remove from here and add a STUB TYPE
821
+ }
822
+ if (attrs.count && tag === 'enc') {
823
+ fullMessage.retryCount = Number(attrs.count);
824
+ }
825
+ if (tag !== 'enc' && tag !== 'plaintext') {
826
+ continue;
827
+ }
828
+ if (!(content instanceof Uint8Array)) {
829
+ continue;
830
+ }
831
+ decryptables += 1;
832
+ let msgBuffer;
833
+ const decryptionJid = await (0, exports.getDecryptionJid)(author, repository);
834
+ if (tag !== 'plaintext') {
835
+ // TODO: Handle hosted devices
836
+ await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger);
837
+ }
838
+ try {
839
+ const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type;
840
+ switch (e2eType) {
841
+ case 'skmsg':
842
+ msgBuffer = await repository.decryptGroupMessage({
843
+ group: sender,
844
+ authorJid: author,
845
+ msg: content
846
+ });
847
+ break;
848
+ case 'pkmsg':
849
+ case 'msg':
850
+ msgBuffer = await repository.decryptMessage({
851
+ jid: decryptionJid,
852
+ type: e2eType,
853
+ ciphertext: content
854
+ });
855
+ break;
856
+ case 'plaintext':
857
+ msgBuffer = content;
858
+ break;
859
+ default:
860
+ throw new Error(`Unknown e2e type: ${e2eType}`);
861
+ }
862
+ let msg = index_js_1.proto.Message.decode(e2eType !== 'plaintext' ? (0, generics_js_1.unpadRandomMax16)(msgBuffer) : msgBuffer);
863
+ msg = msg.deviceSentMessage?.message || msg;
864
+ if (msg.senderKeyDistributionMessage) {
865
+ //eslint-disable-next-line max-depth
866
+ try {
867
+ await repository.processSenderKeyDistributionMessage({
868
+ authorJid: author,
869
+ item: msg.senderKeyDistributionMessage
870
+ });
871
+ }
872
+ catch (err) {
873
+ logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message');
874
+ }
875
+ }
876
+ if (fullMessage.message) {
877
+ Object.assign(fullMessage.message, msg);
878
+ }
879
+ else {
880
+ fullMessage.message = msg;
881
+ }
882
+ }
883
+ catch (err) {
884
+ const errorContext = {
885
+ key: fullMessage.key,
886
+ err,
887
+ messageType: tag === 'plaintext' ? 'plaintext' : attrs.type,
888
+ sender,
889
+ author,
890
+ isSessionRecordError: isSessionRecordError(err)
891
+ };
892
+ logger.error(errorContext, 'failed to decrypt message');
893
+ fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT;
894
+ fullMessage.messageStubParameters = [err.message.toString()];
895
+ }
896
+ }
897
+ }
898
+ // if nothing was found to decrypt
899
+ if (!decryptables && !fullMessage.key?.isViewOnce) {
900
+ fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT;
901
+ fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT];
902
+ }
903
+ }
904
+ };
905
+ };
906
+ exports.decryptMessageNode = decryptMessageNode;
907
+ /**
908
+ * Utility function to check if an error is related to missing session record
909
+ */
910
+ function isSessionRecordError(error) {
911
+ const errorMessage = error?.message || error?.toString() || '';
912
+ return exports.DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern));
913
+ }
914
+
915
+ return module.exports;
916
+ })();
917
+ for (const key of Object.keys(__kageModule167)) {
918
+ if (key !== '__esModule' && !Object.prototype.hasOwnProperty.call(exports,key)) Object.defineProperty(exports,key,{enumerable:true,configurable:true,get:()=>__kageModule167[key]});
919
+ }
920
+ Object.defineProperty(exports, Symbol.for('kage.advanced'), {value:__kageModule167, configurable:true});
921
+
922
+ // Kage: superficie pública completa.
923
+ for (const name of ["NACK_REASONS"]) {
924
+ const advanced = exports[Symbol.for('kage.advanced')][name];
925
+ for (const [key, value] of Object.entries(advanced || {})) if (!(key in exports[name])) exports[name][key] = value;
926
+ }