@badzz88/baileys 8.5.4 → 8.5.5
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.
- package/README.md +1 -1
- package/WAProto/WAProto.proto +75 -1256
- package/WAProto/index.d.ts +19729 -36122
- package/WAProto/index.js +132193 -178538
- package/engine-requirements.js +15 -7
- package/lib/Defaults/index.js +14 -22
- package/lib/Signal/Group/group_cipher.js +5 -5
- package/lib/Signal/Group/keyhelper.js +4 -4
- package/lib/Signal/Group/sender-chain-key.js +2 -2
- package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
- package/lib/Signal/Group/sender-key-message.js +3 -3
- package/lib/Signal/Group/sender-key-record.js +1 -1
- package/lib/Signal/Group/sender-message-key.js +5 -5
- package/lib/Signal/libsignal.js +28 -39
- package/lib/Signal/lid-mapping.js +8 -28
- package/lib/Socket/aigroups.js +5 -5
- package/lib/Socket/business.js +11 -3
- package/lib/Socket/chats.js +319 -668
- package/lib/Socket/communities.js +89 -85
- package/lib/Socket/graphql.js +228 -435
- package/lib/Socket/groups.js +211 -132
- package/lib/Socket/index.js +7 -9
- package/lib/Socket/interactive-handler.js +60 -117
- package/lib/Socket/interop.js +175 -56
- package/lib/Socket/luxu.js +387 -0
- package/lib/Socket/managed-account.js +48 -79
- package/lib/Socket/messages-recv.js +340 -898
- package/lib/Socket/messages-send.js +160 -462
- package/lib/Socket/mex.js +53 -40
- package/lib/Socket/newsletter.js +295 -291
- package/lib/Socket/privacy.js +265 -77
- package/lib/Socket/registration.js +157 -164
- package/lib/Socket/socket.js +199 -181
- package/lib/Socket/text-router.js +83 -0
- package/lib/Socket/username.js +227 -144
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +2 -2
- package/lib/Store/make-in-memory-store.js +141 -25
- package/lib/Types/Auth.js +3 -3
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Mex.js +112 -0
- package/lib/Types/Newsletter.js +65 -96
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +57 -52
- package/lib/Utils/browser-utils.js +1 -1
- package/lib/Utils/business.js +6 -2
- package/lib/Utils/chat-utils.js +38 -102
- package/lib/Utils/command-loader.d.ts +31 -0
- package/lib/Utils/command-loader.js +100 -0
- package/lib/Utils/companion-reg-client-utils.js +42 -0
- package/lib/Utils/crypto.js +84 -54
- package/lib/Utils/curve25519-js.js +275 -0
- package/lib/Utils/decode-wa-message.js +83 -316
- package/lib/Utils/event-buffer.js +61 -37
- package/lib/Utils/generics.js +103 -157
- package/lib/Utils/group-history.js +12 -3
- package/lib/Utils/history.js +15 -15
- package/lib/Utils/index.js +5 -1
- package/lib/Utils/link-preview.js +8 -3
- package/lib/Utils/lt-hash.js +35 -2
- package/lib/Utils/make-mutex.js +1 -1
- package/lib/Utils/message-retry-manager.js +92 -27
- package/lib/Utils/messages-media.js +130 -159
- package/lib/Utils/messages.js +566 -144
- package/lib/Utils/meta-ai-msmsg.js +202 -62
- package/lib/Utils/native-bridge.js +82 -0
- package/lib/Utils/noise-handler.js +21 -19
- package/lib/Utils/offline-node-processor.js +8 -3
- package/lib/Utils/pre-key-manager.js +23 -13
- package/lib/Utils/process-message.js +106 -197
- package/lib/Utils/reporting-utils.js +2 -2
- package/lib/Utils/session-pool.d.ts +16 -0
- package/lib/Utils/session-pool.js +94 -0
- package/lib/Utils/signal.js +63 -28
- package/lib/Utils/stanza-ack.js +12 -39
- package/lib/Utils/sticker.d.ts +17 -0
- package/lib/Utils/sticker.js +145 -0
- package/lib/Utils/sync-action-utils.js +7 -4
- package/lib/Utils/tc-token-utils.js +25 -20
- package/lib/Utils/use-multi-file-auth-state.js +14 -30
- package/lib/Utils/validate-connection.js +19 -59
- package/lib/Utils/view-once-cache.d.ts +9 -0
- package/lib/Utils/view-once-cache.js +79 -0
- package/lib/WABinary/decode.js +16 -50
- package/lib/WABinary/encode.js +224 -54
- package/lib/WABinary/generic-utils.js +97 -7
- package/lib/WABinary/jid-utils.js +14 -27
- package/lib/WAM/encode.js +7 -7
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +1 -58
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +1 -7
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +7 -20
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
- package/lib/WAUSync/Protocols/index.js +0 -1
- package/lib/WAUSync/USyncQuery.js +6 -77
- package/lib/WAUSync/USyncUser.js +8 -16
- package/lib/WAUSync/index.js +0 -1
- package/lib/antiban.js +854 -608
- package/lib/index.js +1 -1
- package/package.json +20 -16
|
@@ -11,12 +11,16 @@ 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')
|
|
14
15
|
const WAProto_1 = require('../../WAProto/index.js')
|
|
15
16
|
const WABinary_1 = require('../WABinary')
|
|
16
17
|
const generics_1 = require('./generics')
|
|
17
18
|
const meta_ai_msmsg_1 = require('./meta-ai-msmsg')
|
|
18
19
|
const messages_1 = require('./messages')
|
|
19
20
|
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
|
|
20
24
|
const botMessageSecrets = new Map()
|
|
21
25
|
const botRecentSecretsByChat = new Map()
|
|
22
26
|
const pushRecentChatSecret = (chatJid, id, secretBuf) => {
|
|
@@ -53,7 +57,7 @@ const getDecryptionJid = async (sender, repository) => {
|
|
|
53
57
|
(0, WABinary_1.isHostedLidUser)(sender) ||
|
|
54
58
|
(0, WABinary_1.isInteropUser)(sender)
|
|
55
59
|
) {
|
|
56
|
-
|
|
60
|
+
// LID and interop JIDs are session keys themselves — no PN mapping lookup needed
|
|
57
61
|
return sender
|
|
58
62
|
}
|
|
59
63
|
const mapped = await repository.lidMapping.getLIDForPN(sender)
|
|
@@ -61,11 +65,12 @@ const getDecryptionJid = async (sender, repository) => {
|
|
|
61
65
|
}
|
|
62
66
|
exports.getDecryptionJid = getDecryptionJid
|
|
63
67
|
const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
|
|
68
|
+
// TODO: Handle hosted IDs
|
|
64
69
|
const { senderAlt } = (0, exports.extractAddressingContext)(stanza)
|
|
65
70
|
if (
|
|
66
71
|
senderAlt &&
|
|
67
|
-
(
|
|
68
|
-
(
|
|
72
|
+
(0, WABinary_1.isLidUser)(senderAlt) &&
|
|
73
|
+
(0, WABinary_1.isPnUser)(sender) &&
|
|
69
74
|
decryptionJid === sender
|
|
70
75
|
) {
|
|
71
76
|
try {
|
|
@@ -79,14 +84,17 @@ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJi
|
|
|
79
84
|
}
|
|
80
85
|
exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node'
|
|
81
86
|
exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled'
|
|
82
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Server-side error codes returned in ack stanzas (server → client).
|
|
89
|
+
* Distinct from the client-side NackReason enum.
|
|
90
|
+
*/
|
|
83
91
|
exports.SERVER_ERROR_CODES = {
|
|
84
|
-
|
|
92
|
+
/** 1:1 message missing privacy token (tctoken) */
|
|
85
93
|
MissingTcToken: '463',
|
|
86
|
-
|
|
94
|
+
/** Stanza validation failure (SMAX_INVALID) — likely stale device session */
|
|
87
95
|
SmaxInvalid: '479'
|
|
88
96
|
}
|
|
89
|
-
|
|
97
|
+
// Retry configuration for failed decryption
|
|
90
98
|
exports.DECRYPTION_RETRY_CONFIG = {
|
|
91
99
|
maxRetries: 3,
|
|
92
100
|
baseDelayMs: 100,
|
|
@@ -113,19 +121,19 @@ const extractAddressingContext = stanza => {
|
|
|
113
121
|
const sender = stanza.attrs.participant || stanza.attrs.from
|
|
114
122
|
const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
|
|
115
123
|
if (addressingMode === 'lid') {
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
// Message is LID-addressed: sender is LID, extract corresponding PN
|
|
125
|
+
// without device data
|
|
118
126
|
senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
|
|
119
127
|
recipientAlt = stanza.attrs.recipient_pn
|
|
120
|
-
|
|
121
|
-
|
|
128
|
+
// with device data
|
|
129
|
+
//if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
|
|
122
130
|
} else {
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
// Message is PN-addressed: sender is PN, extract corresponding LID
|
|
132
|
+
// without device data
|
|
125
133
|
senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
|
|
126
134
|
recipientAlt = stanza.attrs.recipient_lid
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
//with device data
|
|
136
|
+
//if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
|
|
129
137
|
}
|
|
130
138
|
return {
|
|
131
139
|
addressingMode,
|
|
@@ -134,50 +142,15 @@ const extractAddressingContext = stanza => {
|
|
|
134
142
|
}
|
|
135
143
|
}
|
|
136
144
|
exports.extractAddressingContext = extractAddressingContext
|
|
137
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Decode the received node as a message.
|
|
147
|
+
* @note this will only parse the message, not decrypt it
|
|
148
|
+
*/
|
|
138
149
|
function decodeMessageNode(stanza, meId, meLid) {
|
|
139
|
-
let nodey = []
|
|
140
150
|
let msgType
|
|
141
151
|
let chatId
|
|
142
152
|
let author
|
|
143
153
|
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
|
-
|
|
181
154
|
const msgId = stanza.attrs.id
|
|
182
155
|
const from = stanza.attrs.from
|
|
183
156
|
const participant = stanza.attrs.participant
|
|
@@ -236,9 +209,9 @@ content: content
|
|
|
236
209
|
msgType = 'newsletter'
|
|
237
210
|
chatId = from
|
|
238
211
|
author = from
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
212
|
+
// if (isMe(from) || isMeLid(from)) {
|
|
213
|
+
// fromMe = true
|
|
214
|
+
// }
|
|
242
215
|
|
|
243
216
|
fromMe = (0, WABinary_1.isJidNewsletter)(from)
|
|
244
217
|
? !!stanza.attrs?.is_sender
|
|
@@ -246,8 +219,8 @@ content: content
|
|
|
246
219
|
? (0, WABinary_1.areJidsSameUser)(from, meLid)
|
|
247
220
|
: (0, WABinary_1.areJidsSameUser)(from, meId)
|
|
248
221
|
} else if ((0, WABinary_1.isInteropUser)(from)) {
|
|
249
|
-
|
|
250
|
-
|
|
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.
|
|
251
224
|
msgType = 'chat'
|
|
252
225
|
chatId = from
|
|
253
226
|
author = from
|
|
@@ -255,7 +228,7 @@ content: content
|
|
|
255
228
|
} else {
|
|
256
229
|
throw new boom_1.Boom('Unknown message type', { data: stanza })
|
|
257
230
|
}
|
|
258
|
-
|
|
231
|
+
// Interop stanzas (BirdyChat/Haiket) use display_name instead of notify
|
|
259
232
|
const pushname = stanza?.attrs?.notify ?? stanza?.attrs?.display_name
|
|
260
233
|
const key = {
|
|
261
234
|
remoteJid: chatId,
|
|
@@ -279,12 +252,10 @@ content: content
|
|
|
279
252
|
broadcast: (0, WABinary_1.isJidBroadcast)(from),
|
|
280
253
|
newsletter: (0, WABinary_1.isJidNewsletter)(from),
|
|
281
254
|
StanzaAttrs: stanza.attrs,
|
|
282
|
-
|
|
283
|
-
Owner: 'badzz88'
|
|
284
|
-
|
|
255
|
+
Owner: 'xazbails' // Non-WhatsApp attribute
|
|
285
256
|
}
|
|
286
257
|
if (key.fromMe) {
|
|
287
|
-
fullMessage.status =
|
|
258
|
+
fullMessage.status = index_js_1.proto.WebMessageInfo.Status.SERVER_ACK
|
|
288
259
|
}
|
|
289
260
|
if (msgType === 'newsletter') {
|
|
290
261
|
fullMessage.newsletter_server_id = +stanza.attrs?.server_id
|
|
@@ -327,7 +298,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
327
298
|
metaTargetSenderJid = attrs.target_sender_jid
|
|
328
299
|
}
|
|
329
300
|
if (tag === 'bot' && attrs && 'edit_target_id' in attrs) {
|
|
330
|
-
botEditTargetId = attrs.edit_target_id
|
|
301
|
+
botEditTargetId = attrs.edit_target_id // Can be '' for 'first' type
|
|
331
302
|
}
|
|
332
303
|
if (tag === 'bot' && (attrs === null || attrs === void 0 ? void 0 : attrs.edit)) {
|
|
333
304
|
botType = attrs.edit
|
|
@@ -335,27 +306,14 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
335
306
|
}
|
|
336
307
|
}
|
|
337
308
|
|
|
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) {
|
|
309
|
+
for (const { tag, attrs, content } of stanza.content) {
|
|
347
310
|
if (tag === 'verified_name' && content instanceof Uint8Array) {
|
|
348
|
-
const cert =
|
|
349
|
-
const details =
|
|
311
|
+
const cert = index_js_1.proto.VerifiedNameCertificate.decode(content)
|
|
312
|
+
const details = index_js_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
|
|
350
313
|
fullMessage.verifiedBizName = details.verifiedName
|
|
351
|
-
|
|
352
|
-
if (attrs?.verified_level) {
|
|
353
|
-
fullMessage.verifiedNameLevel = attrs.verified_level
|
|
354
|
-
}
|
|
355
314
|
}
|
|
356
315
|
if (tag === 'unavailable' && attrs.type === 'view_once') {
|
|
357
|
-
fullMessage.key.isViewOnce = true
|
|
358
|
-
fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.VIEWED_ONCE
|
|
316
|
+
fullMessage.key.isViewOnce = true // TODO: remove from here and add a STUB TYPE
|
|
359
317
|
}
|
|
360
318
|
if (attrs.count && tag === 'enc') {
|
|
361
319
|
fullMessage.retryCount = Number(attrs.count)
|
|
@@ -370,15 +328,12 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
370
328
|
let msgBuffer
|
|
371
329
|
const decryptionJid = await (0, exports.getDecryptionJid)(author, repository)
|
|
372
330
|
if (tag !== 'plaintext') {
|
|
373
|
-
|
|
374
|
-
fullMessage.isHostedDevice = true
|
|
375
|
-
}
|
|
331
|
+
// TODO: Handle hosted devices
|
|
376
332
|
await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
|
|
377
333
|
}
|
|
378
334
|
try {
|
|
379
335
|
const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
|
|
380
336
|
switch (e2eType) {
|
|
381
|
-
case 'frskmsg':
|
|
382
337
|
case 'skmsg':
|
|
383
338
|
msgBuffer = await repository.decryptGroupMessage({
|
|
384
339
|
group: sender,
|
|
@@ -387,39 +342,17 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
387
342
|
})
|
|
388
343
|
break
|
|
389
344
|
|
|
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':
|
|
399
345
|
case 'pkmsg':
|
|
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
|
|
346
|
+
case 'msg':
|
|
413
347
|
msgBuffer = await repository.decryptMessage({
|
|
414
348
|
jid: decryptionJid,
|
|
415
|
-
type:
|
|
349
|
+
type: e2eType,
|
|
416
350
|
ciphertext: content
|
|
417
351
|
})
|
|
418
352
|
break
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
353
|
+
case 'msmsg': //Message Secret Message
|
|
354
|
+
// null = no bot node (non-streaming), 'full'/'last' = complete response
|
|
355
|
+
// 'first' = streaming partial response, intentionally skipped
|
|
423
356
|
if (botType !== null && !['full', 'last'].includes(botType)) break
|
|
424
357
|
const secretIdCandidates = [botEditTargetId, metaTargetId, fullMessage.key?.id].filter(Boolean)
|
|
425
358
|
const secretCandidates = []
|
|
@@ -455,11 +388,17 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
455
388
|
participant: author,
|
|
456
389
|
meId: metaTargetSenderJid || `${meLid.split(`:`)[0]}@lid`,
|
|
457
390
|
meLid,
|
|
391
|
+
conversationJid: sender,
|
|
392
|
+
senderJid: metaTargetSenderJid,
|
|
393
|
+
botType,
|
|
458
394
|
botEditTargetId,
|
|
459
395
|
metaTargetId,
|
|
460
|
-
stanzaId: stanza.attrs?.id
|
|
396
|
+
stanzaId: stanza.attrs?.id,
|
|
397
|
+
targetId: botEditTargetId || metaTargetId || stanza.attrs?.id,
|
|
398
|
+
targetIdCandidates: secretIdCandidates
|
|
461
399
|
}
|
|
462
400
|
let decryptErr
|
|
401
|
+
const candidateAttemptSummaries = []
|
|
463
402
|
for (const candidate of secretCandidates) {
|
|
464
403
|
try {
|
|
465
404
|
msgBuffer = await (0, meta_ai_msmsg_1.decryptMsmsgBotMessage)(candidate.secret, helperKey, msMsg)
|
|
@@ -467,16 +406,24 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
467
406
|
break
|
|
468
407
|
} catch (e) {
|
|
469
408
|
decryptErr = e
|
|
409
|
+
if (Array.isArray(e?.attemptedStrategies) && e.attemptedStrategies.length) {
|
|
410
|
+
candidateAttemptSummaries.push({
|
|
411
|
+
secretSource: candidate.source,
|
|
412
|
+
attemptedStrategies: e.attemptedStrategies
|
|
413
|
+
})
|
|
414
|
+
}
|
|
470
415
|
}
|
|
471
416
|
}
|
|
472
|
-
if (!msgBuffer &&
|
|
417
|
+
if (!msgBuffer && candidateAttemptSummaries.length) {
|
|
473
418
|
logger.warn(
|
|
474
419
|
{
|
|
475
420
|
secretCandidateSources: secretCandidates.map(candidate => candidate.source),
|
|
476
|
-
|
|
421
|
+
attemptsBySecret: candidateAttemptSummaries
|
|
477
422
|
},
|
|
478
423
|
'msmsg: helper decryption failed for all candidate secrets'
|
|
479
424
|
)
|
|
425
|
+
}
|
|
426
|
+
if (!msgBuffer && decryptErr) {
|
|
480
427
|
throw decryptErr
|
|
481
428
|
}
|
|
482
429
|
}
|
|
@@ -499,16 +446,18 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
499
446
|
let msg =
|
|
500
447
|
e2eType === 'msmsg'
|
|
501
448
|
? (0, meta_ai_msmsg_1.decodeDecryptedMsmsgMessage)(msgBuffer)
|
|
502
|
-
:
|
|
449
|
+
: index_js_1.proto.Message.decode(msgToDecode)
|
|
450
|
+
if (false) {
|
|
451
|
+
}
|
|
503
452
|
const outerMessageContextInfo = msg.messageContextInfo
|
|
504
453
|
msg = msg.deviceSentMessage?.message || msg
|
|
505
|
-
|
|
506
|
-
|
|
454
|
+
// deviceSentMessage.message may not carry messageContextInfo (e.g. messageSecret for @bot)
|
|
455
|
+
// even though the outer wrapper does — preserve it
|
|
507
456
|
if (outerMessageContextInfo && !msg.messageContextInfo) {
|
|
508
457
|
msg.messageContextInfo = outerMessageContextInfo
|
|
509
458
|
}
|
|
510
459
|
if (msg.senderKeyDistributionMessage) {
|
|
511
|
-
|
|
460
|
+
//eslint-disable-next-line max-depth
|
|
512
461
|
try {
|
|
513
462
|
await repository.processSenderKeyDistributionMessage({
|
|
514
463
|
authorJid: author,
|
|
@@ -518,200 +467,12 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
518
467
|
logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message')
|
|
519
468
|
}
|
|
520
469
|
}
|
|
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
|
-
}
|
|
535
470
|
if (fullMessage.message) {
|
|
536
471
|
Object.assign(fullMessage.message, msg)
|
|
537
472
|
} else {
|
|
538
473
|
fullMessage.message = msg
|
|
539
474
|
}
|
|
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
|
-
|
|
475
|
+
// Auto-decode richResponseMessage text so m.msg.text is populated
|
|
715
476
|
{
|
|
716
477
|
const rich = fullMessage.message?.richResponseMessage
|
|
717
478
|
if (rich && !rich.text) {
|
|
@@ -724,7 +485,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
724
485
|
if (decoded) editedRich.text = decoded
|
|
725
486
|
}
|
|
726
487
|
}
|
|
727
|
-
|
|
488
|
+
// Save messageSecret for any message (AI group server may set it on any message)
|
|
728
489
|
{
|
|
729
490
|
const secret = msg.messageContextInfo?.messageSecret
|
|
730
491
|
if (secret) {
|
|
@@ -744,21 +505,25 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
744
505
|
isSessionRecordError: isSessionRecordError(err)
|
|
745
506
|
}
|
|
746
507
|
logger.error(errorContext, 'failed to decrypt message')
|
|
747
|
-
fullMessage.messageStubType =
|
|
508
|
+
fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT
|
|
748
509
|
fullMessage.messageStubParameters = [err.message.toString()]
|
|
749
510
|
}
|
|
750
511
|
}
|
|
751
512
|
}
|
|
752
|
-
|
|
513
|
+
// if nothing was found to decrypt
|
|
753
514
|
if (!decryptables && !fullMessage.key?.isViewOnce) {
|
|
754
|
-
fullMessage.messageStubType =
|
|
515
|
+
fullMessage.messageStubType = index_js_1.proto.WebMessageInfo.StubType.CIPHERTEXT
|
|
755
516
|
fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT]
|
|
756
517
|
}
|
|
757
518
|
}
|
|
758
519
|
}
|
|
759
520
|
}
|
|
760
521
|
exports.decryptMessageNode = decryptMessageNode
|
|
761
|
-
|
|
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
|
+
*/
|
|
762
527
|
function decodeRichResponseMessage(richMsg) {
|
|
763
528
|
try {
|
|
764
529
|
if (!richMsg) return ''
|
|
@@ -782,11 +547,13 @@ function decodeRichResponseMessage(richMsg) {
|
|
|
782
547
|
}
|
|
783
548
|
}
|
|
784
549
|
return texts.join('\n')
|
|
785
|
-
} catch {
|
|
550
|
+
} catch (e) {
|
|
786
551
|
return ''
|
|
787
552
|
}
|
|
788
553
|
}
|
|
789
|
-
|
|
554
|
+
/**
|
|
555
|
+
* Utility function to check if an error is related to missing session record
|
|
556
|
+
*/
|
|
790
557
|
function isSessionRecordError(error) {
|
|
791
558
|
const errorMessage = error?.message || error?.toString() || ''
|
|
792
559
|
return exports.DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern))
|