@d0v3riz/baileys 7.0.0-rc.9 → 7.0.0-rc13
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 +21 -15
- package/WAProto/fix-imports.js +74 -18
- package/WAProto/index.js +201 -160
- package/lib/Defaults/index.d.ts +19 -6
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +24 -10
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +105 -16
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +8 -8
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +176 -70
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/Client/websocket.d.ts +1 -1
- package/lib/Socket/Client/websocket.d.ts.map +1 -1
- package/lib/Socket/Client/websocket.js +5 -1
- package/lib/Socket/Client/websocket.js.map +1 -1
- package/lib/Socket/business.d.ts +36 -8
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/business.js +11 -8
- package/lib/Socket/business.js.map +1 -1
- package/lib/Socket/chats.d.ts +29 -5
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +292 -63
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +36 -8
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts +27 -5
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +20 -0
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +36 -8
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/index.js +0 -6
- package/lib/Socket/index.js.map +1 -1
- package/lib/Socket/messages-recv.d.ts +40 -11
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +841 -342
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +35 -6
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +263 -92
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/mex.d.ts.map +1 -1
- package/lib/Socket/mex.js +2 -0
- package/lib/Socket/mex.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +27 -5
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +35 -3
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts +9 -3
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +124 -39
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +2 -0
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Call.d.ts +2 -1
- package/lib/Types/Call.d.ts.map +1 -1
- package/lib/Types/Chat.d.ts +1 -0
- package/lib/Types/Chat.d.ts.map +1 -1
- package/lib/Types/Contact.d.ts +2 -0
- package/lib/Types/Contact.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +60 -6
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/GroupMetadata.d.ts +4 -0
- package/lib/Types/GroupMetadata.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +20 -5
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/{Newsletter.d.ts → Mex.d.ts} +13 -5
- package/lib/Types/Mex.d.ts.map +1 -0
- package/lib/Types/{Newsletter.js → Mex.js} +11 -3
- package/lib/Types/Mex.js.map +1 -0
- package/lib/Types/Signal.d.ts +12 -1
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Types/Socket.d.ts +3 -0
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Types/State.d.ts +58 -0
- package/lib/Types/State.d.ts.map +1 -1
- package/lib/Types/State.js +43 -0
- package/lib/Types/State.js.map +1 -1
- package/lib/Types/index.d.ts +1 -1
- package/lib/Types/index.d.ts.map +1 -1
- package/lib/Types/index.js +1 -1
- package/lib/Types/index.js.map +1 -1
- package/lib/Utils/auth-utils.d.ts +5 -0
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +65 -20
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/chat-utils.d.ts +31 -1
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +180 -71
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
- package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/companion-reg-client-utils.js.map +1 -0
- package/lib/Utils/crypto.d.ts +4 -8
- package/lib/Utils/crypto.d.ts.map +1 -1
- package/lib/Utils/crypto.js +2 -26
- package/lib/Utils/crypto.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +18 -0
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +34 -0
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/event-buffer.d.ts +2 -0
- package/lib/Utils/event-buffer.d.ts.map +1 -1
- package/lib/Utils/event-buffer.js +82 -8
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts +2 -0
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +13 -1
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts +8 -3
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +58 -14
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/identity-change-handler.d.ts +44 -0
- package/lib/Utils/identity-change-handler.d.ts.map +1 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/identity-change-handler.js.map +1 -0
- package/lib/Utils/index.d.ts +3 -0
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +3 -0
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/link-preview.js +2 -2
- package/lib/Utils/link-preview.js.map +1 -1
- package/lib/Utils/lt-hash.d.ts +7 -12
- package/lib/Utils/lt-hash.d.ts.map +1 -1
- package/lib/Utils/lt-hash.js +2 -42
- package/lib/Utils/lt-hash.js.map +1 -1
- package/lib/Utils/make-mutex.d.ts +1 -0
- package/lib/Utils/make-mutex.d.ts.map +1 -1
- package/lib/Utils/make-mutex.js +20 -27
- package/lib/Utils/make-mutex.js.map +1 -1
- package/lib/Utils/message-retry-manager.d.ts +35 -2
- package/lib/Utils/message-retry-manager.d.ts.map +1 -1
- package/lib/Utils/message-retry-manager.js +98 -5
- package/lib/Utils/message-retry-manager.js.map +1 -1
- package/lib/Utils/messages-media.d.ts +22 -3
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +169 -44
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts +2 -0
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +70 -27
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/noise-handler.d.ts +4 -4
- package/lib/Utils/noise-handler.d.ts.map +1 -1
- package/lib/Utils/noise-handler.js +139 -85
- package/lib/Utils/noise-handler.js.map +1 -1
- package/lib/Utils/offline-node-processor.d.ts +17 -0
- package/lib/Utils/offline-node-processor.d.ts.map +1 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/offline-node-processor.js.map +1 -0
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +165 -15
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/reporting-utils.d.ts +11 -0
- package/lib/Utils/reporting-utils.d.ts.map +1 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/reporting-utils.js.map +1 -0
- package/lib/Utils/signal.d.ts +13 -0
- package/lib/Utils/signal.d.ts.map +1 -1
- package/lib/Utils/signal.js +42 -0
- package/lib/Utils/signal.js.map +1 -1
- package/lib/Utils/stanza-ack.d.ts +11 -0
- package/lib/Utils/stanza-ack.d.ts.map +1 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/stanza-ack.js.map +1 -0
- package/lib/Utils/sync-action-utils.d.ts +19 -0
- package/lib/Utils/sync-action-utils.d.ts.map +1 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/sync-action-utils.js.map +1 -0
- package/lib/Utils/tc-token-utils.d.ts +37 -0
- package/lib/Utils/tc-token-utils.d.ts.map +1 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/tc-token-utils.js.map +1 -0
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +4 -1
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/decode.d.ts.map +1 -1
- package/lib/WABinary/decode.js +24 -0
- package/lib/WABinary/decode.js.map +1 -1
- package/lib/WABinary/encode.js +5 -1
- package/lib/WABinary/encode.js.map +1 -1
- package/lib/WABinary/generic-utils.d.ts +1 -1
- package/lib/WABinary/generic-utils.d.ts.map +1 -1
- package/lib/WABinary/generic-utils.js +19 -8
- package/lib/WABinary/generic-utils.js.map +1 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +26 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/index.d.ts +1 -0
- package/lib/WAUSync/Protocols/index.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/Protocols/index.js.map +1 -1
- package/lib/WAUSync/USyncQuery.d.ts +1 -0
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -1
- package/lib/WAUSync/USyncQuery.js +6 -2
- package/lib/WAUSync/USyncQuery.js.map +1 -1
- package/lib/WAUSync/USyncUser.d.ts +4 -0
- package/lib/WAUSync/USyncUser.d.ts.map +1 -1
- package/lib/WAUSync/USyncUser.js +8 -0
- package/lib/WAUSync/USyncUser.js.map +1 -1
- package/package.json +39 -8
- package/lib/Types/Newsletter.d.ts.map +0 -1
- package/lib/Types/Newsletter.js.map +0 -1
|
@@ -2,30 +2,39 @@ import NodeCache from '@cacheable/node-cache';
|
|
|
2
2
|
import { Boom } from '@hapi/boom';
|
|
3
3
|
import { proto } from '../../WAProto/index.js';
|
|
4
4
|
import { DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
5
|
-
import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
|
|
5
|
+
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, 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
|
-
import {
|
|
7
|
+
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
|
|
8
|
+
import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/reporting-utils.js';
|
|
9
|
+
import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, resolveTcTokenJid, shouldSendNewTcToken, storeTcTokensFromIqResult } from '../Utils/tc-token-utils.js';
|
|
10
|
+
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
9
11
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
10
12
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
11
13
|
export const makeMessagesSocket = (config) => {
|
|
12
14
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
13
15
|
const sock = makeNewsletterSocket(config);
|
|
14
|
-
const { ev, authState,
|
|
16
|
+
const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral, registerSocketEndHandler } = sock;
|
|
17
|
+
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
|
|
18
|
+
/**
|
|
19
|
+
* Set of tctoken storage JIDs with a fire-and-forget `issuePrivacyTokens` IQ in flight.
|
|
20
|
+
* Prevents duplicate IQs from rapid back-to-back sends before `senderTimestamp` persists.
|
|
21
|
+
* Entries are always removed in `.finally()`, so the set is bounded by concurrency.
|
|
22
|
+
*/
|
|
23
|
+
const inFlightTcTokenIssuance = new Set();
|
|
15
24
|
const userDevicesCache = config.userDevicesCache ||
|
|
16
25
|
new NodeCache({
|
|
17
26
|
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
18
27
|
useClones: false
|
|
19
28
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
useClones: false
|
|
23
|
-
});
|
|
29
|
+
/** Serializes writes to userDevicesCache across USync refresh and device-notification handling. */
|
|
30
|
+
const devicesMutex = makeMutex();
|
|
24
31
|
// Initialize message retry manager if enabled
|
|
25
32
|
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
26
33
|
// Prevent race conditions in Signal session encryption by user
|
|
27
34
|
const encryptionMutex = makeKeyedMutex();
|
|
28
35
|
let mediaConn;
|
|
36
|
+
/** Per-socket media host; updated whenever media_conn is fetched. Defaults to the public WhatsApp host. */
|
|
37
|
+
let mediaHost = DEF_MEDIA_HOST;
|
|
29
38
|
const refreshMediaConn = async (forceGet = false) => {
|
|
30
39
|
const media = await mediaConn;
|
|
31
40
|
if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
|
|
@@ -51,6 +60,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
51
60
|
fetchDate: new Date()
|
|
52
61
|
};
|
|
53
62
|
logger.debug('fetched media conn');
|
|
63
|
+
if (node.hosts[0]) {
|
|
64
|
+
mediaHost = node.hosts[0].hostname;
|
|
65
|
+
}
|
|
54
66
|
return node;
|
|
55
67
|
})();
|
|
56
68
|
}
|
|
@@ -226,16 +238,18 @@ export const makeMessagesSocket = (config) => {
|
|
|
226
238
|
}, 'Processed device with LID priority');
|
|
227
239
|
}
|
|
228
240
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
else {
|
|
234
|
-
for (const key in deviceMap) {
|
|
235
|
-
if (deviceMap[key])
|
|
236
|
-
await userDevicesCache.set(key, deviceMap[key]);
|
|
241
|
+
await devicesMutex.mutex(async () => {
|
|
242
|
+
if (userDevicesCache.mset) {
|
|
243
|
+
// if the cache supports mset, we can set all devices in one go
|
|
244
|
+
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
237
245
|
}
|
|
238
|
-
|
|
246
|
+
else {
|
|
247
|
+
for (const key in deviceMap) {
|
|
248
|
+
if (deviceMap[key])
|
|
249
|
+
await userDevicesCache.set(key, deviceMap[key]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
});
|
|
239
253
|
const userDeviceUpdates = {};
|
|
240
254
|
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
241
255
|
if (devices && devices.length > 0) {
|
|
@@ -254,25 +268,40 @@ export const makeMessagesSocket = (config) => {
|
|
|
254
268
|
}
|
|
255
269
|
return deviceResults;
|
|
256
270
|
};
|
|
271
|
+
/**
|
|
272
|
+
* Update Member Label
|
|
273
|
+
*/
|
|
274
|
+
const updateMemberLabel = (jid, memberLabel) => {
|
|
275
|
+
return relayMessage(jid, {
|
|
276
|
+
protocolMessage: {
|
|
277
|
+
type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
|
|
278
|
+
memberLabel: {
|
|
279
|
+
label: memberLabel?.slice(0, 30),
|
|
280
|
+
labelTimestamp: unixTimestampSeconds()
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}, {
|
|
284
|
+
additionalNodes: [
|
|
285
|
+
{
|
|
286
|
+
tag: 'meta',
|
|
287
|
+
attrs: {
|
|
288
|
+
tag_reason: 'user_update',
|
|
289
|
+
appdata: 'member_tag'
|
|
290
|
+
},
|
|
291
|
+
content: undefined
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
});
|
|
295
|
+
};
|
|
257
296
|
const assertSessions = async (jids, force) => {
|
|
258
297
|
let didFetchNewSession = false;
|
|
259
|
-
const uniqueJids = [...new Set(jids)];
|
|
298
|
+
const uniqueJids = [...new Set(jids)];
|
|
260
299
|
const jidsRequiringFetch = [];
|
|
261
300
|
logger.debug({ jids }, 'assertSessions call with jids');
|
|
262
|
-
// Check peerSessionsCache and validate sessions using libsignal loadSession
|
|
263
301
|
for (const jid of uniqueJids) {
|
|
264
|
-
|
|
265
|
-
const cachedSession = peerSessionsCache.get(signalId);
|
|
266
|
-
if (cachedSession !== undefined) {
|
|
267
|
-
if (cachedSession && !force) {
|
|
268
|
-
continue; // Session exists in cache
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
302
|
+
if (!force) {
|
|
272
303
|
const sessionValidation = await signalRepository.validateSession(jid);
|
|
273
|
-
|
|
274
|
-
peerSessionsCache.set(signalId, hasSession);
|
|
275
|
-
if (hasSession && !force) {
|
|
304
|
+
if (sessionValidation.exists) {
|
|
276
305
|
continue;
|
|
277
306
|
}
|
|
278
307
|
}
|
|
@@ -307,11 +336,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
307
336
|
});
|
|
308
337
|
await parseAndInjectE2ESessions(result, signalRepository);
|
|
309
338
|
didFetchNewSession = true;
|
|
310
|
-
// Cache fetched sessions using wire JIDs
|
|
311
|
-
for (const wireJid of wireJids) {
|
|
312
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
|
|
313
|
-
peerSessionsCache.set(signalId, true);
|
|
314
|
-
}
|
|
315
339
|
}
|
|
316
340
|
return didFetchNewSession;
|
|
317
341
|
};
|
|
@@ -354,53 +378,55 @@ export const makeMessagesSocket = (config) => {
|
|
|
354
378
|
const meLid = authState.creds.me?.lid;
|
|
355
379
|
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
356
380
|
const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const
|
|
375
|
-
jid,
|
|
376
|
-
|
|
381
|
+
try {
|
|
382
|
+
if (!jid)
|
|
383
|
+
return null;
|
|
384
|
+
let msgToEncrypt = patchedMessage;
|
|
385
|
+
if (dsmMessage) {
|
|
386
|
+
const { user: targetUser } = jidDecode(jid);
|
|
387
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
388
|
+
const ownLidUser = meLidUser;
|
|
389
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
390
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
391
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
392
|
+
msgToEncrypt = dsmMessage;
|
|
393
|
+
logger.debug({ jid, targetUser }, 'Using DSM for own device');
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
397
|
+
const mutexKey = jid;
|
|
398
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
399
|
+
const { type, ciphertext } = await signalRepository.encryptMessage({ jid, data: bytes });
|
|
400
|
+
if (type === 'pkmsg') {
|
|
401
|
+
shouldIncludeDeviceIdentity = true;
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
tag: 'to',
|
|
405
|
+
attrs: { jid },
|
|
406
|
+
content: [
|
|
407
|
+
{
|
|
408
|
+
tag: 'enc',
|
|
409
|
+
attrs: { v: '2', type, ...(extraAttrs || {}) },
|
|
410
|
+
content: ciphertext
|
|
411
|
+
}
|
|
412
|
+
]
|
|
413
|
+
};
|
|
377
414
|
});
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
content: [
|
|
385
|
-
{
|
|
386
|
-
tag: 'enc',
|
|
387
|
-
attrs: {
|
|
388
|
-
v: '2',
|
|
389
|
-
type,
|
|
390
|
-
...(extraAttrs || {})
|
|
391
|
-
},
|
|
392
|
-
content: ciphertext
|
|
393
|
-
}
|
|
394
|
-
]
|
|
395
|
-
};
|
|
396
|
-
});
|
|
397
|
-
return node;
|
|
415
|
+
return node;
|
|
416
|
+
}
|
|
417
|
+
catch (err) {
|
|
418
|
+
logger.error({ jid, err }, 'Failed to encrypt for recipient');
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
398
421
|
});
|
|
399
422
|
const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
|
|
423
|
+
if (recipientJids.length > 0 && nodes.length === 0) {
|
|
424
|
+
throw new Boom('All encryptions failed', { statusCode: 500 });
|
|
425
|
+
}
|
|
400
426
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
401
427
|
};
|
|
402
428
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
403
|
-
const meId = authState.creds
|
|
429
|
+
const meId = assertMeId(authState.creds);
|
|
404
430
|
const meLid = authState.creds.me?.lid;
|
|
405
431
|
const isRetryResend = Boolean(participant?.jid);
|
|
406
432
|
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
@@ -419,6 +445,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
419
445
|
const destinationJid = !isStatus ? finalJid : statusJid;
|
|
420
446
|
const binaryNodeContent = [];
|
|
421
447
|
const devices = [];
|
|
448
|
+
let reportingMessage;
|
|
422
449
|
const meMsg = {
|
|
423
450
|
deviceSentMessage: {
|
|
424
451
|
destinationJid,
|
|
@@ -465,7 +492,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
465
492
|
await sendNode(stanza);
|
|
466
493
|
return;
|
|
467
494
|
}
|
|
468
|
-
if (normalizeMessageContent(message)?.pinInChatMessage) {
|
|
495
|
+
if (normalizeMessageContent(message)?.pinInChatMessage || normalizeMessageContent(message)?.reactionMessage) {
|
|
469
496
|
extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
|
|
470
497
|
}
|
|
471
498
|
if (isGroupOrStatus && !isRetryResend) {
|
|
@@ -513,6 +540,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
513
540
|
throw new Boom('Per-jid patching is not supported in groups');
|
|
514
541
|
}
|
|
515
542
|
const bytes = encodeWAMessage(patched);
|
|
543
|
+
reportingMessage = patched;
|
|
516
544
|
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
|
|
517
545
|
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
518
546
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
@@ -567,6 +595,12 @@ export const makeMessagesSocket = (config) => {
|
|
|
567
595
|
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
|
|
568
596
|
}
|
|
569
597
|
const { user: ownUser } = jidDecode(ownId);
|
|
598
|
+
if (!participant) {
|
|
599
|
+
const patchedForReporting = await patchMessageBeforeSending(message, [jid]);
|
|
600
|
+
reportingMessage = Array.isArray(patchedForReporting)
|
|
601
|
+
? patchedForReporting.find(item => item.recipientJid === jid) || patchedForReporting[0]
|
|
602
|
+
: patchedForReporting;
|
|
603
|
+
}
|
|
570
604
|
if (!isRetryResend) {
|
|
571
605
|
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
572
606
|
devices.push({
|
|
@@ -636,14 +670,42 @@ export const makeMessagesSocket = (config) => {
|
|
|
636
670
|
if (isRetryResend) {
|
|
637
671
|
const isParticipantLid = isLidUser(participant.jid);
|
|
638
672
|
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
|
|
673
|
+
let messageToSend = message;
|
|
674
|
+
if (isGroupOrStatus) {
|
|
675
|
+
let groupSenderIdentity;
|
|
676
|
+
if (meLid && (await signalRepository.hasSenderKey({ group: destinationJid, meId: meLid }))) {
|
|
677
|
+
groupSenderIdentity = meLid;
|
|
678
|
+
}
|
|
679
|
+
else if (await signalRepository.hasSenderKey({ group: destinationJid, meId })) {
|
|
680
|
+
groupSenderIdentity = meId;
|
|
681
|
+
}
|
|
682
|
+
if (groupSenderIdentity) {
|
|
683
|
+
try {
|
|
684
|
+
const skdm = await signalRepository.getSenderKeyDistributionMessage({
|
|
685
|
+
group: destinationJid,
|
|
686
|
+
meId: groupSenderIdentity
|
|
687
|
+
});
|
|
688
|
+
messageToSend = {
|
|
689
|
+
...message,
|
|
690
|
+
senderKeyDistributionMessage: {
|
|
691
|
+
groupId: destinationJid,
|
|
692
|
+
axolotlSenderKeyDistributionMessage: skdm
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
catch (err) {
|
|
697
|
+
logger.warn({ err, jid: destinationJid }, 'failed to build SKDM for retry, sending without it');
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
639
701
|
const encodedMessageToSend = isMe
|
|
640
702
|
? encodeWAMessage({
|
|
641
703
|
deviceSentMessage: {
|
|
642
704
|
destinationJid,
|
|
643
|
-
message
|
|
705
|
+
message: messageToSend
|
|
644
706
|
}
|
|
645
707
|
})
|
|
646
|
-
: encodeWAMessage(
|
|
708
|
+
: encodeWAMessage(messageToSend);
|
|
647
709
|
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
648
710
|
data: encodedMessageToSend,
|
|
649
711
|
jid: participant.jid
|
|
@@ -711,9 +773,53 @@ export const makeMessagesSocket = (config) => {
|
|
|
711
773
|
});
|
|
712
774
|
logger.debug({ jid }, 'adding device identity');
|
|
713
775
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
776
|
+
if (!isNewsletter &&
|
|
777
|
+
!isRetryResend &&
|
|
778
|
+
reportingMessage?.messageContextInfo?.messageSecret &&
|
|
779
|
+
shouldIncludeReportingToken(reportingMessage)) {
|
|
780
|
+
try {
|
|
781
|
+
const encoded = encodeWAMessage(reportingMessage);
|
|
782
|
+
const reportingKey = {
|
|
783
|
+
id: msgId,
|
|
784
|
+
fromMe: true,
|
|
785
|
+
remoteJid: destinationJid,
|
|
786
|
+
participant: participant?.jid
|
|
787
|
+
};
|
|
788
|
+
const reportingNode = await getMessageReportingToken(encoded, reportingMessage, reportingKey);
|
|
789
|
+
if (reportingNode) {
|
|
790
|
+
;
|
|
791
|
+
stanza.content.push(reportingNode);
|
|
792
|
+
logger.trace({ jid }, 'added reporting token to message');
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
catch (error) {
|
|
796
|
+
logger.warn({ jid, trace: error?.stack }, 'failed to attach reporting token');
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
// WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
|
|
800
|
+
const isPeerMessage = additionalAttributes?.['category'] === 'peer';
|
|
801
|
+
const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage;
|
|
802
|
+
// Resolve destination to LID for tctoken storage — matches Signal session key pattern
|
|
803
|
+
const tcTokenJid = is1on1Send ? await resolveTcTokenJid(destinationJid, getLIDForPN) : destinationJid;
|
|
804
|
+
const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {};
|
|
805
|
+
const existingTokenEntry = contactTcTokenData[tcTokenJid];
|
|
806
|
+
let tcTokenBuffer = existingTokenEntry?.token;
|
|
807
|
+
// Treat expired tokens the same as missing — clear from cache
|
|
808
|
+
if (tcTokenBuffer?.length && isTcTokenExpired(existingTokenEntry?.timestamp)) {
|
|
809
|
+
logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing');
|
|
810
|
+
tcTokenBuffer = undefined;
|
|
811
|
+
// Preserve senderTimestamp so the fire-and-forget issuance dedupe survives cleanup.
|
|
812
|
+
const cleared = existingTokenEntry?.senderTimestamp !== undefined
|
|
813
|
+
? { token: Buffer.alloc(0), senderTimestamp: existingTokenEntry.senderTimestamp }
|
|
814
|
+
: null;
|
|
815
|
+
try {
|
|
816
|
+
await authState.keys.set({ tctoken: { [tcTokenJid]: cleared } });
|
|
817
|
+
}
|
|
818
|
+
catch (err) {
|
|
819
|
+
logger.debug({ jid: destinationJid, err: err?.message }, 'failed to persist tctoken expiry cleanup');
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (tcTokenBuffer?.length && sock.serverProps.privacyTokenOn1to1) {
|
|
717
823
|
;
|
|
718
824
|
stanza.content.push({
|
|
719
825
|
tag: 'tctoken',
|
|
@@ -727,6 +833,48 @@ export const makeMessagesSocket = (config) => {
|
|
|
727
833
|
}
|
|
728
834
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
729
835
|
await sendNode(stanza);
|
|
836
|
+
// Fire-and-forget: issue our token to the contact AFTER message send.
|
|
837
|
+
// WA Web skips protocol messages and PSA/bot contacts (TcTokenChatAction: isRegularUser)
|
|
838
|
+
const isProtocolMsg = !!normalizeMessageContent(message)?.protocolMessage;
|
|
839
|
+
const isBotOrPSA = destinationJid === PSA_WID || isJidBot(destinationJid) || isJidMetaAI(destinationJid);
|
|
840
|
+
if (is1on1Send &&
|
|
841
|
+
!isProtocolMsg &&
|
|
842
|
+
!isBotOrPSA &&
|
|
843
|
+
shouldSendNewTcToken(existingTokenEntry?.senderTimestamp) &&
|
|
844
|
+
!inFlightTcTokenIssuance.has(tcTokenJid)) {
|
|
845
|
+
inFlightTcTokenIssuance.add(tcTokenJid);
|
|
846
|
+
const issueTimestamp = unixTimestampSeconds();
|
|
847
|
+
const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping);
|
|
848
|
+
resolveIssuanceJid(destinationJid, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID)
|
|
849
|
+
.then(issueJid => issuePrivacyTokens([issueJid], issueTimestamp))
|
|
850
|
+
.then(async (result) => {
|
|
851
|
+
await storeTcTokensFromIqResult({
|
|
852
|
+
result,
|
|
853
|
+
fallbackJid: tcTokenJid,
|
|
854
|
+
keys: authState.keys,
|
|
855
|
+
getLIDForPN
|
|
856
|
+
});
|
|
857
|
+
const currentData = await authState.keys.get('tctoken', [tcTokenJid]);
|
|
858
|
+
const currentEntry = currentData[tcTokenJid];
|
|
859
|
+
const indexWrite = await buildMergedTcTokenIndexWrite(authState.keys, [tcTokenJid]);
|
|
860
|
+
await authState.keys.set({
|
|
861
|
+
tctoken: {
|
|
862
|
+
[tcTokenJid]: {
|
|
863
|
+
token: Buffer.alloc(0),
|
|
864
|
+
...currentEntry,
|
|
865
|
+
senderTimestamp: issueTimestamp
|
|
866
|
+
},
|
|
867
|
+
...indexWrite
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
})
|
|
871
|
+
.catch(err => {
|
|
872
|
+
logger.debug({ jid: destinationJid, err: err?.message }, 'fire-and-forget tctoken issuance failed');
|
|
873
|
+
})
|
|
874
|
+
.finally(() => {
|
|
875
|
+
inFlightTcTokenIssuance.delete(tcTokenJid);
|
|
876
|
+
});
|
|
877
|
+
}
|
|
730
878
|
// Add message to retry cache if enabled
|
|
731
879
|
if (messageRetryManager && !participant) {
|
|
732
880
|
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
@@ -735,13 +883,22 @@ export const makeMessagesSocket = (config) => {
|
|
|
735
883
|
return msgId;
|
|
736
884
|
};
|
|
737
885
|
const getMessageType = (message) => {
|
|
738
|
-
|
|
886
|
+
const normalizedMessage = normalizeMessageContent(message);
|
|
887
|
+
if (!normalizedMessage)
|
|
888
|
+
return 'text';
|
|
889
|
+
if (normalizedMessage.reactionMessage || normalizedMessage.encReactionMessage) {
|
|
890
|
+
return 'reaction';
|
|
891
|
+
}
|
|
892
|
+
if (normalizedMessage.pollCreationMessage ||
|
|
893
|
+
normalizedMessage.pollCreationMessageV2 ||
|
|
894
|
+
normalizedMessage.pollCreationMessageV3 ||
|
|
895
|
+
normalizedMessage.pollUpdateMessage) {
|
|
739
896
|
return 'poll';
|
|
740
897
|
}
|
|
741
|
-
if (
|
|
898
|
+
if (normalizedMessage.eventMessage) {
|
|
742
899
|
return 'event';
|
|
743
900
|
}
|
|
744
|
-
if (getMediaType(
|
|
901
|
+
if (getMediaType(normalizedMessage) !== '') {
|
|
745
902
|
return 'media';
|
|
746
903
|
}
|
|
747
904
|
return 'text';
|
|
@@ -794,8 +951,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
794
951
|
}
|
|
795
952
|
return '';
|
|
796
953
|
};
|
|
797
|
-
const
|
|
798
|
-
const t = unixTimestampSeconds().toString();
|
|
954
|
+
const issuePrivacyTokens = async (jids, timestamp) => {
|
|
955
|
+
const t = (timestamp ?? unixTimestampSeconds()).toString();
|
|
799
956
|
const result = await query({
|
|
800
957
|
tag: 'iq',
|
|
801
958
|
attrs: {
|
|
@@ -822,26 +979,40 @@ export const makeMessagesSocket = (config) => {
|
|
|
822
979
|
};
|
|
823
980
|
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
824
981
|
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
982
|
+
registerSocketEndHandler(() => {
|
|
983
|
+
if (!config.userDevicesCache && userDevicesCache.close) {
|
|
984
|
+
userDevicesCache.close();
|
|
985
|
+
}
|
|
986
|
+
mediaConn = undefined;
|
|
987
|
+
if (messageRetryManager) {
|
|
988
|
+
messageRetryManager.clear();
|
|
989
|
+
}
|
|
990
|
+
});
|
|
825
991
|
return {
|
|
826
992
|
...sock,
|
|
827
|
-
|
|
993
|
+
userDevicesCache,
|
|
994
|
+
devicesMutex,
|
|
995
|
+
issuePrivacyTokens,
|
|
828
996
|
assertSessions,
|
|
829
997
|
relayMessage,
|
|
830
998
|
sendReceipt,
|
|
831
999
|
sendReceipts,
|
|
832
1000
|
readMessages,
|
|
833
1001
|
refreshMediaConn,
|
|
1002
|
+
// Function (not getter) so the spread in chats.ts preserves the live closure binding.
|
|
1003
|
+
getMediaHost: () => mediaHost,
|
|
834
1004
|
waUploadToServer,
|
|
835
1005
|
fetchPrivacySettings,
|
|
836
1006
|
sendPeerDataOperationMessage,
|
|
837
1007
|
createParticipantNodes,
|
|
838
1008
|
getUSyncDevices,
|
|
839
1009
|
messageRetryManager,
|
|
1010
|
+
updateMemberLabel,
|
|
840
1011
|
updateMediaMessage: async (message) => {
|
|
841
1012
|
const content = assertMediaContent(message.message);
|
|
842
1013
|
const mediaKey = content.mediaKey;
|
|
843
1014
|
const meId = authState.creds.me.id;
|
|
844
|
-
const node =
|
|
1015
|
+
const node = encryptMediaRetryRequest(message.key, mediaKey, meId);
|
|
845
1016
|
let error = undefined;
|
|
846
1017
|
await Promise.all([
|
|
847
1018
|
sendNode(node),
|
|
@@ -853,7 +1024,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
853
1024
|
}
|
|
854
1025
|
else {
|
|
855
1026
|
try {
|
|
856
|
-
const media =
|
|
1027
|
+
const media = decryptMediaRetryData(result.media, mediaKey, result.key.id);
|
|
857
1028
|
if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
|
|
858
1029
|
const resultStr = proto.MediaRetryNotification.ResultType[media.result];
|
|
859
1030
|
throw new Boom(`Media re-upload failed by device (${resultStr})`, {
|
|
@@ -862,7 +1033,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
862
1033
|
});
|
|
863
1034
|
}
|
|
864
1035
|
content.directPath = media.directPath;
|
|
865
|
-
content.url = getUrlFromDirectPath(content.directPath);
|
|
1036
|
+
content.url = getUrlFromDirectPath(content.directPath, mediaHost);
|
|
866
1037
|
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
|
|
867
1038
|
}
|
|
868
1039
|
catch (err) {
|
|
@@ -963,7 +1134,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
963
1134
|
});
|
|
964
1135
|
if (config.emitOwnEvents) {
|
|
965
1136
|
process.nextTick(async () => {
|
|
966
|
-
await
|
|
1137
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
967
1138
|
});
|
|
968
1139
|
}
|
|
969
1140
|
return fullMsg;
|