@periskope/baileys 7.0.0-alpha-7 → 7.0.0-alpha-9
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 +3 -0
- package/lib/Defaults/index.js +1 -1
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/Group/group_cipher.d.ts +1 -1
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
- package/lib/Signal/Group/group_cipher.js +1 -4
- package/lib/Signal/Group/group_cipher.js.map +1 -1
- package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -1
- package/lib/Signal/Group/sender-chain-key.js +1 -13
- package/lib/Signal/Group/sender-chain-key.js.map +1 -1
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-distribution-message.js +6 -11
- package/lib/Signal/Group/sender-key-distribution-message.js.map +1 -1
- package/lib/Signal/Group/sender-key-message.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-message.js +3 -5
- package/lib/Signal/Group/sender-key-message.js.map +1 -1
- package/lib/Signal/Group/sender-key-record.d.ts +1 -1
- package/lib/Signal/Group/sender-key-record.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-record.js +2 -11
- package/lib/Signal/Group/sender-key-record.js.map +1 -1
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-state.js +9 -52
- package/lib/Signal/Group/sender-key-state.js.map +1 -1
- package/lib/Signal/libsignal.d.ts +2 -5
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +109 -88
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +3 -6
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +19 -33
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/business.d.ts +2 -2
- package/lib/Socket/communities.d.ts +2 -2
- package/lib/Socket/index.d.ts +2 -2
- package/lib/Socket/messages-recv.d.ts +2 -2
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +10 -31
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +2 -2
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +125 -280
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +22 -9
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +1 -0
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Signal.d.ts +1 -11
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Types/Socket.d.ts +1 -1
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +1 -1
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/browser-utils.d.ts +4 -0
- package/lib/Utils/browser-utils.d.ts.map +1 -0
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/browser-utils.js.map +1 -0
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +6 -5
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +8 -5
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/generics.d.ts +1 -3
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +11 -29
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +2 -1
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/index.d.ts +2 -0
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +2 -0
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +2 -1
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +3 -2
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/noise-handler.d.ts.map +1 -1
- package/lib/Utils/noise-handler.js +2 -1
- package/lib/Utils/noise-handler.js.map +1 -1
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +8 -2
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/proto-utils.d.ts +7 -0
- package/lib/Utils/proto-utils.d.ts.map +1 -0
- package/lib/Utils/proto-utils.js +7 -0
- package/lib/Utils/proto-utils.js.map +1 -0
- package/lib/Utils/signal.d.ts.map +1 -1
- package/lib/Utils/signal.js.map +1 -1
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +4 -3
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/generic-utils.d.ts.map +1 -1
- package/lib/WABinary/generic-utils.js +2 -1
- package/lib/WABinary/generic-utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -18,6 +18,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
18
18
|
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
19
19
|
useClones: false
|
|
20
20
|
});
|
|
21
|
+
const peerSessionsCache = new NodeCache({
|
|
22
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
23
|
+
useClones: false
|
|
24
|
+
});
|
|
21
25
|
// Initialize message retry manager if enabled
|
|
22
26
|
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
23
27
|
// Prevent race conditions in Signal session encryption by user
|
|
@@ -113,33 +117,28 @@ export const makeMessagesSocket = (config) => {
|
|
|
113
117
|
const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self';
|
|
114
118
|
await sendReceipts(keys, readType);
|
|
115
119
|
};
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const deduplicateLidPnJids = (jids) => {
|
|
121
|
-
const lidUsers = new Set();
|
|
122
|
-
const filteredJids = [];
|
|
123
|
-
// Collect all LID users
|
|
124
|
-
for (const jid of jids) {
|
|
125
|
-
if (jid.includes('@lid')) {
|
|
126
|
-
const user = jidDecode(jid)?.user;
|
|
127
|
-
if (user)
|
|
128
|
-
lidUsers.add(user);
|
|
129
|
-
}
|
|
120
|
+
const resolveSessionJids = async (jids) => {
|
|
121
|
+
const uniquePnJids = Array.from(new Set(jids.filter(isPnUser)));
|
|
122
|
+
if (!uniquePnJids.length) {
|
|
123
|
+
return new Map();
|
|
130
124
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
125
|
+
const lookups = await Promise.all(uniquePnJids.map(async (pnJid) => {
|
|
126
|
+
try {
|
|
127
|
+
const resolved = await signalRepository.lidMapping.getLIDForPN(pnJid);
|
|
128
|
+
return resolved ? [pnJid, resolved] : [pnJid, pnJid];
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
logger.warn({ pnJid, error }, 'Failed to resolve LID mapping for PN JID');
|
|
132
|
+
return [pnJid, pnJid];
|
|
133
|
+
}
|
|
134
|
+
}));
|
|
135
|
+
const sessionMap = new Map();
|
|
136
|
+
for (const entry of lookups) {
|
|
137
|
+
if (entry) {
|
|
138
|
+
sessionMap.set(entry[0], entry[1]);
|
|
139
139
|
}
|
|
140
|
-
filteredJids.push(jid);
|
|
141
140
|
}
|
|
142
|
-
return
|
|
141
|
+
return sessionMap;
|
|
143
142
|
};
|
|
144
143
|
/** Fetch all the devices we've to send a message to */
|
|
145
144
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
@@ -148,7 +147,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
148
147
|
logger.debug('not using cache for devices');
|
|
149
148
|
}
|
|
150
149
|
const toFetch = [];
|
|
151
|
-
jids = deduplicateLidPnJids(Array.from(new Set(jids)));
|
|
152
150
|
const jidsWithUser = jids
|
|
153
151
|
.map(jid => {
|
|
154
152
|
const decoded = jidDecode(jid);
|
|
@@ -246,139 +244,49 @@ export const makeMessagesSocket = (config) => {
|
|
|
246
244
|
await userDevicesCache.set(key, deviceMap[key]);
|
|
247
245
|
}
|
|
248
246
|
}
|
|
247
|
+
const userDeviceUpdates = {};
|
|
248
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
249
|
+
if (devices && devices.length > 0) {
|
|
250
|
+
userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
254
|
+
try {
|
|
255
|
+
await authState.keys.set({ 'device-list': userDeviceUpdates });
|
|
256
|
+
logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration');
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
logger.warn({ error }, 'failed to store user device lists');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
249
262
|
}
|
|
250
263
|
return deviceResults;
|
|
251
264
|
};
|
|
252
|
-
const assertSessions = async (jids
|
|
265
|
+
const assertSessions = async (jids) => {
|
|
253
266
|
let didFetchNewSession = false;
|
|
267
|
+
const uniqueJids = [...new Set(jids)]; // Deduplicate JIDs
|
|
254
268
|
const jidsRequiringFetch = [];
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const checkJidSession = (jid) => {
|
|
263
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
264
|
-
const hasSession = !!sessions[signalId];
|
|
265
|
-
// Add to fetch list if no session exists
|
|
266
|
-
// Session type selection (LID vs PN) is handled in encryptMessage
|
|
267
|
-
if (!hasSession) {
|
|
268
|
-
if (jid.includes('@lid')) {
|
|
269
|
-
logger.debug({ jid }, 'No LID session found, will create new LID session');
|
|
270
|
-
}
|
|
271
|
-
jidsRequiringFetch.push(jid);
|
|
269
|
+
// Check peerSessionsCache and authState.keys
|
|
270
|
+
for (const jid of uniqueJids) {
|
|
271
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
272
|
+
const cachedSession = peerSessionsCache.get(signalId);
|
|
273
|
+
if (cachedSession !== undefined) {
|
|
274
|
+
if (cachedSession) {
|
|
275
|
+
continue; // Session exists in cache
|
|
272
276
|
}
|
|
273
|
-
};
|
|
274
|
-
// Process all JIDs
|
|
275
|
-
for (const jid of jids) {
|
|
276
|
-
checkJidSession(jid);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid));
|
|
281
|
-
const sessions = await authState.keys.get('session', addrs);
|
|
282
|
-
// Group JIDs by user for bulk migration
|
|
283
|
-
const userGroups = new Map();
|
|
284
|
-
for (const jid of jids) {
|
|
285
|
-
const user = jidNormalizedUser(jid);
|
|
286
|
-
if (!userGroups.has(user)) {
|
|
287
|
-
userGroups.set(user, []);
|
|
288
|
-
}
|
|
289
|
-
userGroups.get(user).push(jid);
|
|
290
277
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
// Convert user to proper PN JID format for getLIDForPN
|
|
298
|
-
const pnJid = `${user}@s.whatsapp.net`;
|
|
299
|
-
const mapping = await signalRepository.lidMapping.getLIDForPN(pnJid);
|
|
300
|
-
if (mapping?.includes('@lid')) {
|
|
301
|
-
logger.debug({ user, lidForPN: mapping, deviceCount: userJids.length }, 'User has LID mapping - preparing bulk migration');
|
|
302
|
-
return { shouldMigrate: true, lidForPN: mapping };
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
catch (error) {
|
|
306
|
-
logger.debug({ user, error }, 'Failed to check LID mapping for user');
|
|
307
|
-
}
|
|
308
|
-
return { shouldMigrate: false, lidForPN: undefined };
|
|
309
|
-
};
|
|
310
|
-
// Process each user group for potential bulk LID migration
|
|
311
|
-
for (const [user, userJids] of userGroups) {
|
|
312
|
-
const mappingResult = await checkUserLidMapping(user, userJids);
|
|
313
|
-
const shouldMigrateUser = mappingResult.shouldMigrate;
|
|
314
|
-
const lidForPN = mappingResult.lidForPN;
|
|
315
|
-
// Migrate all devices for this user if LID mapping exists
|
|
316
|
-
if (shouldMigrateUser && lidForPN) {
|
|
317
|
-
// Bulk migrate all user devices in single transaction
|
|
318
|
-
const migrationResult = await signalRepository.migrateSession(userJids, lidForPN);
|
|
319
|
-
if (migrationResult.migrated > 0) {
|
|
320
|
-
logger.info({
|
|
321
|
-
user,
|
|
322
|
-
lidMapping: lidForPN,
|
|
323
|
-
migrated: migrationResult.migrated,
|
|
324
|
-
skipped: migrationResult.skipped,
|
|
325
|
-
total: migrationResult.total
|
|
326
|
-
}, 'Completed bulk migration for user devices');
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
logger.debug({
|
|
330
|
-
user,
|
|
331
|
-
lidMapping: lidForPN,
|
|
332
|
-
skipped: migrationResult.skipped,
|
|
333
|
-
total: migrationResult.total
|
|
334
|
-
}, 'All user device sessions already migrated');
|
|
335
|
-
}
|
|
278
|
+
else {
|
|
279
|
+
const sessions = await authState.keys.get('session', [signalId]);
|
|
280
|
+
const hasSession = !!sessions[signalId];
|
|
281
|
+
peerSessionsCache.set(signalId, hasSession);
|
|
282
|
+
if (hasSession) {
|
|
283
|
+
continue;
|
|
336
284
|
}
|
|
337
|
-
// Direct bulk session check with LID single source of truth
|
|
338
|
-
const addMissingSessionsToFetchList = (jid) => {
|
|
339
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
340
|
-
if (sessions[signalId])
|
|
341
|
-
return;
|
|
342
|
-
// Determine correct JID to fetch (LID if mapping exists, otherwise original)
|
|
343
|
-
if (jid.includes('@s.whatsapp.net') && shouldMigrateUser && lidForPN) {
|
|
344
|
-
const decoded = jidDecode(jid);
|
|
345
|
-
const lidDeviceJid = decoded.device !== undefined ? `${jidDecode(lidForPN).user}:${decoded.device}@lid` : lidForPN;
|
|
346
|
-
jidsRequiringFetch.push(lidDeviceJid);
|
|
347
|
-
logger.debug({ pnJid: jid, lidJid: lidDeviceJid }, 'Adding LID JID to fetch list (conversion)');
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
jidsRequiringFetch.push(jid);
|
|
351
|
-
logger.debug({ jid }, 'Adding JID to fetch list');
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
userJids.forEach(addMissingSessionsToFetchList);
|
|
355
285
|
}
|
|
286
|
+
jidsRequiringFetch.push(jid);
|
|
356
287
|
}
|
|
357
288
|
if (jidsRequiringFetch.length) {
|
|
358
289
|
logger.debug({ jidsRequiringFetch }, 'fetching sessions');
|
|
359
|
-
// DEBUG: Check if there are PN versions of LID users being fetched
|
|
360
|
-
const lidUsersBeingFetched = new Set();
|
|
361
|
-
const pnUsersBeingFetched = new Set();
|
|
362
|
-
for (const jid of jidsRequiringFetch) {
|
|
363
|
-
const user = jidDecode(jid)?.user;
|
|
364
|
-
if (user) {
|
|
365
|
-
if (jid.includes('@lid')) {
|
|
366
|
-
lidUsersBeingFetched.add(user);
|
|
367
|
-
}
|
|
368
|
-
else if (jid.includes('@s.whatsapp.net')) {
|
|
369
|
-
pnUsersBeingFetched.add(user);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
// Find overlaps
|
|
374
|
-
const overlapping = Array.from(pnUsersBeingFetched).filter(user => lidUsersBeingFetched.has(user));
|
|
375
|
-
if (overlapping.length > 0) {
|
|
376
|
-
logger.warn({
|
|
377
|
-
overlapping,
|
|
378
|
-
lidUsersBeingFetched: Array.from(lidUsersBeingFetched),
|
|
379
|
-
pnUsersBeingFetched: Array.from(pnUsersBeingFetched)
|
|
380
|
-
}, 'Fetching both LID and PN sessions for same users');
|
|
381
|
-
}
|
|
382
290
|
const result = await query({
|
|
383
291
|
tag: 'iq',
|
|
384
292
|
attrs: {
|
|
@@ -399,6 +307,11 @@ export const makeMessagesSocket = (config) => {
|
|
|
399
307
|
});
|
|
400
308
|
await parseAndInjectE2ESessions(result, signalRepository);
|
|
401
309
|
didFetchNewSession = true;
|
|
310
|
+
// Cache fetched sessions
|
|
311
|
+
for (const jid of jidsRequiringFetch) {
|
|
312
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
313
|
+
peerSessionsCache.set(signalId, true);
|
|
314
|
+
}
|
|
402
315
|
}
|
|
403
316
|
return didFetchNewSession;
|
|
404
317
|
};
|
|
@@ -422,107 +335,47 @@ export const makeMessagesSocket = (config) => {
|
|
|
422
335
|
});
|
|
423
336
|
return msgId;
|
|
424
337
|
};
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
338
|
+
const createParticipantNodesWithSessionMap = async (recipientWireJids, sessionMap, message, extraAttrs, dsmMessage) => {
|
|
339
|
+
if (!recipientWireJids.length) {
|
|
340
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
341
|
+
}
|
|
342
|
+
const patched = await patchMessageBeforeSending(message, recipientWireJids);
|
|
343
|
+
const patchedMessages = Array.isArray(patched)
|
|
344
|
+
? patched
|
|
345
|
+
: recipientWireJids.map(jid => ({ recipientJid: jid, message: patched }));
|
|
430
346
|
let shouldIncludeDeviceIdentity = false;
|
|
431
347
|
const meId = authState.creds.me.id;
|
|
432
348
|
const meLid = authState.creds.me?.lid;
|
|
433
349
|
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
434
|
-
const
|
|
435
|
-
for (const patchedMessageWithJid of patched) {
|
|
436
|
-
const { recipientJid: wireJid, ...patchedMessage } = patchedMessageWithJid;
|
|
350
|
+
const encryptionPromises = patchedMessages.map(async ({ recipientJid: wireJid, message: patchedMessage }) => {
|
|
437
351
|
if (!wireJid)
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
const
|
|
455
|
-
if (!wireJid.includes('@s.whatsapp.net'))
|
|
456
|
-
return wireJid;
|
|
457
|
-
try {
|
|
458
|
-
const lidForPN = await signalRepository.lidMapping.getLIDForPN(wireJid);
|
|
459
|
-
if (!lidForPN?.includes('@lid'))
|
|
460
|
-
return wireJid;
|
|
461
|
-
// Preserve device ID from original wire JID
|
|
462
|
-
const wireDecoded = jidDecode(wireJid);
|
|
463
|
-
const deviceId = wireDecoded?.device || 0;
|
|
464
|
-
const lidDecoded = jidDecode(lidForPN);
|
|
465
|
-
const lidWithDevice = jidEncode(lidDecoded?.user, 'lid', deviceId);
|
|
466
|
-
// Migrate session to LID for unified encryption layer
|
|
467
|
-
try {
|
|
468
|
-
const migrationResult = await signalRepository.migrateSession([wireJid], lidWithDevice);
|
|
469
|
-
const recipientUser = jidNormalizedUser(wireJid);
|
|
470
|
-
const ownPnUser = jidNormalizedUser(meId);
|
|
471
|
-
const isOwnDevice = recipientUser === ownPnUser;
|
|
472
|
-
logger.info({ wireJid, lidWithDevice, isOwnDevice }, 'Migrated to LID encryption');
|
|
473
|
-
// Delete PN session after successful migration
|
|
474
|
-
try {
|
|
475
|
-
if (migrationResult.migrated) {
|
|
476
|
-
await signalRepository.deleteSession([wireJid]);
|
|
477
|
-
logger.debug({ deletedPNSession: wireJid }, 'Deleted PN session');
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
catch (deleteError) {
|
|
481
|
-
logger.warn({ wireJid, error: deleteError }, 'Failed to delete PN session');
|
|
482
|
-
}
|
|
483
|
-
return lidWithDevice;
|
|
484
|
-
}
|
|
485
|
-
catch (migrationError) {
|
|
486
|
-
logger.warn({ wireJid, error: migrationError }, 'Failed to migrate session');
|
|
487
|
-
return wireJid;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
catch (error) {
|
|
491
|
-
logger.debug({ wireJid, error }, 'Failed to check LID mapping');
|
|
492
|
-
return wireJid;
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
// Encrypt to this user's devices sequentially to prevent session corruption
|
|
496
|
-
for (const { recipientJid: wireJid, patchedMessage } of userDevices) {
|
|
497
|
-
// DSM logic: Use DSM for own other devices (following whatsmeow implementation)
|
|
498
|
-
let messageToEncrypt = patchedMessage;
|
|
499
|
-
if (dsmMessage) {
|
|
500
|
-
const { user: targetUser } = jidDecode(wireJid);
|
|
501
|
-
const { user: ownPnUser } = jidDecode(meId);
|
|
502
|
-
const ownLidUser = meLidUser;
|
|
503
|
-
// Check if this is our device (same user, different device)
|
|
504
|
-
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
505
|
-
// Exclude exact sender device (whatsmeow: if jid == ownJID || jid == ownLID { continue })
|
|
506
|
-
const isExactSenderDevice = wireJid === meId || (authState.creds.me?.lid && wireJid === authState.creds.me.lid);
|
|
507
|
-
if (isOwnUser && !isExactSenderDevice) {
|
|
508
|
-
messageToEncrypt = dsmMessage;
|
|
509
|
-
logger.debug({ wireJid, targetUser }, 'Using DSM for own device');
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
const bytes = encodeWAMessage(messageToEncrypt);
|
|
513
|
-
// Get encryption JID with LID migration
|
|
514
|
-
const encryptionJid = await getEncryptionJid(wireJid);
|
|
515
|
-
// ENCRYPT: Use the determined encryption identity (prefers migrated LID)
|
|
352
|
+
return null;
|
|
353
|
+
wireJid = sessionMap.get(wireJid) ?? wireJid;
|
|
354
|
+
let msgToEncrypt = patchedMessage;
|
|
355
|
+
if (dsmMessage) {
|
|
356
|
+
const { user: targetUser } = jidDecode(wireJid);
|
|
357
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
358
|
+
const ownLidUser = meLidUser;
|
|
359
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
360
|
+
const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid);
|
|
361
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
362
|
+
msgToEncrypt = dsmMessage;
|
|
363
|
+
logger.debug({ wireJid, targetUser }, 'Using DSM for own device');
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
367
|
+
const mutexKey = wireJid;
|
|
368
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
516
369
|
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
517
|
-
jid:
|
|
370
|
+
jid: wireJid,
|
|
518
371
|
data: bytes
|
|
519
372
|
});
|
|
520
373
|
if (type === 'pkmsg') {
|
|
521
374
|
shouldIncludeDeviceIdentity = true;
|
|
522
375
|
}
|
|
523
|
-
|
|
376
|
+
return {
|
|
524
377
|
tag: 'to',
|
|
525
|
-
attrs: { jid: wireJid },
|
|
378
|
+
attrs: { jid: wireJid },
|
|
526
379
|
content: [
|
|
527
380
|
{
|
|
528
381
|
tag: 'enc',
|
|
@@ -535,28 +388,26 @@ export const makeMessagesSocket = (config) => {
|
|
|
535
388
|
}
|
|
536
389
|
]
|
|
537
390
|
};
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}));
|
|
543
|
-
// Wait for all users to complete (users are processed in parallel)
|
|
544
|
-
const userNodesArrays = await Promise.all(userEncryptionPromises);
|
|
545
|
-
const nodes = userNodesArrays.flat();
|
|
391
|
+
});
|
|
392
|
+
return node;
|
|
393
|
+
});
|
|
394
|
+
const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
|
|
546
395
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
547
396
|
};
|
|
397
|
+
const createParticipantNodes = async (recipientWireJids, message, extraAttrs, dsmMessage) => {
|
|
398
|
+
const sessionMap = await resolveSessionJids(recipientWireJids);
|
|
399
|
+
return createParticipantNodesWithSessionMap(recipientWireJids, sessionMap, message, extraAttrs, dsmMessage);
|
|
400
|
+
};
|
|
548
401
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
549
402
|
const meId = authState.creds.me.id;
|
|
550
403
|
const meLid = authState.creds.me?.lid;
|
|
551
|
-
// ADDRESSING CONSISTENCY: Keep envelope addressing as user provided, handle LID migration in encryption
|
|
552
404
|
let shouldIncludeDeviceIdentity = false;
|
|
553
|
-
const { user, server } = jidDecode(jid);
|
|
554
405
|
const statusJid = 'status@broadcast';
|
|
406
|
+
const { user, server } = jidDecode(jid);
|
|
555
407
|
const isGroup = server === 'g.us';
|
|
556
408
|
const isStatus = jid === statusJid;
|
|
557
409
|
const isLid = server === 'lid';
|
|
558
410
|
const isNewsletter = server === 'newsletter';
|
|
559
|
-
// Keep user's original JID choice for envelope addressing
|
|
560
411
|
const finalJid = jid;
|
|
561
412
|
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
562
413
|
// TODO: investigate if this is true
|
|
@@ -584,17 +435,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
584
435
|
};
|
|
585
436
|
const extraAttrs = {};
|
|
586
437
|
if (participant) {
|
|
587
|
-
// when the retry request is not for a group
|
|
588
|
-
// only send to the specific device that asked for a retry
|
|
589
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
590
438
|
if (!isGroup && !isStatus) {
|
|
591
439
|
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
|
|
592
440
|
}
|
|
593
|
-
const { user, device } = jidDecode(participant.jid);
|
|
441
|
+
const { user, device } = jidDecode(participant.jid);
|
|
594
442
|
devices.push({
|
|
595
443
|
user,
|
|
596
444
|
device,
|
|
597
|
-
wireJid: participant.jid
|
|
445
|
+
wireJid: participant.jid
|
|
598
446
|
});
|
|
599
447
|
}
|
|
600
448
|
await authState.keys.transaction(async () => {
|
|
@@ -603,7 +451,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
603
451
|
extraAttrs['mediatype'] = mediaType;
|
|
604
452
|
}
|
|
605
453
|
if (isNewsletter) {
|
|
606
|
-
// Patch message if needed, then encode as plaintext
|
|
607
454
|
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
608
455
|
const bytes = encodeNewsletterMessage(patched);
|
|
609
456
|
binaryNodeContent.push({
|
|
@@ -668,7 +515,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
668
515
|
throw new Boom('Per-jid patching is not supported in groups');
|
|
669
516
|
}
|
|
670
517
|
const bytes = encodeWAMessage(patched);
|
|
671
|
-
// This should match the group's addressing mode and conversation context
|
|
672
518
|
const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn');
|
|
673
519
|
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
674
520
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
@@ -676,30 +522,27 @@ export const makeMessagesSocket = (config) => {
|
|
|
676
522
|
data: bytes,
|
|
677
523
|
meId: groupSenderIdentity
|
|
678
524
|
});
|
|
679
|
-
const
|
|
680
|
-
|
|
525
|
+
const deviceSessionMap = await resolveSessionJids(devices.map(d => d.wireJid));
|
|
526
|
+
const senderKeyRecipients = [];
|
|
681
527
|
for (const device of devices) {
|
|
682
|
-
// This preserves the LID migration results from getUSyncDevices
|
|
683
528
|
const deviceJid = device.wireJid;
|
|
684
529
|
const hasKey = !!senderKeyMap[deviceJid];
|
|
685
530
|
if (!hasKey || !!participant) {
|
|
686
|
-
|
|
687
|
-
// store that this person has had the sender keys sent to them
|
|
531
|
+
senderKeyRecipients.push(deviceJid);
|
|
688
532
|
senderKeyMap[deviceJid] = true;
|
|
689
533
|
}
|
|
690
534
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
if (senderKeyJids.length) {
|
|
694
|
-
logger.debug({ senderKeyJids }, 'sending new sender key');
|
|
535
|
+
if (senderKeyRecipients.length) {
|
|
536
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
|
|
695
537
|
const senderKeyMsg = {
|
|
696
538
|
senderKeyDistributionMessage: {
|
|
697
539
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
698
540
|
groupId: destinationJid
|
|
699
541
|
}
|
|
700
542
|
};
|
|
701
|
-
|
|
702
|
-
|
|
543
|
+
const senderKeySessionTargets = senderKeyRecipients.map(jid => deviceSessionMap.get(jid) ?? jid);
|
|
544
|
+
await assertSessions(senderKeySessionTargets);
|
|
545
|
+
const result = await createParticipantNodesWithSessionMap(senderKeyRecipients, deviceSessionMap, senderKeyMsg, extraAttrs);
|
|
703
546
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
704
547
|
participants.push(...result.nodes);
|
|
705
548
|
}
|
|
@@ -737,7 +580,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
737
580
|
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
738
581
|
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
739
582
|
// Enumerate devices for sender and target with consistent addressing
|
|
740
|
-
const sessionDevices = await getUSyncDevices([senderIdentity, jid],
|
|
583
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
741
584
|
devices.push(...sessionDevices);
|
|
742
585
|
logger.debug({
|
|
743
586
|
deviceCount: devices.length,
|
|
@@ -745,9 +588,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
745
588
|
}, 'Device enumeration complete with unified addressing');
|
|
746
589
|
}
|
|
747
590
|
}
|
|
748
|
-
const
|
|
749
|
-
const
|
|
750
|
-
const
|
|
591
|
+
const allRecipients = [];
|
|
592
|
+
const meRecipients = [];
|
|
593
|
+
const otherRecipients = [];
|
|
751
594
|
const { user: mePnUser } = jidDecode(meId);
|
|
752
595
|
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
|
|
753
596
|
for (const { user, wireJid } of devices) {
|
|
@@ -758,25 +601,26 @@ export const makeMessagesSocket = (config) => {
|
|
|
758
601
|
}
|
|
759
602
|
// Check if this is our device (could match either PN or LID user)
|
|
760
603
|
const isMe = user === mePnUser || (meLidUser && user === meLidUser);
|
|
761
|
-
const jid = wireJid;
|
|
762
604
|
if (isMe) {
|
|
763
|
-
|
|
605
|
+
meRecipients.push(wireJid);
|
|
764
606
|
}
|
|
765
607
|
else {
|
|
766
|
-
|
|
608
|
+
otherRecipients.push(wireJid);
|
|
767
609
|
}
|
|
768
|
-
|
|
610
|
+
allRecipients.push(wireJid);
|
|
769
611
|
}
|
|
770
|
-
await
|
|
612
|
+
const deviceSessionMap = await resolveSessionJids(devices.map(d => d.wireJid));
|
|
613
|
+
const sessionTargets = allRecipients.map(jid => deviceSessionMap.get(jid) ?? jid);
|
|
614
|
+
await assertSessions(sessionTargets);
|
|
771
615
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
772
616
|
// For own devices: use DSM if available (1:1 chats only)
|
|
773
|
-
|
|
774
|
-
|
|
617
|
+
createParticipantNodesWithSessionMap(meRecipients, deviceSessionMap, meMsg || message, extraAttrs),
|
|
618
|
+
createParticipantNodesWithSessionMap(otherRecipients, deviceSessionMap, message, extraAttrs, meMsg)
|
|
775
619
|
]);
|
|
776
620
|
participants.push(...meNodes);
|
|
777
621
|
participants.push(...otherNodes);
|
|
778
|
-
if (
|
|
779
|
-
extraAttrs['phash'] = generateParticipantHashV2([...
|
|
622
|
+
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
623
|
+
extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
|
|
780
624
|
}
|
|
781
625
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
782
626
|
}
|
|
@@ -853,6 +697,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
853
697
|
if (message.eventMessage) {
|
|
854
698
|
return 'event';
|
|
855
699
|
}
|
|
700
|
+
if (getMediaType(message) !== 'text') {
|
|
701
|
+
return 'media';
|
|
702
|
+
}
|
|
856
703
|
return 'text';
|
|
857
704
|
};
|
|
858
705
|
const getMediaType = (message) => {
|
|
@@ -901,6 +748,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
901
748
|
else if (message.groupInviteMessage) {
|
|
902
749
|
return 'url';
|
|
903
750
|
}
|
|
751
|
+
return 'text';
|
|
904
752
|
};
|
|
905
753
|
const getPrivacyTokens = async (jids) => {
|
|
906
754
|
const t = unixTimestampSeconds().toString();
|
|
@@ -1062,9 +910,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
1062
910
|
}
|
|
1063
911
|
});
|
|
1064
912
|
}
|
|
1065
|
-
if ('cachedGroupMetadata' in options) {
|
|
1066
|
-
console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.');
|
|
1067
|
-
}
|
|
1068
913
|
await relayMessage(jid, fullMsg.message, {
|
|
1069
914
|
messageId: fullMsg.key.id,
|
|
1070
915
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|