@periskope/baileys 7.0.0-beta-1 → 7.0.0-beta-2
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/lib/Defaults/index.d.ts +0 -5
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +2 -8
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/Group/queue-job.d.ts +0 -1
- package/lib/Signal/Group/queue-job.d.ts.map +1 -1
- package/lib/Signal/Group/queue-job.js +0 -3
- package/lib/Signal/Group/queue-job.js.map +1 -1
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-state.js +1 -6
- package/lib/Signal/Group/sender-key-state.js.map +1 -1
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +9 -147
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Socket/business.d.ts +7 -18
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/business.js +1 -122
- package/lib/Socket/business.js.map +1 -1
- package/lib/Socket/chats.d.ts +2 -8
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +1 -38
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +4 -17
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/communities.js +0 -44
- package/lib/Socket/communities.js.map +1 -1
- package/lib/Socket/groups.d.ts +2 -7
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/index.d.ts +4 -17
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/messages-recv.d.ts +4 -11
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +7 -70
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +4 -11
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +55 -443
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +2 -7
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/socket.d.ts +2 -2
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +24 -146
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Socket/usync.d.ts +2 -2
- package/lib/Types/Auth.d.ts +0 -1
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Chat.d.ts +0 -3
- package/lib/Types/Chat.d.ts.map +1 -1
- package/lib/Types/Chat.js.map +1 -1
- package/lib/Types/Message.d.ts +1 -21
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Signal.d.ts +0 -20
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +0 -17
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +0 -5
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +3 -51
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +1 -4
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +1 -21
- package/lib/Utils/messages.js.map +1 -1
- package/package.json +2 -4
|
@@ -4,7 +4,6 @@ import { proto } from '../../WAProto/index.js';
|
|
|
4
4
|
import { DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
5
5
|
import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
|
|
6
6
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
7
|
-
import { makeKeyedMutex } from '../Utils/make-mutex.js';
|
|
8
7
|
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isJidUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
9
8
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
10
9
|
import { makeGroupsSocket } from './groups.js';
|
|
@@ -18,8 +17,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
18
17
|
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
19
18
|
useClones: false
|
|
20
19
|
});
|
|
21
|
-
// Prevent race conditions in Signal session encryption by user
|
|
22
|
-
const encryptionMutex = makeKeyedMutex();
|
|
23
20
|
let mediaConn;
|
|
24
21
|
const refreshMediaConn = async (forceGet = false) => {
|
|
25
22
|
const media = await mediaConn;
|
|
@@ -111,34 +108,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
111
108
|
const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self';
|
|
112
109
|
await sendReceipts(keys, readType);
|
|
113
110
|
};
|
|
114
|
-
/**
|
|
115
|
-
* Deduplicate JIDs when both LID and PN versions exist for same user
|
|
116
|
-
* Prefers LID over PN to maintain single encryption layer
|
|
117
|
-
*/
|
|
118
|
-
const deduplicateLidPnJids = (jids) => {
|
|
119
|
-
const lidUsers = new Set();
|
|
120
|
-
const filteredJids = [];
|
|
121
|
-
// Collect all LID users
|
|
122
|
-
for (const jid of jids) {
|
|
123
|
-
if (jid.includes('@lid')) {
|
|
124
|
-
const user = jidDecode(jid)?.user;
|
|
125
|
-
if (user)
|
|
126
|
-
lidUsers.add(user);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// Filter out PN versions when LID exists
|
|
130
|
-
for (const jid of jids) {
|
|
131
|
-
if (jid.includes('@s.whatsapp.net')) {
|
|
132
|
-
const user = jidDecode(jid)?.user;
|
|
133
|
-
if (user && lidUsers.has(user)) {
|
|
134
|
-
logger.debug({ jid }, 'Skipping PN - LID version exists');
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
filteredJids.push(jid);
|
|
139
|
-
}
|
|
140
|
-
return filteredJids;
|
|
141
|
-
};
|
|
142
111
|
/** Fetch all the devices we've to send a message to */
|
|
143
112
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
144
113
|
const deviceResults = [];
|
|
@@ -146,33 +115,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
146
115
|
logger.debug('not using cache for devices');
|
|
147
116
|
}
|
|
148
117
|
const toFetch = [];
|
|
149
|
-
|
|
150
|
-
jids = deduplicateLidPnJids(Array.from(new Set(jids)));
|
|
118
|
+
jids = Array.from(new Set(jids));
|
|
151
119
|
for (let jid of jids) {
|
|
152
|
-
const
|
|
153
|
-
const user = decoded?.user;
|
|
154
|
-
const device = decoded?.device;
|
|
155
|
-
const isExplicitDevice = typeof device === 'number' && device >= 0;
|
|
156
|
-
// Handle explicit device JIDs directly
|
|
157
|
-
if (isExplicitDevice && user) {
|
|
158
|
-
deviceResults.push({
|
|
159
|
-
user,
|
|
160
|
-
device,
|
|
161
|
-
wireJid: jid // Preserve exact JID format for wire protocol
|
|
162
|
-
});
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
// For user JIDs, normalize and prepare for device enumeration
|
|
120
|
+
const user = jidDecode(jid)?.user;
|
|
166
121
|
jid = jidNormalizedUser(jid);
|
|
167
122
|
if (useCache) {
|
|
168
123
|
const devices = userDevicesCache.get(user);
|
|
169
124
|
if (devices) {
|
|
170
|
-
|
|
171
|
-
const devicesWithWire = devices.map(d => ({
|
|
172
|
-
...d,
|
|
173
|
-
wireJid: isLidJid ? jidEncode(d.user, 'lid', d.device) : jidEncode(d.user, 's.whatsapp.net', d.device)
|
|
174
|
-
}));
|
|
175
|
-
deviceResults.push(...devicesWithWire);
|
|
125
|
+
deviceResults.push(...devices);
|
|
176
126
|
logger.trace({ user }, 'using cache for devices');
|
|
177
127
|
}
|
|
178
128
|
else {
|
|
@@ -186,14 +136,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
186
136
|
if (!toFetch.length) {
|
|
187
137
|
return deviceResults;
|
|
188
138
|
}
|
|
189
|
-
const requestedLidUsers = new Set();
|
|
190
|
-
for (const jid of toFetch) {
|
|
191
|
-
if (jid.includes('@lid')) {
|
|
192
|
-
const user = jidDecode(jid)?.user;
|
|
193
|
-
if (user)
|
|
194
|
-
requestedLidUsers.add(user);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
139
|
const query = new USyncQuery().withContext('message').withDeviceProtocol();
|
|
198
140
|
for (const jid of toFetch) {
|
|
199
141
|
query.withUser(new USyncUser().withId(jid));
|
|
@@ -205,26 +147,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
205
147
|
for (const item of extracted) {
|
|
206
148
|
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
207
149
|
deviceMap[item.user]?.push(item);
|
|
208
|
-
|
|
209
|
-
// Process each user's devices as a group for bulk LID migration
|
|
210
|
-
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
211
|
-
const isLidUser = requestedLidUsers.has(user);
|
|
212
|
-
// Process all devices for this user
|
|
213
|
-
for (const item of userDevices) {
|
|
214
|
-
const finalWireJid = isLidUser
|
|
215
|
-
? jidEncode(user, 'lid', item.device)
|
|
216
|
-
: jidEncode(item.user, 's.whatsapp.net', item.device);
|
|
217
|
-
deviceResults.push({
|
|
218
|
-
...item,
|
|
219
|
-
wireJid: finalWireJid
|
|
220
|
-
});
|
|
221
|
-
logger.debug({
|
|
222
|
-
user: item.user,
|
|
223
|
-
device: item.device,
|
|
224
|
-
finalWireJid,
|
|
225
|
-
usedLid: isLidUser
|
|
226
|
-
}, 'Processed device with LID priority');
|
|
227
|
-
}
|
|
150
|
+
deviceResults.push(item);
|
|
228
151
|
}
|
|
229
152
|
for (const key in deviceMap) {
|
|
230
153
|
userDevicesCache.set(key, deviceMap[key]);
|
|
@@ -232,179 +155,24 @@ export const makeMessagesSocket = (config) => {
|
|
|
232
155
|
}
|
|
233
156
|
return deviceResults;
|
|
234
157
|
};
|
|
235
|
-
// Helper to check if JID has migrated LID session
|
|
236
|
-
const checkForMigratedLidSession = async (jid) => {
|
|
237
|
-
if (!jid.includes('@s.whatsapp.net'))
|
|
238
|
-
return false;
|
|
239
|
-
const lidMapping = signalRepository.getLIDMappingStore();
|
|
240
|
-
const lidForPN = await lidMapping.getLIDForPN(jid);
|
|
241
|
-
if (!lidForPN?.includes('@lid'))
|
|
242
|
-
return false;
|
|
243
|
-
const lidSignalId = signalRepository.jidToSignalProtocolAddress(lidForPN);
|
|
244
|
-
const lidSessions = await authState.keys.get('session', [lidSignalId]);
|
|
245
|
-
return !!lidSessions[lidSignalId];
|
|
246
|
-
};
|
|
247
158
|
const assertSessions = async (jids, force) => {
|
|
248
159
|
let didFetchNewSession = false;
|
|
249
|
-
|
|
250
|
-
// Apply same deduplication as in getUSyncDevices
|
|
251
|
-
jids = deduplicateLidPnJids(jids);
|
|
160
|
+
let jidsRequiringFetch = [];
|
|
252
161
|
if (force) {
|
|
253
|
-
|
|
254
|
-
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid));
|
|
255
|
-
const sessions = await authState.keys.get('session', addrs);
|
|
256
|
-
// Helper to check session for a JID
|
|
257
|
-
const checkJidSession = async (jid) => {
|
|
258
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
259
|
-
let hasSession = !!sessions[signalId];
|
|
260
|
-
// Check for migrated LID session if PN session missing
|
|
261
|
-
if (!hasSession) {
|
|
262
|
-
hasSession = await checkForMigratedLidSession(jid);
|
|
263
|
-
if (hasSession) {
|
|
264
|
-
logger.debug({ jid }, 'Found migrated LID session during force assert, skipping PN fetch');
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
// Add to fetch list if no session exists
|
|
268
|
-
if (!hasSession) {
|
|
269
|
-
if (jid.includes('@lid')) {
|
|
270
|
-
logger.debug({ jid }, 'No LID session found, will create new LID session');
|
|
271
|
-
}
|
|
272
|
-
jidsRequiringFetch.push(jid);
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
// Process all JIDs
|
|
276
|
-
for (const jid of jids) {
|
|
277
|
-
await checkJidSession(jid);
|
|
278
|
-
}
|
|
162
|
+
jidsRequiringFetch = jids;
|
|
279
163
|
}
|
|
280
164
|
else {
|
|
281
|
-
const lidMapping = signalRepository.getLIDMappingStore();
|
|
282
165
|
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid));
|
|
283
166
|
const sessions = await authState.keys.get('session', addrs);
|
|
284
|
-
// Group JIDs by user for bulk migration
|
|
285
|
-
const userGroups = new Map();
|
|
286
167
|
for (const jid of jids) {
|
|
287
|
-
const
|
|
288
|
-
if (!
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
userGroups.get(user).push(jid);
|
|
292
|
-
}
|
|
293
|
-
// Helper to check LID mapping for a user
|
|
294
|
-
const checkUserLidMapping = async (user, userJids) => {
|
|
295
|
-
if (!userJids.some(jid => jid.includes('@s.whatsapp.net'))) {
|
|
296
|
-
return { shouldMigrate: false, lidForPN: undefined };
|
|
297
|
-
}
|
|
298
|
-
try {
|
|
299
|
-
const mapping = await lidMapping.getLIDForPN(user);
|
|
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
|
-
// Helper to migrate a single device
|
|
311
|
-
const migrateDeviceToLid = async (jid, lidForPN) => {
|
|
312
|
-
if (!jid.includes('@s.whatsapp.net'))
|
|
313
|
-
return;
|
|
314
|
-
try {
|
|
315
|
-
const jidDecoded = jidDecode(jid);
|
|
316
|
-
const deviceId = jidDecoded?.device || 0;
|
|
317
|
-
const lidDecoded = jidDecode(lidForPN);
|
|
318
|
-
const lidWithDevice = jidEncode(lidDecoded?.user, 'lid', deviceId);
|
|
319
|
-
await signalRepository.migrateSession(jid, lidWithDevice);
|
|
320
|
-
logger.debug({ fromJid: jid, toJid: lidWithDevice }, 'Migrated device session to LID');
|
|
321
|
-
// Delete PN session after successful migration
|
|
322
|
-
try {
|
|
323
|
-
await signalRepository.deleteSession(jid);
|
|
324
|
-
logger.debug({ deletedPNSession: jid }, 'Deleted PN session after migration');
|
|
325
|
-
}
|
|
326
|
-
catch (deleteError) {
|
|
327
|
-
logger.warn({ jid, error: deleteError }, 'Failed to delete PN session');
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
catch (migrationError) {
|
|
331
|
-
logger.warn({ jid, error: migrationError }, 'Failed to migrate device session');
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
// Process each user group for potential bulk LID migration
|
|
335
|
-
for (const [user, userJids] of userGroups) {
|
|
336
|
-
const mappingResult = await checkUserLidMapping(user, userJids);
|
|
337
|
-
const shouldMigrateUser = mappingResult.shouldMigrate;
|
|
338
|
-
const lidForPN = mappingResult.lidForPN;
|
|
339
|
-
// Migrate all devices for this user if LID mapping exists
|
|
340
|
-
if (shouldMigrateUser && lidForPN) {
|
|
341
|
-
// Migrate each device individually
|
|
342
|
-
for (const jid of userJids) {
|
|
343
|
-
await migrateDeviceToLid(jid, lidForPN);
|
|
344
|
-
}
|
|
345
|
-
logger.info({
|
|
346
|
-
user,
|
|
347
|
-
lidMapping: lidForPN,
|
|
348
|
-
deviceCount: userJids.length
|
|
349
|
-
}, 'Completed migration attempt for user devices');
|
|
350
|
-
}
|
|
351
|
-
// Helper to check session for migrated user
|
|
352
|
-
const checkMigratedSession = async (jid) => {
|
|
353
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
354
|
-
let hasSession = !!sessions[signalId];
|
|
355
|
-
let jidToFetch = jid;
|
|
356
|
-
// Check if we should use migrated LID session instead
|
|
357
|
-
if (shouldMigrateUser && lidForPN && jid.includes('@s.whatsapp.net')) {
|
|
358
|
-
const originalDecoded = jidDecode(jid);
|
|
359
|
-
const deviceId = originalDecoded?.device || 0;
|
|
360
|
-
const lidDecoded = jidDecode(lidForPN);
|
|
361
|
-
const lidWithDevice = jidEncode(lidDecoded?.user, 'lid', deviceId);
|
|
362
|
-
// Check if LID session exists
|
|
363
|
-
const lidSignalId = signalRepository.jidToSignalProtocolAddress(lidWithDevice);
|
|
364
|
-
const lidSessions = await authState.keys.get('session', [lidSignalId]);
|
|
365
|
-
hasSession = !!lidSessions[lidSignalId];
|
|
366
|
-
jidToFetch = lidWithDevice;
|
|
367
|
-
if (hasSession) {
|
|
368
|
-
logger.debug({ originalJid: jid, lidJid: lidWithDevice }, '✅ Found bulk-migrated LID session');
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
// Add to fetch list if no session exists
|
|
372
|
-
if (!hasSession) {
|
|
373
|
-
jidsRequiringFetch.push(jidToFetch);
|
|
374
|
-
logger.debug({ jid: jidToFetch, originalJid: jid !== jidToFetch ? jid : undefined }, 'Adding to session fetch list');
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
// Now check which sessions need to be fetched for this user
|
|
378
|
-
for (const jid of userJids) {
|
|
379
|
-
await checkMigratedSession(jid);
|
|
168
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
169
|
+
if (!sessions[signalId]) {
|
|
170
|
+
jidsRequiringFetch.push(jid);
|
|
380
171
|
}
|
|
381
172
|
}
|
|
382
173
|
}
|
|
383
174
|
if (jidsRequiringFetch.length) {
|
|
384
175
|
logger.debug({ jidsRequiringFetch }, 'fetching sessions');
|
|
385
|
-
// DEBUG: Check if there are PN versions of LID users being fetched
|
|
386
|
-
const lidUsersBeingFetched = new Set();
|
|
387
|
-
const pnUsersBeingFetched = new Set();
|
|
388
|
-
for (const jid of jidsRequiringFetch) {
|
|
389
|
-
const user = jidDecode(jid)?.user;
|
|
390
|
-
if (user) {
|
|
391
|
-
if (jid.includes('@lid')) {
|
|
392
|
-
lidUsersBeingFetched.add(user);
|
|
393
|
-
}
|
|
394
|
-
else if (jid.includes('@s.whatsapp.net')) {
|
|
395
|
-
pnUsersBeingFetched.add(user);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
// Find overlaps
|
|
400
|
-
const overlapping = Array.from(pnUsersBeingFetched).filter(user => lidUsersBeingFetched.has(user));
|
|
401
|
-
if (overlapping.length > 0) {
|
|
402
|
-
logger.warn({
|
|
403
|
-
overlapping,
|
|
404
|
-
lidUsersBeingFetched: Array.from(lidUsersBeingFetched),
|
|
405
|
-
pnUsersBeingFetched: Array.from(pnUsersBeingFetched)
|
|
406
|
-
}, 'Fetching both LID and PN sessions for same users');
|
|
407
|
-
}
|
|
408
176
|
const result = await query({
|
|
409
177
|
tag: 'iq',
|
|
410
178
|
attrs: {
|
|
@@ -448,132 +216,43 @@ export const makeMessagesSocket = (config) => {
|
|
|
448
216
|
});
|
|
449
217
|
return msgId;
|
|
450
218
|
};
|
|
451
|
-
const createParticipantNodes = async (jids, message, extraAttrs
|
|
219
|
+
const createParticipantNodes = async (jids, message, extraAttrs) => {
|
|
452
220
|
let patched = await patchMessageBeforeSending(message, jids);
|
|
453
221
|
if (!Array.isArray(patched)) {
|
|
454
222
|
patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched];
|
|
455
223
|
}
|
|
456
224
|
let shouldIncludeDeviceIdentity = false;
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
// Helper to get encryption JID with LID migration
|
|
480
|
-
const getEncryptionJid = async (wireJid) => {
|
|
481
|
-
if (!wireJid.includes('@s.whatsapp.net'))
|
|
482
|
-
return wireJid;
|
|
483
|
-
try {
|
|
484
|
-
const lidMapping = signalRepository.getLIDMappingStore();
|
|
485
|
-
const lidForPN = await lidMapping.getLIDForPN(wireJid);
|
|
486
|
-
if (!lidForPN?.includes('@lid'))
|
|
487
|
-
return wireJid;
|
|
488
|
-
// Preserve device ID from original wire JID
|
|
489
|
-
const wireDecoded = jidDecode(wireJid);
|
|
490
|
-
const deviceId = wireDecoded?.device || 0;
|
|
491
|
-
const lidDecoded = jidDecode(lidForPN);
|
|
492
|
-
const lidWithDevice = jidEncode(lidDecoded?.user, 'lid', deviceId);
|
|
493
|
-
// Migrate session to LID for unified encryption layer
|
|
494
|
-
try {
|
|
495
|
-
await signalRepository.migrateSession(wireJid, lidWithDevice);
|
|
496
|
-
const recipientUser = jidNormalizedUser(wireJid);
|
|
497
|
-
const ownPnUser = jidNormalizedUser(meId);
|
|
498
|
-
const isOwnDevice = recipientUser === ownPnUser;
|
|
499
|
-
logger.info({ wireJid, lidWithDevice, isOwnDevice }, 'Migrated to LID encryption');
|
|
500
|
-
// Delete PN session after successful migration
|
|
501
|
-
try {
|
|
502
|
-
await signalRepository.deleteSession(wireJid);
|
|
503
|
-
logger.debug({ deletedPNSession: wireJid }, 'Deleted PN session');
|
|
504
|
-
}
|
|
505
|
-
catch (deleteError) {
|
|
506
|
-
logger.warn({ wireJid, error: deleteError }, 'Failed to delete PN session');
|
|
507
|
-
}
|
|
508
|
-
return lidWithDevice;
|
|
509
|
-
}
|
|
510
|
-
catch (migrationError) {
|
|
511
|
-
logger.warn({ wireJid, error: migrationError }, 'Failed to migrate session');
|
|
512
|
-
return wireJid;
|
|
225
|
+
const nodes = await Promise.all(patched.map(async (patchedMessageWithJid) => {
|
|
226
|
+
const { recipientJid: jid, ...patchedMessage } = patchedMessageWithJid;
|
|
227
|
+
if (!jid) {
|
|
228
|
+
return {};
|
|
229
|
+
}
|
|
230
|
+
const bytes = encodeWAMessage(patchedMessage);
|
|
231
|
+
const { type, ciphertext } = await signalRepository.encryptMessage({ jid, data: bytes });
|
|
232
|
+
if (type === 'pkmsg') {
|
|
233
|
+
shouldIncludeDeviceIdentity = true;
|
|
234
|
+
}
|
|
235
|
+
const node = {
|
|
236
|
+
tag: 'to',
|
|
237
|
+
attrs: { jid },
|
|
238
|
+
content: [
|
|
239
|
+
{
|
|
240
|
+
tag: 'enc',
|
|
241
|
+
attrs: {
|
|
242
|
+
v: '2',
|
|
243
|
+
type,
|
|
244
|
+
...(extraAttrs || {})
|
|
245
|
+
},
|
|
246
|
+
content: ciphertext
|
|
513
247
|
}
|
|
514
|
-
|
|
515
|
-
catch (error) {
|
|
516
|
-
logger.debug({ wireJid, error }, 'Failed to check LID mapping');
|
|
517
|
-
return wireJid;
|
|
518
|
-
}
|
|
248
|
+
]
|
|
519
249
|
};
|
|
520
|
-
|
|
521
|
-
for (const { recipientJid: wireJid, patchedMessage } of userDevices) {
|
|
522
|
-
// DSM logic: Use DSM for own other devices (following whatsmeow implementation)
|
|
523
|
-
let messageToEncrypt = patchedMessage;
|
|
524
|
-
if (dsmMessage) {
|
|
525
|
-
const { user: targetUser } = jidDecode(wireJid);
|
|
526
|
-
const { user: ownPnUser } = jidDecode(meId);
|
|
527
|
-
const ownLidUser = meLidUser;
|
|
528
|
-
// Check if this is our device (same user, different device)
|
|
529
|
-
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
530
|
-
// Exclude exact sender device (whatsmeow: if jid == ownJID || jid == ownLID { continue })
|
|
531
|
-
const isExactSenderDevice = wireJid === meId || (authState.creds.me?.lid && wireJid === authState.creds.me.lid);
|
|
532
|
-
if (isOwnUser && !isExactSenderDevice) {
|
|
533
|
-
messageToEncrypt = dsmMessage;
|
|
534
|
-
logger.debug({ wireJid, targetUser }, 'Using DSM for own device');
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
const bytes = encodeWAMessage(messageToEncrypt);
|
|
538
|
-
// Get encryption JID with LID migration
|
|
539
|
-
const encryptionJid = await getEncryptionJid(wireJid);
|
|
540
|
-
// ENCRYPT: Use the determined encryption identity (prefers migrated LID)
|
|
541
|
-
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
542
|
-
jid: encryptionJid, // Unified encryption layer (LID when available)
|
|
543
|
-
data: bytes
|
|
544
|
-
});
|
|
545
|
-
if (type === 'pkmsg') {
|
|
546
|
-
shouldIncludeDeviceIdentity = true;
|
|
547
|
-
}
|
|
548
|
-
const node = {
|
|
549
|
-
tag: 'to',
|
|
550
|
-
attrs: { jid: wireJid }, // Always use original wire identity in envelope
|
|
551
|
-
content: [
|
|
552
|
-
{
|
|
553
|
-
tag: 'enc',
|
|
554
|
-
attrs: {
|
|
555
|
-
v: '2',
|
|
556
|
-
type,
|
|
557
|
-
...(extraAttrs || {})
|
|
558
|
-
},
|
|
559
|
-
content: ciphertext
|
|
560
|
-
}
|
|
561
|
-
]
|
|
562
|
-
};
|
|
563
|
-
userNodes.push(node);
|
|
564
|
-
}
|
|
565
|
-
logger.debug({ user, nodesCreated: userNodes.length }, 'Releasing encryption lock for user devices');
|
|
566
|
-
return userNodes;
|
|
250
|
+
return node;
|
|
567
251
|
}));
|
|
568
|
-
// Wait for all users to complete (users are processed in parallel)
|
|
569
|
-
const userNodesArrays = await Promise.all(userEncryptionPromises);
|
|
570
|
-
const nodes = userNodesArrays.flat();
|
|
571
252
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
572
253
|
};
|
|
573
254
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
574
255
|
const meId = authState.creds.me.id;
|
|
575
|
-
const meLid = authState.creds.me?.lid;
|
|
576
|
-
// ADDRESSING CONSISTENCY: Keep envelope addressing as user provided, handle LID migration in encryption
|
|
577
256
|
let shouldIncludeDeviceIdentity = false;
|
|
578
257
|
const { user, server } = jidDecode(jid);
|
|
579
258
|
const statusJid = 'status@broadcast';
|
|
@@ -581,22 +260,11 @@ export const makeMessagesSocket = (config) => {
|
|
|
581
260
|
const isStatus = jid === statusJid;
|
|
582
261
|
const isLid = server === 'lid';
|
|
583
262
|
const isNewsletter = server === 'newsletter';
|
|
584
|
-
// Keep user's original JID choice for envelope addressing
|
|
585
|
-
const finalJid = jid;
|
|
586
|
-
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
587
|
-
let ownId = meId;
|
|
588
|
-
if (isLid && meLid) {
|
|
589
|
-
ownId = meLid;
|
|
590
|
-
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
|
|
591
|
-
}
|
|
592
|
-
else {
|
|
593
|
-
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
|
|
594
|
-
}
|
|
595
263
|
msgId = msgId || generateMessageIDV2(sock.user?.id);
|
|
596
264
|
useUserDevicesCache = useUserDevicesCache !== false;
|
|
597
265
|
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
598
266
|
const participants = [];
|
|
599
|
-
const destinationJid = !isStatus ?
|
|
267
|
+
const destinationJid = !isStatus ? jidEncode(user, isLid ? 'lid' : isGroup ? 'g.us' : 's.whatsapp.net') : statusJid;
|
|
600
268
|
const binaryNodeContent = [];
|
|
601
269
|
const devices = [];
|
|
602
270
|
const meMsg = {
|
|
@@ -615,11 +283,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
615
283
|
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
|
|
616
284
|
}
|
|
617
285
|
const { user, device } = jidDecode(participant.jid);
|
|
618
|
-
devices.push({
|
|
619
|
-
user,
|
|
620
|
-
device,
|
|
621
|
-
wireJid: participant.jid // Use the participant JID as wire JID
|
|
622
|
-
});
|
|
286
|
+
devices.push({ user, device });
|
|
623
287
|
}
|
|
624
288
|
await authState.keys.transaction(async () => {
|
|
625
289
|
const mediaType = getMediaType(message);
|
|
@@ -678,10 +342,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
678
342
|
participantsList.push(...statusJidList);
|
|
679
343
|
}
|
|
680
344
|
if (!isStatus) {
|
|
681
|
-
const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn');
|
|
682
345
|
additionalAttributes = {
|
|
683
346
|
...additionalAttributes,
|
|
684
|
-
addressing_mode:
|
|
347
|
+
addressing_mode: groupData?.addressingMode || 'pn'
|
|
685
348
|
};
|
|
686
349
|
}
|
|
687
350
|
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
|
|
@@ -692,24 +355,19 @@ export const makeMessagesSocket = (config) => {
|
|
|
692
355
|
throw new Boom('Per-jid patching is not supported in groups');
|
|
693
356
|
}
|
|
694
357
|
const bytes = encodeWAMessage(patched);
|
|
695
|
-
// This should match the group's addressing mode and conversation context
|
|
696
|
-
const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn');
|
|
697
|
-
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
698
358
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
699
359
|
group: destinationJid,
|
|
700
360
|
data: bytes,
|
|
701
|
-
meId
|
|
361
|
+
meId
|
|
702
362
|
});
|
|
703
363
|
const senderKeyJids = [];
|
|
704
364
|
// ensure a connection is established with every device
|
|
705
|
-
for (const device of devices) {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
if (!hasKey || !!participant) {
|
|
710
|
-
senderKeyJids.push(deviceJid);
|
|
365
|
+
for (const { user, device } of devices) {
|
|
366
|
+
const jid = jidEncode(user, groupData?.addressingMode === 'lid' ? 'lid' : 's.whatsapp.net', device);
|
|
367
|
+
if (!senderKeyMap[jid] || !!participant) {
|
|
368
|
+
senderKeyJids.push(jid);
|
|
711
369
|
// store that this person has had the sender keys sent to them
|
|
712
|
-
senderKeyMap[
|
|
370
|
+
senderKeyMap[jid] = true;
|
|
713
371
|
}
|
|
714
372
|
}
|
|
715
373
|
// if there are some participants with whom the session has not been established
|
|
@@ -735,54 +393,23 @@ export const makeMessagesSocket = (config) => {
|
|
|
735
393
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
736
394
|
}
|
|
737
395
|
else {
|
|
738
|
-
const { user:
|
|
396
|
+
const { user: meUser } = jidDecode(meId);
|
|
739
397
|
if (!participant) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
user
|
|
743
|
-
device: 0,
|
|
744
|
-
wireJid: jidEncode(user, targetUserServer, 0)
|
|
745
|
-
});
|
|
746
|
-
// Own user matches conversation addressing mode
|
|
747
|
-
if (user !== ownUser) {
|
|
748
|
-
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
749
|
-
const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
750
|
-
devices.push({
|
|
751
|
-
user: ownUserForAddressing,
|
|
752
|
-
device: 0,
|
|
753
|
-
wireJid: jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
754
|
-
});
|
|
398
|
+
devices.push({ user });
|
|
399
|
+
if (user !== meUser) {
|
|
400
|
+
devices.push({ user: meUser });
|
|
755
401
|
}
|
|
756
402
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
757
|
-
|
|
758
|
-
devices.
|
|
759
|
-
// Use conversation-appropriate sender identity
|
|
760
|
-
const senderIdentity = isLid && meLid
|
|
761
|
-
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
762
|
-
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
763
|
-
// Enumerate devices for sender and target with consistent addressing
|
|
764
|
-
const sessionDevices = await getUSyncDevices([senderIdentity, jid], false, false);
|
|
765
|
-
devices.push(...sessionDevices);
|
|
766
|
-
logger.debug({
|
|
767
|
-
deviceCount: devices.length,
|
|
768
|
-
devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.wireJid)?.server}`)
|
|
769
|
-
}, 'Device enumeration complete with unified addressing');
|
|
403
|
+
const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true);
|
|
404
|
+
devices.push(...additionalDevices);
|
|
770
405
|
}
|
|
771
406
|
}
|
|
772
407
|
const allJids = [];
|
|
773
408
|
const meJids = [];
|
|
774
409
|
const otherJids = [];
|
|
775
|
-
const { user
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid);
|
|
779
|
-
if (isExactSenderDevice) {
|
|
780
|
-
logger.debug({ wireJid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
781
|
-
continue;
|
|
782
|
-
}
|
|
783
|
-
// Check if this is our device (could match either PN or LID user)
|
|
784
|
-
const isMe = user === mePnUser || (meLidUser && user === meLidUser);
|
|
785
|
-
const jid = wireJid;
|
|
410
|
+
for (const { user, device } of devices) {
|
|
411
|
+
const isMe = user === meUser;
|
|
412
|
+
const jid = jidEncode(isMe && isLid ? authState.creds?.me?.lid.split(':')[0] || user : user, isLid ? 'lid' : 's.whatsapp.net', device);
|
|
786
413
|
if (isMe) {
|
|
787
414
|
meJids.push(jid);
|
|
788
415
|
}
|
|
@@ -791,11 +418,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
791
418
|
}
|
|
792
419
|
allJids.push(jid);
|
|
793
420
|
}
|
|
794
|
-
await assertSessions(
|
|
421
|
+
await assertSessions(allJids, false);
|
|
795
422
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
796
|
-
|
|
797
|
-
createParticipantNodes(
|
|
798
|
-
createParticipantNodes(otherJids, message, extraAttrs, meMsg)
|
|
423
|
+
createParticipantNodes(meJids, meMsg, extraAttrs),
|
|
424
|
+
createParticipantNodes(otherJids, message, extraAttrs)
|
|
799
425
|
]);
|
|
800
426
|
participants.push(...meNodes);
|
|
801
427
|
participants.push(...otherNodes);
|
|
@@ -820,7 +446,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
820
446
|
tag: 'message',
|
|
821
447
|
attrs: {
|
|
822
448
|
id: msgId,
|
|
823
|
-
to: destinationJid,
|
|
824
449
|
type: getMessageType(message),
|
|
825
450
|
...(additionalAttributes || {})
|
|
826
451
|
},
|
|
@@ -867,9 +492,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
867
492
|
if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
|
|
868
493
|
return 'poll';
|
|
869
494
|
}
|
|
870
|
-
if (message.eventMessage) {
|
|
871
|
-
return 'event';
|
|
872
|
-
}
|
|
873
495
|
return 'text';
|
|
874
496
|
};
|
|
875
497
|
const getMediaType = (message) => {
|
|
@@ -1032,14 +654,12 @@ export const makeMessagesSocket = (config) => {
|
|
|
1032
654
|
}),
|
|
1033
655
|
//TODO: CACHE
|
|
1034
656
|
getProfilePicUrl: sock.profilePictureUrl,
|
|
1035
|
-
getCallLink: sock.createCallLink,
|
|
1036
657
|
upload: waUploadToServer,
|
|
1037
658
|
mediaCache: config.mediaCache,
|
|
1038
659
|
options: config.options,
|
|
1039
660
|
messageId: generateMessageIDV2(sock.user?.id),
|
|
1040
661
|
...options
|
|
1041
662
|
});
|
|
1042
|
-
const isEventMsg = 'event' in content && !!content.event;
|
|
1043
663
|
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
1044
664
|
const isEditMsg = 'edit' in content && !!content.edit;
|
|
1045
665
|
const isPinMsg = 'pin' in content && !!content.pin;
|
|
@@ -1070,14 +690,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
1070
690
|
}
|
|
1071
691
|
});
|
|
1072
692
|
}
|
|
1073
|
-
else if (isEventMsg) {
|
|
1074
|
-
additionalNodes.push({
|
|
1075
|
-
tag: 'meta',
|
|
1076
|
-
attrs: {
|
|
1077
|
-
event_type: 'creation'
|
|
1078
|
-
}
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
693
|
if ('cachedGroupMetadata' in options) {
|
|
1082
694
|
console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.');
|
|
1083
695
|
}
|