@neelegirl/baileys 1.5.2 → 1.5.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.
- package/LICENSE +21 -21
- package/README.md +195 -187
- package/WAProto/WAProto.proto +537 -236
- package/WAProto/index.d.ts +5971 -2388
- package/WAProto/index.js +17298 -6513
- package/lib/Defaults/baileys-version.json +3 -3
- package/lib/Defaults/index.d.ts +77 -67
- package/lib/Defaults/index.js +148 -136
- package/lib/Defaults/phonenumber-mcc.json +223 -223
- package/lib/Signal/WASignalGroup/GroupProtocol.js +1908 -1908
- package/lib/Signal/WASignalGroup/ciphertext-message.d.ts +9 -0
- package/lib/Signal/WASignalGroup/ciphertext-message.js +19 -0
- package/lib/Signal/WASignalGroup/ciphertext_message.js +15 -15
- package/lib/Signal/WASignalGroup/group-session-builder.d.ts +17 -0
- package/lib/Signal/WASignalGroup/group-session-builder.js +72 -0
- package/lib/Signal/WASignalGroup/group.proto +41 -41
- package/lib/Signal/WASignalGroup/group_cipher.d.ts +19 -0
- package/lib/Signal/WASignalGroup/group_cipher.js +101 -110
- package/lib/Signal/WASignalGroup/group_session_builder.js +45 -45
- package/lib/Signal/WASignalGroup/index.d.ts +11 -0
- package/lib/Signal/WASignalGroup/index.js +61 -6
- package/lib/Signal/WASignalGroup/keyhelper.d.ts +16 -0
- package/lib/Signal/WASignalGroup/keyhelper.js +58 -13
- package/lib/Signal/WASignalGroup/protobufs.js +2 -2
- package/lib/Signal/WASignalGroup/queue_job.js +68 -68
- package/lib/Signal/WASignalGroup/readme.md +5 -5
- package/lib/Signal/WASignalGroup/sender-chain-key.d.ts +14 -0
- package/lib/Signal/WASignalGroup/sender-chain-key.js +47 -0
- package/lib/Signal/WASignalGroup/sender-key-distribution-message.d.ts +17 -0
- package/lib/Signal/WASignalGroup/sender-key-distribution-message.js +71 -0
- package/lib/Signal/WASignalGroup/sender-key-message.d.ts +19 -0
- package/lib/Signal/WASignalGroup/sender-key-message.js +73 -0
- package/lib/Signal/WASignalGroup/sender-key-name.d.ts +19 -0
- package/lib/Signal/WASignalGroup/sender-key-name.js +59 -0
- package/lib/Signal/WASignalGroup/sender-key-record.d.ts +32 -0
- package/lib/Signal/WASignalGroup/sender-key-record.js +58 -0
- package/lib/Signal/WASignalGroup/sender-key-state.d.ts +44 -0
- package/lib/Signal/WASignalGroup/sender-key-state.js +147 -0
- package/lib/Signal/WASignalGroup/sender-message-key.d.ts +11 -0
- package/lib/Signal/WASignalGroup/sender-message-key.js +33 -0
- package/lib/Signal/WASignalGroup/sender_chain_key.js +49 -49
- package/lib/Signal/WASignalGroup/sender_key_distribution_message.js +77 -77
- package/lib/Signal/WASignalGroup/sender_key_message.js +91 -91
- package/lib/Signal/WASignalGroup/sender_key_name.js +69 -69
- package/lib/Signal/WASignalGroup/sender_key_record.js +55 -55
- package/lib/Signal/WASignalGroup/sender_key_state.js +128 -128
- package/lib/Signal/WASignalGroup/sender_message_key.js +38 -38
- package/lib/Signal/libsignal.d.ts +5 -1
- package/lib/Signal/libsignal.js +390 -161
- package/lib/Signal/lid-mapping.d.ts +28 -0
- package/lib/Signal/lid-mapping.js +184 -0
- package/lib/Socket/Client/abstract-socket-client.d.ts +15 -15
- package/lib/Socket/Client/abstract-socket-client.js +13 -13
- package/lib/Socket/Client/index.d.ts +2 -2
- package/lib/Socket/Client/mobile-socket-client.d.ts +12 -12
- package/lib/Socket/Client/mobile-socket-client.js +65 -65
- package/lib/Socket/Client/types.d.ts +1 -1
- package/lib/Socket/Client/websocket.d.ts +1 -1
- package/lib/Socket/business.d.ts +6 -6
- package/lib/Socket/business.js +152 -5
- package/lib/Socket/chats.d.ts +3 -4
- package/lib/Socket/chats.js +31 -26
- package/lib/Socket/communities.d.ts +223 -223
- package/lib/Socket/communities.js +432 -432
- package/lib/Socket/groups.d.ts +2 -4
- package/lib/Socket/groups.js +22 -14
- package/lib/Socket/index.d.ts +69 -69
- package/lib/Socket/index.js +3 -2
- package/lib/Socket/messages-recv.d.ts +3 -6
- package/lib/Socket/messages-recv.js +1449 -1707
- package/lib/Socket/messages-send.d.ts +2 -4
- package/lib/Socket/messages-send.js +617 -126
- package/lib/Socket/mex.d.ts +2 -2
- package/lib/Socket/mex.js +46 -46
- package/lib/Socket/newsletter.d.ts +2 -4
- package/lib/Socket/newsletter.js +294 -285
- package/lib/Socket/socket.js +318 -132
- package/lib/Socket/usync.js +3 -3
- package/lib/Store/index.d.ts +4 -4
- package/lib/Store/index.js +23 -23
- package/lib/Store/make-cache-manager-store.d.ts +13 -13
- package/lib/Store/make-cache-manager-store.js +89 -89
- package/lib/Store/make-in-memory-store.d.ts +122 -122
- package/lib/Store/make-in-memory-store.js +428 -428
- package/lib/Store/make-ordered-dictionary.d.ts +11 -11
- package/lib/Store/make-ordered-dictionary.js +85 -85
- package/lib/Store/object-repository.d.ts +9 -9
- package/lib/Store/object-repository.js +30 -30
- package/lib/Types/Auth.d.ts +5 -4
- package/lib/Types/Bussines.js +3 -0
- package/lib/Types/Bussiness.d.ts +28 -0
- package/lib/Types/Chat.d.ts +13 -8
- package/lib/Types/Contact.d.ts +4 -1
- package/lib/Types/Events.d.ts +13 -16
- package/lib/Types/GroupMetadata.d.ts +1 -1
- package/lib/Types/Message.d.ts +18 -7
- package/lib/Types/Message.js +7 -1
- package/lib/Types/MexUpdates.d.ts +8 -8
- package/lib/Types/MexUpdates.js +17 -17
- package/lib/Types/Newsletter.d.ts +1 -1
- package/lib/Types/Product.d.ts +1 -1
- package/lib/Types/Signal.d.ts +31 -1
- package/lib/Types/Socket.d.ts +34 -13
- package/lib/Types/State.d.ts +1 -1
- package/lib/Types/USync.d.ts +2 -2
- package/lib/Types/index.d.ts +16 -15
- package/lib/Types/index.js +4 -2
- package/lib/Utils/auth-utils.d.ts +20 -20
- package/lib/Utils/auth-utils.js +527 -204
- package/lib/Utils/baileys-event-stream.d.ts +17 -17
- package/lib/Utils/baileys-event-stream.js +69 -69
- package/lib/Utils/business.d.ts +28 -28
- package/lib/Utils/business.js +254 -254
- package/lib/Utils/chat-utils.d.ts +81 -81
- package/lib/Utils/chat-utils.js +808 -780
- package/lib/Utils/crypto.d.ts +55 -55
- package/lib/Utils/crypto.js +188 -178
- package/lib/Utils/decode-wa-message.d.ts +52 -40
- package/lib/Utils/decode-wa-message.js +322 -252
- package/lib/Utils/event-buffer.d.ts +38 -38
- package/lib/Utils/event-buffer.js +594 -564
- package/lib/Utils/generics.d.ts +131 -129
- package/lib/Utils/generics.js +629 -623
- package/lib/Utils/history.d.ts +22 -22
- package/lib/Utils/history.js +103 -109
- package/lib/Utils/index.d.ts +20 -19
- package/lib/Utils/index.js +39 -38
- package/lib/Utils/link-preview.d.ts +22 -22
- package/lib/Utils/link-preview.js +119 -119
- package/lib/Utils/logger.d.ts +13 -13
- package/lib/Utils/logger.js +7 -7
- package/lib/Utils/lt-hash.d.ts +13 -13
- package/lib/Utils/lt-hash.js +57 -57
- package/lib/Utils/make-mutex.d.ts +8 -8
- package/lib/Utils/make-mutex.js +48 -48
- package/lib/Utils/message-retry-manager.d.ts +88 -0
- package/lib/Utils/message-retry-manager.js +160 -0
- package/lib/Utils/messages-media.d.ts +134 -128
- package/lib/Utils/messages-media.js +868 -805
- package/lib/Utils/messages.d.ts +104 -102
- package/lib/Utils/messages.js +1744 -1578
- package/lib/Utils/noise-handler.d.ts +20 -19
- package/lib/Utils/noise-handler.js +164 -154
- package/lib/Utils/process-message.d.ts +48 -48
- package/lib/Utils/process-message.js +427 -428
- package/lib/Utils/signal.d.ts +41 -41
- package/lib/Utils/signal.js +165 -165
- package/lib/Utils/use-mongo-file-auth-state.d.ts +5 -5
- package/lib/Utils/use-mongo-file-auth-state.js +83 -83
- package/lib/Utils/use-multi-file-auth-state.d.ts +17 -17
- package/lib/Utils/use-multi-file-auth-state.js +237 -237
- package/lib/Utils/use-single-file-auth-state.d.ts +12 -12
- package/lib/Utils/use-single-file-auth-state.js +79 -79
- package/lib/Utils/validate-connection.d.ts +12 -12
- package/lib/Utils/validate-connection.js +219 -186
- package/lib/WABinary/constants.d.ts +29 -29
- package/lib/WABinary/constants.js +1315 -1315
- package/lib/WABinary/decode.d.ts +8 -8
- package/lib/WABinary/decode.js +287 -287
- package/lib/WABinary/encode.d.ts +2 -2
- package/lib/WABinary/encode.js +264 -264
- package/lib/WABinary/generic-utils.d.ts +27 -27
- package/lib/WABinary/generic-utils.js +141 -141
- package/lib/WABinary/index.d.ts +5 -5
- package/lib/WABinary/index.js +24 -24
- package/lib/WABinary/jid-utils.d.ts +58 -53
- package/lib/WABinary/jid-utils.js +103 -91
- package/lib/WABinary/types.d.ts +21 -21
- package/lib/WABinary/types.js +2 -2
- package/lib/WAM/BinaryInfo.d.ts +15 -15
- package/lib/WAM/BinaryInfo.js +16 -16
- package/lib/WAM/constants.d.ts +46 -46
- package/lib/WAM/constants.js +15370 -15370
- package/lib/WAM/encode.d.ts +2 -2
- package/lib/WAM/encode.js +163 -164
- package/lib/WAM/index.d.ts +3 -3
- package/lib/WAM/index.js +22 -22
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +27 -27
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +68 -68
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +3 -3
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +9 -8
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +37 -29
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/index.d.ts +6 -6
- package/lib/WAUSync/USyncQuery.d.ts +3 -3
- package/lib/WAUSync/index.d.ts +3 -3
- package/lib/index.d.ts +13 -13
- package/lib/index.js +33 -33
- package/package.json +96 -94
- package/lib/Socket/registration.d.ts +0 -266
- package/lib/Socket/registration.js +0 -166
|
@@ -17,9 +17,10 @@ const WABinary_1 = require("../WABinary")
|
|
|
17
17
|
const WAUSync_1 = require("../WAUSync")
|
|
18
18
|
const newsletter_1 = require("./newsletter")
|
|
19
19
|
const link_preview_1 = require("../Utils/link-preview")
|
|
20
|
+
const make_keyed_mutex_1 = require("../Utils/make-mutex")
|
|
20
21
|
|
|
21
22
|
const makeMessagesSocket = (config) => {
|
|
22
|
-
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, } = config
|
|
23
|
+
const { logger, maxMsgRetryCount, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache } = config
|
|
23
24
|
const baron = newsletter_1.makeNewsletterSocket(config)
|
|
24
25
|
const { ev, authState, processingMutex, signalRepository, upsertMessage, createCallLink, query, fetchPrivacySettings, sendNode, groupQuery, groupMetadata, groupToggleEphemeral, newsletterWMexQuery, executeUSyncQuery } = baron
|
|
25
26
|
|
|
@@ -27,6 +28,12 @@ const makeMessagesSocket = (config) => {
|
|
|
27
28
|
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
28
29
|
useClones: false
|
|
29
30
|
})
|
|
31
|
+
|
|
32
|
+
// Initialize message retry manager if enabled
|
|
33
|
+
const messageRetryManager = enableRecentMessageCache ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount) : null
|
|
34
|
+
|
|
35
|
+
// Prevent race conditions in Signal session encryption by user
|
|
36
|
+
const encryptionMutex = make_keyed_mutex_1.makeKeyedMutex()
|
|
30
37
|
|
|
31
38
|
let mediaConn
|
|
32
39
|
|
|
@@ -139,6 +146,37 @@ const makeMessagesSocket = (config) => {
|
|
|
139
146
|
|
|
140
147
|
await sendReceipts(keys, readType)
|
|
141
148
|
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Deduplicate JIDs when both LID and PN versions exist for same user
|
|
152
|
+
* Prefers LID over PN to maintain single encryption layer
|
|
153
|
+
*/
|
|
154
|
+
const deduplicateLidPnJids = (jids) => {
|
|
155
|
+
const lidUsers = new Set()
|
|
156
|
+
const filteredJids = []
|
|
157
|
+
|
|
158
|
+
// Collect all LID users
|
|
159
|
+
for (const jid of jids) {
|
|
160
|
+
if (WABinary_1.isLidUser(jid)) {
|
|
161
|
+
const user = WABinary_1.jidDecode(jid)?.user
|
|
162
|
+
if (user)
|
|
163
|
+
lidUsers.add(user)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Filter out PN versions when LID exists
|
|
168
|
+
for (const jid of jids) {
|
|
169
|
+
if (WABinary_1.isJidUser(jid)) {
|
|
170
|
+
const user = WABinary_1.jidDecode(jid)?.user
|
|
171
|
+
if (user && lidUsers.has(user)) {
|
|
172
|
+
logger.debug({ jid }, 'Skipping PN - LID version exists')
|
|
173
|
+
continue
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
filteredJids.push(jid)
|
|
177
|
+
}
|
|
178
|
+
return filteredJids
|
|
179
|
+
}
|
|
142
180
|
|
|
143
181
|
/** Fetch image for groups, user, and newsletter **/
|
|
144
182
|
const profilePictureUrl = async (jid) => {
|
|
@@ -190,103 +228,293 @@ const makeMessagesSocket = (config) => {
|
|
|
190
228
|
/** Fetch all the devices we've to send a message to */
|
|
191
229
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
192
230
|
const deviceResults = []
|
|
193
|
-
|
|
231
|
+
|
|
194
232
|
if (!useCache) {
|
|
195
233
|
logger.debug('not using cache for devices')
|
|
196
234
|
}
|
|
197
|
-
|
|
235
|
+
|
|
198
236
|
const toFetch = []
|
|
199
|
-
|
|
200
|
-
jids = Array.from(new Set(jids))
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
237
|
+
|
|
238
|
+
jids = deduplicateLidPnJids(Array.from(new Set(jids)))
|
|
239
|
+
const jidsWithUser = jids
|
|
240
|
+
.map(jid => {
|
|
241
|
+
const decoded = WABinary_1.jidDecode(jid)
|
|
242
|
+
const user = decoded?.user
|
|
243
|
+
const device = decoded?.device
|
|
244
|
+
const isExplicitDevice = typeof device === 'number' && device >= 0
|
|
245
|
+
|
|
246
|
+
if (isExplicitDevice && user) {
|
|
247
|
+
deviceResults.push({
|
|
248
|
+
user,
|
|
249
|
+
device,
|
|
250
|
+
wireJid: jid // again this makes no sense
|
|
251
|
+
});
|
|
252
|
+
return null
|
|
253
|
+
}
|
|
254
|
+
|
|
205
255
|
jid = WABinary_1.jidNormalizedUser(jid)
|
|
206
|
-
|
|
256
|
+
return { jid, user }
|
|
257
|
+
})
|
|
258
|
+
.filter(jid => jid !== null)
|
|
259
|
+
|
|
260
|
+
let mgetDevices
|
|
261
|
+
|
|
262
|
+
if (useCache && userDevicesCache.mget) {
|
|
263
|
+
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean)
|
|
264
|
+
mgetDevices = await userDevicesCache.mget(usersToFetch)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
for (const { jid, user } of jidsWithUser) {
|
|
207
268
|
if (useCache) {
|
|
208
|
-
const devices =
|
|
209
|
-
|
|
269
|
+
const devices = mgetDevices?.[user] ||
|
|
270
|
+
(userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)))
|
|
271
|
+
|
|
210
272
|
if (devices) {
|
|
211
|
-
|
|
273
|
+
const isLidJid = WABinary_1.isLidUser(jid)
|
|
274
|
+
const devicesWithWire = devices.map(d => ({
|
|
275
|
+
...d,
|
|
276
|
+
wireJid: isLidJid ? WABinary_1.jidEncode(d.user, 'lid', d.device) : WABinary_1.jidEncode(d.user, 's.whatsapp.net', d.device)
|
|
277
|
+
}))
|
|
278
|
+
|
|
279
|
+
deviceResults.push(...devicesWithWire)
|
|
212
280
|
logger.trace({ user }, 'using cache for devices')
|
|
213
281
|
}
|
|
214
|
-
|
|
215
282
|
else {
|
|
216
283
|
toFetch.push(jid)
|
|
217
284
|
}
|
|
218
285
|
}
|
|
219
|
-
|
|
220
286
|
else {
|
|
221
287
|
toFetch.push(jid)
|
|
222
288
|
}
|
|
223
289
|
}
|
|
224
|
-
|
|
290
|
+
|
|
225
291
|
if (!toFetch.length) {
|
|
226
292
|
return deviceResults
|
|
227
293
|
}
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
.
|
|
232
|
-
|
|
294
|
+
|
|
295
|
+
const requestedLidUsers = new Set()
|
|
296
|
+
for (const jid of toFetch) {
|
|
297
|
+
if (WABinary_1.isLidUser(jid)) {
|
|
298
|
+
const user = WABinary_1.jidDecode(jid)?.user
|
|
299
|
+
if (user)
|
|
300
|
+
requestedLidUsers.add(user)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const query = new WAUSync_1.USyncQuery().withContext('message').withDeviceProtocol()
|
|
233
305
|
for (const jid of toFetch) {
|
|
234
306
|
query.withUser(new WAUSync_1.USyncUser().withId(jid))
|
|
235
307
|
}
|
|
236
|
-
|
|
308
|
+
|
|
237
309
|
const result = await executeUSyncQuery(query)
|
|
238
|
-
|
|
310
|
+
|
|
239
311
|
if (result) {
|
|
240
312
|
const extracted = Utils_1.extractDeviceJids(result?.list, authState.creds.me.id, ignoreZeroDevices)
|
|
241
313
|
const deviceMap = {}
|
|
242
|
-
|
|
314
|
+
|
|
243
315
|
for (const item of extracted) {
|
|
244
316
|
deviceMap[item.user] = deviceMap[item.user] || []
|
|
245
|
-
deviceMap[item.user]
|
|
246
|
-
deviceResults.push(item)
|
|
317
|
+
deviceMap[item.user]?.push(item)
|
|
247
318
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
319
|
+
|
|
320
|
+
// Process each user's devices as a group for bulk LID migration
|
|
321
|
+
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
322
|
+
const isLidUser = requestedLidUsers.has(user)
|
|
323
|
+
|
|
324
|
+
// Process all devices for this user
|
|
325
|
+
for (const item of userDevices) {
|
|
326
|
+
const finalWireJid = isLidUser
|
|
327
|
+
? WABinary_1.jidEncode(user, 'lid', item.device)
|
|
328
|
+
: WABinary_1.jidEncode(item.user, 's.whatsapp.net', item.device)
|
|
329
|
+
deviceResults.push({
|
|
330
|
+
...item,
|
|
331
|
+
wireJid: finalWireJid
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
logger.debug({
|
|
335
|
+
user: item.user,
|
|
336
|
+
device: item.device,
|
|
337
|
+
finalWireJid,
|
|
338
|
+
usedLid: isLidUser
|
|
339
|
+
}, 'Processed device with LID priority')
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (userDevicesCache.mset) {
|
|
344
|
+
// if the cache supports mset, we can set all devices in one go
|
|
345
|
+
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })))
|
|
251
346
|
}
|
|
347
|
+
|
|
348
|
+
else {
|
|
349
|
+
for (const key in deviceMap) {
|
|
350
|
+
if (deviceMap[key])
|
|
351
|
+
await userDevicesCache.set(key, deviceMap[key])
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
252
355
|
}
|
|
253
|
-
|
|
254
356
|
return deviceResults
|
|
255
357
|
}
|
|
256
358
|
|
|
257
|
-
/** Assert Sessions */
|
|
258
359
|
const assertSessions = async (jids, force) => {
|
|
259
360
|
let didFetchNewSession = false
|
|
260
|
-
|
|
261
|
-
|
|
361
|
+
const jidsRequiringFetch = []
|
|
362
|
+
|
|
363
|
+
// Apply same deduplication as in getUSyncDevices
|
|
364
|
+
jids = deduplicateLidPnJids(jids)
|
|
365
|
+
|
|
262
366
|
if (force) {
|
|
263
|
-
|
|
367
|
+
// Check which sessions are missing (with LID migration check)
|
|
368
|
+
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid))
|
|
369
|
+
const sessions = await authState.keys.get('session', addrs)
|
|
370
|
+
|
|
371
|
+
const checkJidSession = (jid) => {
|
|
372
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid)
|
|
373
|
+
const hasSession = !!sessions[signalId]
|
|
374
|
+
|
|
375
|
+
// Add to fetch list if no session exists
|
|
376
|
+
// Session type selection (LID vs PN) is handled in encryptMessage
|
|
377
|
+
if (!hasSession) {
|
|
378
|
+
if (jid.includes('@lid')) {
|
|
379
|
+
logger.debug({ jid }, 'No LID session found, will create new LID session')
|
|
380
|
+
}
|
|
381
|
+
jidsRequiringFetch.push(jid)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Process all JIDs
|
|
386
|
+
for (const jid of jids) {
|
|
387
|
+
checkJidSession(jid)
|
|
388
|
+
}
|
|
264
389
|
}
|
|
265
|
-
|
|
266
390
|
else {
|
|
267
|
-
const addrs = jids.map(jid =>
|
|
268
|
-
|
|
391
|
+
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid))
|
|
269
392
|
const sessions = await authState.keys.get('session', addrs)
|
|
270
|
-
|
|
393
|
+
|
|
394
|
+
// Group JIDs by user for bulk migration
|
|
395
|
+
const userGroups = new Map()
|
|
271
396
|
for (const jid of jids) {
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
if (!sessions[signalId]) {
|
|
276
|
-
jidsRequiringFetch.push(jid)
|
|
397
|
+
const user = WABinary_1.jidNormalizedUser(jid)
|
|
398
|
+
if (!userGroups.has(user)) {
|
|
399
|
+
userGroups.set(user, [])
|
|
277
400
|
}
|
|
401
|
+
userGroups.get(user).push(jid)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Helper to check LID mapping for a user
|
|
405
|
+
const checkUserLidMapping = async (user, userJids) => {
|
|
406
|
+
if (!userJids.some(jid => WABinary_1.isJidUser(jid))) {
|
|
407
|
+
return { shouldMigrate: false, lidForPN: undefined }
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
try {
|
|
411
|
+
// Convert user to proper PN JID format for getLIDForPN
|
|
412
|
+
const pnJid = `${user}@s.whatsapp.net`
|
|
413
|
+
const mapping = await signalRepository.lidMapping.getLIDForPN(pnJid)
|
|
414
|
+
|
|
415
|
+
if (mapping?.includes('@lid')) {
|
|
416
|
+
logger.debug({ user, lidForPN: mapping, deviceCount: userJids.length }, 'User has LID mapping - preparing bulk migration')
|
|
417
|
+
return { shouldMigrate: true, lidForPN: mapping }
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
logger.debug({ user, error }, 'Failed to check LID mapping for user')
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return { shouldMigrate: false, lidForPN: undefined }
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Process each user group for potential bulk LID migration
|
|
428
|
+
for (const [user, userJids] of userGroups) {
|
|
429
|
+
const mappingResult = await checkUserLidMapping(user, userJids)
|
|
430
|
+
const shouldMigrateUser = mappingResult.shouldMigrate
|
|
431
|
+
const lidForPN = mappingResult.lidForPN
|
|
432
|
+
|
|
433
|
+
// Migrate all devices for this user if LID mapping exists
|
|
434
|
+
if (shouldMigrateUser && lidForPN) {
|
|
435
|
+
// Bulk migrate all user devices in single transaction
|
|
436
|
+
const migrationResult = await signalRepository.migrateSession(userJids, lidForPN)
|
|
437
|
+
|
|
438
|
+
if (migrationResult.migrated > 0) {
|
|
439
|
+
logger.info({
|
|
440
|
+
user,
|
|
441
|
+
lidMapping: lidForPN,
|
|
442
|
+
migrated: migrationResult.migrated,
|
|
443
|
+
skipped: migrationResult.skipped,
|
|
444
|
+
total: migrationResult.total
|
|
445
|
+
}, 'Completed bulk migration for user devices');
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
logger.debug({
|
|
449
|
+
user,
|
|
450
|
+
lidMapping: lidForPN,
|
|
451
|
+
skipped: migrationResult.skipped,
|
|
452
|
+
total: migrationResult.total
|
|
453
|
+
}, 'All user device sessions already migrated');
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Direct bulk session check with LID single source of truth
|
|
458
|
+
const addMissingSessionsToFetchList = (jid) => {
|
|
459
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid)
|
|
460
|
+
|
|
461
|
+
if (sessions[signalId]) return
|
|
462
|
+
|
|
463
|
+
// Determine correct JID to fetch (LID if mapping exists, otherwise original)
|
|
464
|
+
if (jid.includes('@s.whatsapp.net') && shouldMigrateUser && lidForPN) {
|
|
465
|
+
const decoded = WABinary_1.jidDecode(jid)
|
|
466
|
+
const lidDeviceJid = decoded.device !== undefined ? `${WABinary_1.jidDecode(lidForPN).user}:${decoded.device}@lid` : lidForPN
|
|
467
|
+
|
|
468
|
+
jidsRequiringFetch.push(lidDeviceJid)
|
|
469
|
+
logger.debug({ pnJid: jid, lidJid: lidDeviceJid }, 'Adding LID JID to fetch list (conversion)')
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
else {
|
|
473
|
+
jidsRequiringFetch.push(jid)
|
|
474
|
+
logger.debug({ jid }, 'Adding JID to fetch list')
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
userJids.forEach(addMissingSessionsToFetchList)
|
|
278
479
|
}
|
|
279
480
|
}
|
|
280
|
-
|
|
481
|
+
|
|
281
482
|
if (jidsRequiringFetch.length) {
|
|
282
483
|
logger.debug({ jidsRequiringFetch }, 'fetching sessions')
|
|
283
|
-
|
|
484
|
+
|
|
485
|
+
// DEBUG: Check if there are PN versions of LID users being fetched
|
|
486
|
+
const lidUsersBeingFetched = new Set()
|
|
487
|
+
const pnUsersBeingFetched = new Set()
|
|
488
|
+
|
|
489
|
+
for (const jid of jidsRequiringFetch) {
|
|
490
|
+
const user = WABinary_1.jidDecode(jid)?.user
|
|
491
|
+
|
|
492
|
+
if (user) {
|
|
493
|
+
if (WABinary_1.isLidUser(jid)) {
|
|
494
|
+
lidUsersBeingFetched.add(user)
|
|
495
|
+
}
|
|
496
|
+
else if (WABinary_1.isJidUser(jid)) {
|
|
497
|
+
pnUsersBeingFetched.add(user)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Find overlaps
|
|
503
|
+
const overlapping = Array.from(pnUsersBeingFetched).filter(user => lidUsersBeingFetched.has(user))
|
|
504
|
+
if (overlapping.length > 0) {
|
|
505
|
+
logger.warn({
|
|
506
|
+
overlapping,
|
|
507
|
+
lidUsersBeingFetched: Array.from(lidUsersBeingFetched),
|
|
508
|
+
pnUsersBeingFetched: Array.from(pnUsersBeingFetched)
|
|
509
|
+
}, 'Fetching both LID and PN sessions for same users')
|
|
510
|
+
}
|
|
511
|
+
|
|
284
512
|
const result = await query({
|
|
285
513
|
tag: 'iq',
|
|
286
514
|
attrs: {
|
|
287
515
|
xmlns: 'encrypt',
|
|
288
516
|
type: 'get',
|
|
289
|
-
to: WABinary_1.S_WHATSAPP_NET
|
|
517
|
+
to: WABinary_1.S_WHATSAPP_NET
|
|
290
518
|
},
|
|
291
519
|
content: [
|
|
292
520
|
{
|
|
@@ -294,17 +522,15 @@ const makeMessagesSocket = (config) => {
|
|
|
294
522
|
attrs: {},
|
|
295
523
|
content: jidsRequiringFetch.map(jid => ({
|
|
296
524
|
tag: 'user',
|
|
297
|
-
attrs: { jid }
|
|
525
|
+
attrs: { jid }
|
|
298
526
|
}))
|
|
299
527
|
}
|
|
300
528
|
]
|
|
301
529
|
})
|
|
302
|
-
|
|
530
|
+
|
|
303
531
|
await Utils_1.parseAndInjectE2ESessions(result, signalRepository)
|
|
304
|
-
|
|
305
532
|
didFetchNewSession = true
|
|
306
533
|
}
|
|
307
|
-
|
|
308
534
|
return didFetchNewSession
|
|
309
535
|
}
|
|
310
536
|
|
|
@@ -335,44 +561,159 @@ const makeMessagesSocket = (config) => {
|
|
|
335
561
|
return msgId
|
|
336
562
|
}
|
|
337
563
|
|
|
338
|
-
const createParticipantNodes = async (jids, message, extraAttrs) => {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
564
|
+
const createParticipantNodes = async (jids, message, extraAttrs, dsmMessage) => {
|
|
565
|
+
let patched = await patchMessageBeforeSending(message, jids)
|
|
566
|
+
|
|
567
|
+
if (!Array.isArray(patched)) {
|
|
568
|
+
patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched]
|
|
569
|
+
}
|
|
570
|
+
|
|
342
571
|
let shouldIncludeDeviceIdentity = false
|
|
343
|
-
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
572
|
+
|
|
573
|
+
const meId = authState.creds.me.id
|
|
574
|
+
const meLid = authState.creds.me?.lid
|
|
575
|
+
const meLidUser = meLid ? WABinary_1.jidDecode(meLid)?.user : null
|
|
576
|
+
const devicesByUser = new Map()
|
|
577
|
+
|
|
578
|
+
for (const patchedMessageWithJid of patched) {
|
|
579
|
+
const { recipientJid: wireJid, ...patchedMessage } = patchedMessageWithJid
|
|
580
|
+
if (!wireJid)
|
|
581
|
+
continue
|
|
582
|
+
|
|
583
|
+
// Extract user from JID for grouping
|
|
584
|
+
const decoded = WABinary_1.jidDecode(wireJid)
|
|
585
|
+
const user = decoded?.user
|
|
586
|
+
|
|
587
|
+
if (!user)
|
|
588
|
+
continue
|
|
589
|
+
|
|
590
|
+
if (!devicesByUser.has(user)) {
|
|
591
|
+
devicesByUser.set(user, []);
|
|
349
592
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
593
|
+
|
|
594
|
+
devicesByUser.get(user).push({ recipientJid: wireJid, patchedMessage })
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Process each user's devices sequentially, but different users in parallel
|
|
598
|
+
const userEncryptionPromises = Array.from(devicesByUser.entries()).map(([user, userDevices]) => encryptionMutex.mutex(user, async () => {
|
|
599
|
+
logger.debug({ user, deviceCount: userDevices.length }, 'Acquiring encryption lock for user devices');
|
|
600
|
+
const userNodes = []
|
|
601
|
+
|
|
602
|
+
// Helper to get encryption JID with LID migration
|
|
603
|
+
const getEncryptionJid = async (wireJid) => {
|
|
604
|
+
if (!WABinary_1.isJidUser(wireJid))
|
|
605
|
+
return wireJid
|
|
606
|
+
|
|
607
|
+
try {
|
|
608
|
+
const lidForPN = await signalRepository.lidMapping.getLIDForPN(wireJid)
|
|
609
|
+
|
|
610
|
+
if (!lidForPN?.includes('@lid'))
|
|
611
|
+
return wireJid
|
|
612
|
+
|
|
613
|
+
// Preserve device ID from original wire JID
|
|
614
|
+
const wireDecoded = WABinary_1.jidDecode(wireJid)
|
|
615
|
+
const deviceId = wireDecoded?.device || 0
|
|
616
|
+
const lidDecoded = WABinary_1.jidDecode(lidForPN)
|
|
617
|
+
const lidWithDevice = WABinary_1.jidEncode(lidDecoded?.user, 'lid', deviceId)
|
|
618
|
+
|
|
619
|
+
// Migrate session to LID for unified encryption layer
|
|
620
|
+
try {
|
|
621
|
+
const migrationResult = await signalRepository.migrateSession([wireJid], lidWithDevice)
|
|
622
|
+
const recipientUser = WABinary_1.jidNormalizedUser(wireJid)
|
|
623
|
+
const ownPnUser = WABinary_1.jidNormalizedUser(meId)
|
|
624
|
+
const isOwnDevice = recipientUser === ownPnUser
|
|
625
|
+
logger.info({ wireJid, lidWithDevice, isOwnDevice }, 'Migrated to LID encryption')
|
|
626
|
+
|
|
627
|
+
// Delete PN session after successful migration
|
|
628
|
+
try {
|
|
629
|
+
if (migrationResult.migrated) {
|
|
630
|
+
await signalRepository.deleteSession([wireJid])
|
|
631
|
+
logger.debug({ deletedPNSession: wireJid }, 'Deleted PN session')
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
catch (deleteError) {
|
|
635
|
+
logger.warn({ wireJid, error: deleteError }, 'Failed to delete PN session')
|
|
636
|
+
}
|
|
637
|
+
return lidWithDevice
|
|
638
|
+
}
|
|
639
|
+
catch (migrationError) {
|
|
640
|
+
logger.warn({ wireJid, error: migrationError }, 'Failed to migrate session')
|
|
641
|
+
return wireJid
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
logger.debug({ wireJid, error }, 'Failed to check LID mapping')
|
|
646
|
+
return wireJid
|
|
647
|
+
}
|
|
363
648
|
}
|
|
364
|
-
|
|
365
|
-
|
|
649
|
+
|
|
650
|
+
// Encrypt to this user's devices sequentially to prevent session corruption
|
|
651
|
+
for (const { recipientJid: wireJid, patchedMessage } of userDevices) {
|
|
652
|
+
// DSM logic: Use DSM for own other devices (following whatsmeow implementation)
|
|
653
|
+
let messageToEncrypt = patchedMessage
|
|
654
|
+
|
|
655
|
+
if (dsmMessage) {
|
|
656
|
+
const { user: targetUser } = WABinary_1.jidDecode(wireJid)
|
|
657
|
+
const { user: ownPnUser } = WABinary_1.jidDecode(meId)
|
|
658
|
+
const ownLidUser = meLidUser
|
|
659
|
+
|
|
660
|
+
// Check if this is our device (same user, different device)
|
|
661
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser)
|
|
662
|
+
|
|
663
|
+
// Exclude exact sender device (whatsmeow: if jid == ownJID || jid == ownLID { continue })
|
|
664
|
+
const isExactSenderDevice = wireJid === meId || (authState.creds.me?.lid && wireJid === authState.creds.me.lid)
|
|
665
|
+
|
|
666
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
667
|
+
messageToEncrypt = dsmMessage
|
|
668
|
+
logger.debug({ wireJid, targetUser }, 'Using DSM for own device')
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const bytes = Utils_1.encodeWAMessage(messageToEncrypt)
|
|
673
|
+
|
|
674
|
+
// Get encryption JID with LID migration
|
|
675
|
+
const encryptionJid = await getEncryptionJid(wireJid)
|
|
676
|
+
|
|
677
|
+
// ENCRYPT: Use the determined encryption identity (prefers migrated LID)
|
|
678
|
+
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
679
|
+
jid: encryptionJid, // Unified encryption layer (LID when available)
|
|
680
|
+
data: bytes
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
if (type === 'pkmsg') {
|
|
684
|
+
shouldIncludeDeviceIdentity = true
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const node = {
|
|
688
|
+
tag: 'to',
|
|
689
|
+
attrs: { jid: wireJid }, // Always use original wire identity in envelope
|
|
690
|
+
content: [
|
|
691
|
+
{
|
|
692
|
+
tag: 'enc',
|
|
693
|
+
attrs: {
|
|
694
|
+
v: '2',
|
|
695
|
+
type,
|
|
696
|
+
...(extraAttrs || {})
|
|
697
|
+
},
|
|
698
|
+
content: ciphertext
|
|
699
|
+
}
|
|
700
|
+
]
|
|
701
|
+
}
|
|
702
|
+
userNodes.push(node)
|
|
703
|
+
}
|
|
704
|
+
logger.debug({ user, nodesCreated: userNodes.length }, 'Releasing encryption lock for user devices');
|
|
705
|
+
return userNodes
|
|
366
706
|
}))
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
707
|
+
|
|
708
|
+
// Wait for all users to complete (users are processed in parallel)
|
|
709
|
+
const userNodesArrays = await Promise.all(userEncryptionPromises)
|
|
710
|
+
const nodes = userNodesArrays.flat()
|
|
711
|
+
return { nodes, shouldIncludeDeviceIdentity }
|
|
372
712
|
}
|
|
373
713
|
|
|
374
|
-
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, additionalNodes, AI =
|
|
714
|
+
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, additionalNodes, AI = false, isSecret = 0 }) => {
|
|
375
715
|
const meId = authState.creds.me.id
|
|
716
|
+
const meLid = authState.creds.me?.lid
|
|
376
717
|
|
|
377
718
|
let didPushAdditional = false
|
|
378
719
|
let shouldIncludeDeviceIdentity = false
|
|
@@ -385,13 +726,27 @@ const makeMessagesSocket = (config) => {
|
|
|
385
726
|
const isNewsletter = server == 'newsletter'
|
|
386
727
|
const isStatus = jid === statusJid
|
|
387
728
|
const isLid = server === 'lid'
|
|
729
|
+
|
|
730
|
+
// Keep user's original JID choice for envelope addressing
|
|
731
|
+
const finalJid = jid
|
|
732
|
+
|
|
733
|
+
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
734
|
+
let ownId = meId
|
|
735
|
+
|
|
736
|
+
if (isLid && meLid) {
|
|
737
|
+
ownId = meLid
|
|
738
|
+
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation')
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
|
|
742
|
+
}
|
|
388
743
|
|
|
389
744
|
msgId = msgId || Utils_1.generateMessageID(authState.creds.me.id)
|
|
390
745
|
useUserDevicesCache = useUserDevicesCache !== false
|
|
391
746
|
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
|
392
747
|
|
|
393
748
|
const participants = []
|
|
394
|
-
const destinationJid =
|
|
749
|
+
const destinationJid = !isStatus ? finalJid : statusJid
|
|
395
750
|
const binaryNodeContent = []
|
|
396
751
|
const devices = []
|
|
397
752
|
|
|
@@ -423,7 +778,11 @@ const makeMessagesSocket = (config) => {
|
|
|
423
778
|
|
|
424
779
|
const { user, device } = WABinary_1.jidDecode(participant.jid)
|
|
425
780
|
|
|
426
|
-
devices.push({
|
|
781
|
+
devices.push({
|
|
782
|
+
user,
|
|
783
|
+
device,
|
|
784
|
+
wireJid: participant.jid // Use the participant JID as wire JID
|
|
785
|
+
})
|
|
427
786
|
}
|
|
428
787
|
|
|
429
788
|
await authState.keys.transaction(async () => {
|
|
@@ -476,9 +835,10 @@ const makeMessagesSocket = (config) => {
|
|
|
476
835
|
}
|
|
477
836
|
|
|
478
837
|
if (!isStatus) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
838
|
+
const groupAddressingMode = groupData?.addressingMode || (isLid ? Types_1.WAMessageAddressingMode.LID : Types_1.WAMessageAddressingMode.PN)
|
|
839
|
+
additionalAttributes = {
|
|
840
|
+
...additionalAttributes,
|
|
841
|
+
addressing_mode: groupAddressingMode
|
|
482
842
|
}
|
|
483
843
|
}
|
|
484
844
|
|
|
@@ -488,22 +848,28 @@ const makeMessagesSocket = (config) => {
|
|
|
488
848
|
|
|
489
849
|
const patched = await patchMessageBeforeSending(message, devices.map(d => WABinary_1.jidEncode(d.user, isLid ? 'lid' : 's.whatsapp.net', d.device)))
|
|
490
850
|
const bytes = Utils_1.encodeWAMessage(patched)
|
|
851
|
+
|
|
852
|
+
// This should match the group's addressing mode and conversation context
|
|
853
|
+
const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn')
|
|
854
|
+
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId
|
|
491
855
|
|
|
492
856
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
493
857
|
group: destinationJid,
|
|
494
858
|
data: bytes,
|
|
495
|
-
meId
|
|
859
|
+
meId: groupSenderIdentity
|
|
496
860
|
})
|
|
497
861
|
|
|
498
862
|
const senderKeyJids = []
|
|
499
863
|
|
|
500
864
|
// ensure a connection is established with every device
|
|
501
|
-
for (const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
865
|
+
for (const device of devices) {
|
|
866
|
+
// This preserves the LID migration results from getUSyncDevices
|
|
867
|
+
const deviceJid = device.wireJid
|
|
868
|
+
const hasKey = !!senderKeyMap[deviceJid]
|
|
869
|
+
if (!hasKey || !!participant) {
|
|
870
|
+
senderKeyJids.push(deviceJid)
|
|
505
871
|
// store that this person has had the sender keys sent to them
|
|
506
|
-
senderKeyMap[
|
|
872
|
+
senderKeyMap[deviceJid] = true
|
|
507
873
|
}
|
|
508
874
|
}
|
|
509
875
|
|
|
@@ -554,56 +920,137 @@ const makeMessagesSocket = (config) => {
|
|
|
554
920
|
|
|
555
921
|
binaryNodeContent.push({
|
|
556
922
|
tag: 'plaintext',
|
|
557
|
-
attrs: extraAttrs
|
|
923
|
+
attrs: extraAttrs,
|
|
558
924
|
content: bytes
|
|
559
925
|
})
|
|
560
926
|
}
|
|
561
927
|
|
|
562
928
|
else {
|
|
563
|
-
const { user:
|
|
929
|
+
const { user: ownUser } = WABinary_1.jidDecode(ownId)
|
|
564
930
|
|
|
565
931
|
if (!participant) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
932
|
+
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net'
|
|
933
|
+
devices.push({
|
|
934
|
+
user,
|
|
935
|
+
device: 0,
|
|
936
|
+
wireJid: WABinary_1.jidEncode(user, targetUserServer, 0)
|
|
937
|
+
})
|
|
938
|
+
|
|
939
|
+
// Own user matches conversation addressing mode
|
|
940
|
+
if (user !== ownUser) {
|
|
941
|
+
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
942
|
+
const ownUserForAddressing = isLid && meLid ? WABinary_1.jidDecode(meLid).user : WABinary_1.jidDecode(meId).user
|
|
943
|
+
devices.push({
|
|
944
|
+
user: ownUserForAddressing,
|
|
945
|
+
device: 0,
|
|
946
|
+
wireJid: WABinary_1.jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
947
|
+
})
|
|
569
948
|
}
|
|
570
949
|
|
|
571
950
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
951
|
+
// Clear placeholders and enumerate actual devices
|
|
952
|
+
devices.length = 0
|
|
953
|
+
|
|
954
|
+
// Use conversation-appropriate sender identity
|
|
955
|
+
const senderIdentity = isLid && meLid
|
|
956
|
+
? WABinary_1.jidEncode(WABinary_1.jidDecode(meLid)?.user, 'lid', undefined)
|
|
957
|
+
: WABinary_1.jidEncode(WABinary_1.jidDecode(meId)?.user, 's.whatsapp.net', undefined)
|
|
958
|
+
|
|
959
|
+
// Enumerate devices for sender and target with consistent addressing
|
|
960
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], false, false)
|
|
961
|
+
devices.push(...sessionDevices)
|
|
962
|
+
logger.debug({
|
|
963
|
+
deviceCount: devices.length,
|
|
964
|
+
devices: devices.map(d => `${d.user}:${d.device}@${WABinary_1.jidDecode(d.wireJid)?.server}`)
|
|
965
|
+
}, 'Device enumeration complete with unified addressing')
|
|
575
966
|
}
|
|
576
967
|
}
|
|
577
968
|
|
|
578
969
|
const allJids = []
|
|
579
970
|
const meJids = []
|
|
580
971
|
const otherJids = []
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
else {
|
|
591
|
-
otherJids.push(jid)
|
|
972
|
+
|
|
973
|
+
const { user: mePnUser } = WABinary_1.jidDecode(meId)
|
|
974
|
+
const { user: meLidUser } = meLid ? WABinary_1.jidDecode(meLid) : { user: null }
|
|
975
|
+
|
|
976
|
+
for (const { user, wireJid, device } of devices) {
|
|
977
|
+
const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid)
|
|
978
|
+
if (isExactSenderDevice) {
|
|
979
|
+
logger.debug({ wireJid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
|
|
980
|
+
continue
|
|
592
981
|
}
|
|
982
|
+
|
|
983
|
+
// Check if this is our device (could match either PN or LID user)
|
|
984
|
+
const isMe = user === mePnUser || (meLidUser && user === meLidUser)
|
|
985
|
+
const jid = wireJid
|
|
986
|
+
|
|
987
|
+
// if (isMe) {
|
|
988
|
+
// meJids.push(jid)
|
|
989
|
+
// }
|
|
990
|
+
|
|
991
|
+
// else {
|
|
992
|
+
// otherJids.push(jid)
|
|
993
|
+
// }
|
|
994
|
+
|
|
995
|
+
// allJids.push(jid)
|
|
996
|
+
// }
|
|
997
|
+
|
|
998
|
+
let tatar = false;
|
|
999
|
+
|
|
1000
|
+
if (!isMe) {
|
|
1001
|
+
if (isSecret === 1 && device !== undefined) {
|
|
1002
|
+
tatar = true;
|
|
1003
|
+
} else if (isSecret === 2 && device === undefined) {
|
|
1004
|
+
tatar = true;
|
|
1005
|
+
} else if (isSecret === 5 && device === undefined) {
|
|
1006
|
+
tatar = true
|
|
1007
|
+
} else if (isSecret === 6 && device !== undefined) {
|
|
1008
|
+
tatar = true
|
|
1009
|
+
}
|
|
1010
|
+
} else {
|
|
1011
|
+
if (isSecret === 3 && device !== undefined) {
|
|
1012
|
+
tatar = true;
|
|
1013
|
+
} else if (isSecret === 4 && device === undefined) {
|
|
1014
|
+
tatar = true;
|
|
1015
|
+
} else if (isSecret === 5) {
|
|
1016
|
+
tatar = true
|
|
1017
|
+
} else if (isSecret === 6) {
|
|
1018
|
+
tatar = true
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
593
1021
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
1022
|
+
if (!tatar) {
|
|
1023
|
+
// const jid = (0, WABinary_1.jidEncode)(
|
|
1024
|
+
// isMe && isLid
|
|
1025
|
+
// ? (authState.creds?.me?.lid.split(':')[0]) || user
|
|
1026
|
+
// : user,
|
|
1027
|
+
// isLid ? 'lid' : 's.whatsapp.net',
|
|
1028
|
+
// device
|
|
1029
|
+
// );
|
|
1030
|
+
|
|
1031
|
+
if (isMe) {
|
|
1032
|
+
meJids.push(jid);
|
|
1033
|
+
} else {
|
|
1034
|
+
otherJids.push(jid);
|
|
1035
|
+
}
|
|
1036
|
+
allJids.push(jid);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
// await assertSessions([...otherJids, ...meJids], false)
|
|
1040
|
+
await assertSessions(allJids, false)
|
|
599
1041
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
600
|
-
|
|
601
|
-
createParticipantNodes(
|
|
1042
|
+
// For own devices: use DSM if available (1:1 chats only)
|
|
1043
|
+
createParticipantNodes(meJids, meMsg || message, extraAttrs),
|
|
1044
|
+
createParticipantNodes(otherJids, message, extraAttrs, meMsg)
|
|
602
1045
|
])
|
|
603
1046
|
|
|
604
1047
|
participants.push(...meNodes)
|
|
605
1048
|
|
|
606
1049
|
participants.push(...otherNodes)
|
|
1050
|
+
|
|
1051
|
+
if (meJids.length > 0 || otherJids.length > 0) {
|
|
1052
|
+
extraAttrs['phash'] = Utils_1.generateParticipantHashV2([...meJids, ...otherJids])
|
|
1053
|
+
}
|
|
607
1054
|
|
|
608
1055
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
|
609
1056
|
}
|
|
@@ -629,7 +1076,8 @@ const makeMessagesSocket = (config) => {
|
|
|
629
1076
|
const stanza = {
|
|
630
1077
|
tag: 'message',
|
|
631
1078
|
attrs: {
|
|
632
|
-
|
|
1079
|
+
to: destinationJid,
|
|
1080
|
+
id: msgId,
|
|
633
1081
|
type: getTypeMessage(message),
|
|
634
1082
|
...(additionalAttributes || {})
|
|
635
1083
|
},
|
|
@@ -731,7 +1179,12 @@ const makeMessagesSocket = (config) => {
|
|
|
731
1179
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`)
|
|
732
1180
|
|
|
733
1181
|
await sendNode(stanza)
|
|
734
|
-
|
|
1182
|
+
|
|
1183
|
+
// Add message to retry cache if enabled
|
|
1184
|
+
if (messageRetryManager && !participant) {
|
|
1185
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message)
|
|
1186
|
+
}
|
|
1187
|
+
}, meId)
|
|
735
1188
|
|
|
736
1189
|
return msgId
|
|
737
1190
|
}
|
|
@@ -756,7 +1209,7 @@ const makeMessagesSocket = (config) => {
|
|
|
756
1209
|
}
|
|
757
1210
|
|
|
758
1211
|
const getMediaType = (message) => {
|
|
759
|
-
|
|
1212
|
+
if (message.imageMessage) {
|
|
760
1213
|
return 'image'
|
|
761
1214
|
}
|
|
762
1215
|
else if (message.stickerMessage) {
|
|
@@ -771,6 +1224,9 @@ const makeMessagesSocket = (config) => {
|
|
|
771
1224
|
else if (message.ptvMessage) {
|
|
772
1225
|
return 'ptv'
|
|
773
1226
|
}
|
|
1227
|
+
else if (message.albumMessage) {
|
|
1228
|
+
return 'collection'
|
|
1229
|
+
}
|
|
774
1230
|
else if (message.contactMessage) {
|
|
775
1231
|
return 'vcard'
|
|
776
1232
|
}
|
|
@@ -850,7 +1306,11 @@ const makeMessagesSocket = (config) => {
|
|
|
850
1306
|
// Only works for WhatsApp Original, not WhatsApp Business
|
|
851
1307
|
return {
|
|
852
1308
|
tag: 'biz',
|
|
853
|
-
attrs: {
|
|
1309
|
+
attrs: {
|
|
1310
|
+
actual_actors: '2',
|
|
1311
|
+
host_storage: '2',
|
|
1312
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1313
|
+
},
|
|
854
1314
|
content: [{
|
|
855
1315
|
tag: 'interactive',
|
|
856
1316
|
attrs: {
|
|
@@ -864,13 +1324,23 @@ const makeMessagesSocket = (config) => {
|
|
|
864
1324
|
name: firstButtonName
|
|
865
1325
|
}
|
|
866
1326
|
}]
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
tag: 'quality_control',
|
|
1330
|
+
attrs: {
|
|
1331
|
+
source_type: 'third_party'
|
|
1332
|
+
}
|
|
867
1333
|
}]
|
|
868
1334
|
}
|
|
869
1335
|
} else if (nativeFlow || message.buttonsMessage) {
|
|
870
1336
|
// It works for whatsapp original and whatsapp business
|
|
871
1337
|
return {
|
|
872
1338
|
tag: 'biz',
|
|
873
|
-
attrs: {
|
|
1339
|
+
attrs: {
|
|
1340
|
+
actual_actors: '2',
|
|
1341
|
+
host_storage: '2',
|
|
1342
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1343
|
+
},
|
|
874
1344
|
content: [{
|
|
875
1345
|
tag: 'interactive',
|
|
876
1346
|
attrs: {
|
|
@@ -884,24 +1354,44 @@ const makeMessagesSocket = (config) => {
|
|
|
884
1354
|
name: 'mixed'
|
|
885
1355
|
}
|
|
886
1356
|
}]
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
tag: 'quality_control',
|
|
1360
|
+
attrs: {
|
|
1361
|
+
source_type: 'third_party'
|
|
1362
|
+
}
|
|
887
1363
|
}]
|
|
888
1364
|
}
|
|
889
1365
|
} else if (message.listMessage) {
|
|
890
1366
|
return {
|
|
891
1367
|
tag: 'biz',
|
|
892
|
-
attrs: {
|
|
1368
|
+
attrs: {
|
|
1369
|
+
actual_actors: '2',
|
|
1370
|
+
host_storage: '2',
|
|
1371
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1372
|
+
},
|
|
893
1373
|
content: [{
|
|
894
1374
|
tag: 'list',
|
|
895
1375
|
attrs: {
|
|
896
1376
|
v: '2',
|
|
897
1377
|
type: 'product_list'
|
|
898
1378
|
}
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
tag: 'quality_control',
|
|
1382
|
+
attrs: {
|
|
1383
|
+
source_type: 'third_party'
|
|
1384
|
+
}
|
|
899
1385
|
}]
|
|
900
1386
|
}
|
|
901
1387
|
} else {
|
|
902
1388
|
return {
|
|
903
1389
|
tag: 'biz',
|
|
904
|
-
attrs: {
|
|
1390
|
+
attrs: {
|
|
1391
|
+
actual_actors: '2',
|
|
1392
|
+
host_storage: '2',
|
|
1393
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1394
|
+
}
|
|
905
1395
|
}
|
|
906
1396
|
}
|
|
907
1397
|
}
|
|
@@ -966,7 +1456,8 @@ const makeMessagesSocket = (config) => {
|
|
|
966
1456
|
waUploadToServer,
|
|
967
1457
|
getEphemeralGroup,
|
|
968
1458
|
fetchPrivacySettings,
|
|
969
|
-
|
|
1459
|
+
messageRetryManager,
|
|
1460
|
+
createParticipantNodes,
|
|
970
1461
|
sendPeerDataOperationMessage,
|
|
971
1462
|
updateMediaMessage: async (message) => {
|
|
972
1463
|
const content = Utils_1.assertMediaContent(message.message)
|