@d0v3riz/baileys 6.7.25 → 7.0.0-rc.8
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 +53 -50
- package/WAProto/GenerateStatics.sh +2 -2
- package/WAProto/WAProto.proto +1339 -493
- package/WAProto/fix-imports.js +1 -1
- package/WAProto/index.d.ts +4585 -44041
- package/WAProto/index.js +80831 -148208
- package/lib/Defaults/index.d.ts +13 -3
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +27 -13
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/Group/group_cipher.d.ts +1 -2
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -1
- package/lib/Signal/Group/group_cipher.js +29 -41
- package/lib/Signal/Group/group_cipher.js.map +1 -1
- package/lib/Signal/Group/keyhelper.d.ts.map +1 -1
- package/lib/Signal/Group/keyhelper.js +0 -1
- package/lib/Signal/Group/keyhelper.js.map +1 -1
- package/lib/Signal/Group/sender-chain-key.d.ts +1 -1
- package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -1
- package/lib/Signal/Group/sender-chain-key.js +1 -7
- package/lib/Signal/Group/sender-chain-key.js.map +1 -1
- package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
- 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 +0 -1
- 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 +4 -4
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -1
- package/lib/Signal/Group/sender-key-state.js +21 -33
- package/lib/Signal/Group/sender-key-state.js.map +1 -1
- package/lib/Signal/Group/sender-message-key.d.ts.map +1 -1
- package/lib/Signal/Group/sender-message-key.js +0 -1
- package/lib/Signal/Group/sender-message-key.js.map +1 -1
- package/lib/Signal/libsignal.d.ts +4 -3
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +243 -42
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +23 -0
- package/lib/Signal/lid-mapping.d.ts.map +1 -0
- package/lib/Signal/lid-mapping.js +171 -0
- package/lib/Signal/lid-mapping.js.map +1 -0
- package/lib/Socket/Client/types.d.ts +2 -2
- package/lib/Socket/Client/types.d.ts.map +1 -1
- package/lib/Socket/Client/websocket.d.ts +2 -2
- package/lib/Socket/Client/websocket.d.ts.map +1 -1
- package/lib/Socket/Client/websocket.js +2 -2
- package/lib/Socket/Client/websocket.js.map +1 -1
- package/lib/Socket/business.d.ts +31 -17
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/business.js +122 -1
- package/lib/Socket/business.js.map +1 -1
- package/lib/Socket/chats.d.ts +17 -9
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +54 -23
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +41 -14
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/communities.js +83 -3
- package/lib/Socket/communities.js.map +1 -1
- package/lib/Socket/groups.d.ts +16 -9
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +14 -11
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +41 -14
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/index.js +1 -0
- package/lib/Socket/index.js.map +1 -1
- package/lib/Socket/messages-recv.d.ts +26 -16
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +512 -311
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +27 -16
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +394 -133
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +18 -12
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +3 -1
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts +13 -3
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +353 -78
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +12 -1
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Bussines.d.ts.map +1 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Bussines.js.map +1 -0
- package/lib/Types/Chat.d.ts +5 -0
- package/lib/Types/Chat.d.ts.map +1 -1
- package/lib/Types/Chat.js.map +1 -1
- package/lib/Types/Contact.d.ts +4 -4
- package/lib/Types/Contact.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +8 -5
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/GroupMetadata.d.ts +7 -4
- package/lib/Types/GroupMetadata.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +38 -12
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js +5 -1
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/Signal.d.ts +18 -0
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Types/Socket.d.ts +24 -13
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Types/Socket.js.map +1 -1
- package/lib/Utils/auth-utils.d.ts +2 -2
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +178 -111
- 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 +6 -7
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +19 -2
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/crypto.d.ts +6 -6
- package/lib/Utils/crypto.d.ts.map +1 -1
- package/lib/Utils/crypto.js +16 -12
- package/lib/Utils/crypto.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts +14 -2
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +104 -15
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/event-buffer.d.ts +0 -1
- package/lib/Utils/event-buffer.d.ts.map +1 -1
- package/lib/Utils/event-buffer.js +65 -20
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts +5 -7
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +59 -51
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts +8 -9
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +8 -3
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/index.d.ts +2 -1
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +2 -1
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/link-preview.d.ts +1 -2
- package/lib/Utils/link-preview.d.ts.map +1 -1
- package/lib/Utils/link-preview.js +1 -1
- package/lib/Utils/link-preview.js.map +1 -1
- package/lib/Utils/message-retry-manager.d.ts +82 -0
- package/lib/Utils/message-retry-manager.d.ts.map +1 -0
- package/lib/Utils/message-retry-manager.js +172 -0
- package/lib/Utils/message-retry-manager.js.map +1 -0
- package/lib/Utils/messages-media.d.ts +14 -12
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +48 -24
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts +17 -4
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +85 -21
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/noise-handler.js +2 -1
- package/lib/Utils/noise-handler.js.map +1 -1
- package/lib/Utils/pre-key-manager.d.ts +28 -0
- package/lib/Utils/pre-key-manager.d.ts.map +1 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/pre-key-manager.js.map +1 -0
- package/lib/Utils/process-message.d.ts +26 -8
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +141 -24
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/signal.d.ts +4 -4
- package/lib/Utils/signal.d.ts.map +1 -1
- package/lib/Utils/signal.js +21 -12
- package/lib/Utils/signal.js.map +1 -1
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +50 -14
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/decode.d.ts.map +1 -1
- package/lib/WABinary/decode.js +12 -2
- package/lib/WABinary/decode.js.map +1 -1
- package/lib/WABinary/generic-utils.js +1 -1
- package/lib/WABinary/generic-utils.js.map +1 -1
- package/lib/WABinary/jid-utils.d.ts +18 -6
- package/lib/WABinary/jid-utils.d.ts.map +1 -1
- package/lib/WABinary/jid-utils.js +52 -8
- package/lib/WABinary/jid-utils.js.map +1 -1
- package/lib/WAM/constants.d.ts +1 -1
- package/lib/WAM/constants.d.ts.map +1 -1
- package/lib/WAM/constants.js +18516 -10904
- package/lib/WAM/constants.js.map +1 -1
- package/lib/WAM/encode.d.ts.map +1 -1
- package/lib/WAM/encode.js +0 -1
- package/lib/WAM/encode.js.map +1 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +2 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +10 -2
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -1
- package/lib/WAUSync/USyncQuery.d.ts +1 -1
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -1
- package/lib/WAUSync/USyncQuery.js +23 -20
- package/lib/WAUSync/USyncQuery.js.map +1 -1
- package/package.json +16 -11
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Signal/Group/queue-job.d.ts +0 -2
- package/lib/Signal/Group/queue-job.d.ts.map +0 -1
- package/lib/Signal/Group/queue-job.js +0 -54
- package/lib/Signal/Group/queue-job.js.map +0 -1
- package/lib/Socket/usync.d.ts +0 -37
- package/lib/Socket/usync.d.ts.map +0 -1
- package/lib/Socket/usync.js +0 -63
- package/lib/Socket/usync.js.map +0 -1
- package/lib/Utils/baileys-event-stream.d.ts +0 -17
- package/lib/Utils/baileys-event-stream.d.ts.map +0 -1
- package/lib/Utils/baileys-event-stream.js +0 -56
- package/lib/Utils/baileys-event-stream.js.map +0 -1
|
@@ -2,21 +2,29 @@ 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, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/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';
|
|
6
6
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
7
|
-
import {
|
|
7
|
+
import { makeKeyedMutex } from '../Utils/make-mutex.js';
|
|
8
|
+
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidGroup, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
8
9
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
9
|
-
import { makeGroupsSocket } from './groups.js';
|
|
10
10
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
11
11
|
export const makeMessagesSocket = (config) => {
|
|
12
|
-
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options:
|
|
13
|
-
const sock = makeNewsletterSocket(
|
|
12
|
+
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
13
|
+
const sock = makeNewsletterSocket(config);
|
|
14
14
|
const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
|
|
15
15
|
const userDevicesCache = config.userDevicesCache ||
|
|
16
16
|
new NodeCache({
|
|
17
17
|
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
18
18
|
useClones: false
|
|
19
19
|
});
|
|
20
|
+
const peerSessionsCache = new NodeCache({
|
|
21
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
22
|
+
useClones: false
|
|
23
|
+
});
|
|
24
|
+
// Initialize message retry manager if enabled
|
|
25
|
+
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
26
|
+
// Prevent race conditions in Signal session encryption by user
|
|
27
|
+
const encryptionMutex = makeKeyedMutex();
|
|
20
28
|
let mediaConn;
|
|
21
29
|
const refreshMediaConn = async (forceGet = false) => {
|
|
22
30
|
const media = await mediaConn;
|
|
@@ -32,6 +40,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
32
40
|
content: [{ tag: 'media_conn', attrs: {} }]
|
|
33
41
|
});
|
|
34
42
|
const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
|
|
43
|
+
// TODO: explore full length of data that whatsapp provides
|
|
35
44
|
const node = {
|
|
36
45
|
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
37
46
|
hostname: attrs.hostname,
|
|
@@ -65,7 +74,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
65
74
|
if (isReadReceipt) {
|
|
66
75
|
node.attrs.t = unixTimestampSeconds().toString();
|
|
67
76
|
}
|
|
68
|
-
if (type === 'sender' &&
|
|
77
|
+
if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
|
|
69
78
|
node.attrs.recipient = jid;
|
|
70
79
|
node.attrs.to = participant;
|
|
71
80
|
}
|
|
@@ -115,14 +124,39 @@ export const makeMessagesSocket = (config) => {
|
|
|
115
124
|
logger.debug('not using cache for devices');
|
|
116
125
|
}
|
|
117
126
|
const toFetch = [];
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
127
|
+
const jidsWithUser = jids
|
|
128
|
+
.map(jid => {
|
|
129
|
+
const decoded = jidDecode(jid);
|
|
130
|
+
const user = decoded?.user;
|
|
131
|
+
const device = decoded?.device;
|
|
132
|
+
const isExplicitDevice = typeof device === 'number' && device >= 0;
|
|
133
|
+
if (isExplicitDevice && user) {
|
|
134
|
+
deviceResults.push({
|
|
135
|
+
user,
|
|
136
|
+
device,
|
|
137
|
+
jid
|
|
138
|
+
});
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
121
141
|
jid = jidNormalizedUser(jid);
|
|
142
|
+
return { jid, user };
|
|
143
|
+
})
|
|
144
|
+
.filter(jid => jid !== null);
|
|
145
|
+
let mgetDevices;
|
|
146
|
+
if (useCache && userDevicesCache.mget) {
|
|
147
|
+
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean);
|
|
148
|
+
mgetDevices = await userDevicesCache.mget(usersToFetch);
|
|
149
|
+
}
|
|
150
|
+
for (const { jid, user } of jidsWithUser) {
|
|
122
151
|
if (useCache) {
|
|
123
|
-
const devices =
|
|
152
|
+
const devices = mgetDevices?.[user] ||
|
|
153
|
+
(userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)));
|
|
124
154
|
if (devices) {
|
|
125
|
-
|
|
155
|
+
const devicesWithJid = devices.map(d => ({
|
|
156
|
+
...d,
|
|
157
|
+
jid: jidEncode(d.user, d.server, d.device)
|
|
158
|
+
}));
|
|
159
|
+
deviceResults.push(...devicesWithJid);
|
|
126
160
|
logger.trace({ user }, 'using cache for devices');
|
|
127
161
|
}
|
|
128
162
|
else {
|
|
@@ -136,43 +170,121 @@ export const makeMessagesSocket = (config) => {
|
|
|
136
170
|
if (!toFetch.length) {
|
|
137
171
|
return deviceResults;
|
|
138
172
|
}
|
|
139
|
-
const
|
|
173
|
+
const requestedLidUsers = new Set();
|
|
174
|
+
for (const jid of toFetch) {
|
|
175
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
176
|
+
const user = jidDecode(jid)?.user;
|
|
177
|
+
if (user)
|
|
178
|
+
requestedLidUsers.add(user);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
|
|
140
182
|
for (const jid of toFetch) {
|
|
141
|
-
query.withUser(new USyncUser().withId(jid));
|
|
183
|
+
query.withUser(new USyncUser().withId(jid)); // todo: investigate - the idea here is that <user> should have an inline lid field with the lid being the pn equivalent
|
|
142
184
|
}
|
|
143
185
|
const result = await sock.executeUSyncQuery(query);
|
|
144
186
|
if (result) {
|
|
145
|
-
|
|
187
|
+
// TODO: LID MAP this stuff (lid protocol will now return lid with devices)
|
|
188
|
+
const lidResults = result.list.filter(a => !!a.lid);
|
|
189
|
+
if (lidResults.length > 0) {
|
|
190
|
+
logger.trace('Storing LID maps from device call');
|
|
191
|
+
await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
|
|
192
|
+
// Force-refresh sessions for newly mapped LIDs to align identity addressing
|
|
193
|
+
try {
|
|
194
|
+
const lids = lidResults.map(a => a.lid);
|
|
195
|
+
if (lids.length) {
|
|
196
|
+
await assertSessions(lids, true);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch (e) {
|
|
200
|
+
logger.warn({ e, count: lidResults.length }, 'failed to assert sessions for newly mapped LIDs');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices);
|
|
146
204
|
const deviceMap = {};
|
|
147
205
|
for (const item of extracted) {
|
|
148
206
|
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
149
207
|
deviceMap[item.user]?.push(item);
|
|
150
|
-
deviceResults.push(item);
|
|
151
208
|
}
|
|
152
|
-
|
|
153
|
-
|
|
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 finalJid = isLidUser
|
|
215
|
+
? jidEncode(user, item.server, item.device)
|
|
216
|
+
: jidEncode(item.user, item.server, item.device);
|
|
217
|
+
deviceResults.push({
|
|
218
|
+
...item,
|
|
219
|
+
jid: finalJid
|
|
220
|
+
});
|
|
221
|
+
logger.debug({
|
|
222
|
+
user: item.user,
|
|
223
|
+
device: item.device,
|
|
224
|
+
finalJid,
|
|
225
|
+
usedLid: isLidUser
|
|
226
|
+
}, 'Processed device with LID priority');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (userDevicesCache.mset) {
|
|
230
|
+
// if the cache supports mset, we can set all devices in one go
|
|
231
|
+
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
for (const key in deviceMap) {
|
|
235
|
+
if (deviceMap[key])
|
|
236
|
+
await userDevicesCache.set(key, deviceMap[key]);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const userDeviceUpdates = {};
|
|
240
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
241
|
+
if (devices && devices.length > 0) {
|
|
242
|
+
userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
246
|
+
try {
|
|
247
|
+
await authState.keys.set({ 'device-list': userDeviceUpdates });
|
|
248
|
+
logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration');
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
logger.warn({ error }, 'failed to store user device lists');
|
|
252
|
+
}
|
|
154
253
|
}
|
|
155
254
|
}
|
|
156
255
|
return deviceResults;
|
|
157
256
|
};
|
|
158
257
|
const assertSessions = async (jids, force) => {
|
|
159
258
|
let didFetchNewSession = false;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
jidsRequiringFetch.push(jid);
|
|
259
|
+
const uniqueJids = [...new Set(jids)]; // Deduplicate JIDs
|
|
260
|
+
const jidsRequiringFetch = [];
|
|
261
|
+
logger.debug({ jids }, 'assertSessions call with jids');
|
|
262
|
+
// Check peerSessionsCache and validate sessions using libsignal loadSession
|
|
263
|
+
for (const jid of uniqueJids) {
|
|
264
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
265
|
+
const cachedSession = peerSessionsCache.get(signalId);
|
|
266
|
+
if (cachedSession !== undefined) {
|
|
267
|
+
if (cachedSession && !force) {
|
|
268
|
+
continue; // Session exists in cache
|
|
171
269
|
}
|
|
172
270
|
}
|
|
271
|
+
else {
|
|
272
|
+
const sessionValidation = await signalRepository.validateSession(jid);
|
|
273
|
+
const hasSession = sessionValidation.exists;
|
|
274
|
+
peerSessionsCache.set(signalId, hasSession);
|
|
275
|
+
if (hasSession && !force) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
jidsRequiringFetch.push(jid);
|
|
173
280
|
}
|
|
174
281
|
if (jidsRequiringFetch.length) {
|
|
175
|
-
|
|
282
|
+
// LID if mapped, otherwise original
|
|
283
|
+
const wireJids = [
|
|
284
|
+
...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
285
|
+
...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
|
|
286
|
+
];
|
|
287
|
+
logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions');
|
|
176
288
|
const result = await query({
|
|
177
289
|
tag: 'iq',
|
|
178
290
|
attrs: {
|
|
@@ -184,15 +296,22 @@ export const makeMessagesSocket = (config) => {
|
|
|
184
296
|
{
|
|
185
297
|
tag: 'key',
|
|
186
298
|
attrs: {},
|
|
187
|
-
content:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
299
|
+
content: wireJids.map(jid => {
|
|
300
|
+
const attrs = { jid };
|
|
301
|
+
if (force)
|
|
302
|
+
attrs.reason = 'identity';
|
|
303
|
+
return { tag: 'user', attrs };
|
|
304
|
+
})
|
|
191
305
|
}
|
|
192
306
|
]
|
|
193
307
|
});
|
|
194
308
|
await parseAndInjectE2ESessions(result, signalRepository);
|
|
195
309
|
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
|
+
}
|
|
196
315
|
}
|
|
197
316
|
return didFetchNewSession;
|
|
198
317
|
};
|
|
@@ -212,59 +331,92 @@ export const makeMessagesSocket = (config) => {
|
|
|
212
331
|
additionalAttributes: {
|
|
213
332
|
category: 'peer',
|
|
214
333
|
push_priority: 'high_force'
|
|
215
|
-
}
|
|
334
|
+
},
|
|
335
|
+
additionalNodes: [
|
|
336
|
+
{
|
|
337
|
+
tag: 'meta',
|
|
338
|
+
attrs: { appdata: 'default' }
|
|
339
|
+
}
|
|
340
|
+
]
|
|
216
341
|
});
|
|
217
342
|
return msgId;
|
|
218
343
|
};
|
|
219
|
-
const createParticipantNodes = async (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
344
|
+
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
345
|
+
if (!recipientJids.length) {
|
|
346
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
347
|
+
}
|
|
348
|
+
const patched = await patchMessageBeforeSending(message, recipientJids);
|
|
349
|
+
const patchedMessages = Array.isArray(patched)
|
|
350
|
+
? patched
|
|
351
|
+
: recipientJids.map(jid => ({ recipientJid: jid, message: patched }));
|
|
224
352
|
let shouldIncludeDeviceIdentity = false;
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
353
|
+
const meId = authState.creds.me.id;
|
|
354
|
+
const meLid = authState.creds.me?.lid;
|
|
355
|
+
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
356
|
+
const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
357
|
+
if (!jid)
|
|
358
|
+
return null;
|
|
359
|
+
let msgToEncrypt = patchedMessage;
|
|
360
|
+
if (dsmMessage) {
|
|
361
|
+
const { user: targetUser } = jidDecode(jid);
|
|
362
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
363
|
+
const ownLidUser = meLidUser;
|
|
364
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
365
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
366
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
367
|
+
msgToEncrypt = dsmMessage;
|
|
368
|
+
logger.debug({ jid, targetUser }, 'Using DSM for own device');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
372
|
+
const mutexKey = jid;
|
|
373
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
374
|
+
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
375
|
+
jid,
|
|
376
|
+
data: bytes
|
|
377
|
+
});
|
|
378
|
+
if (type === 'pkmsg') {
|
|
379
|
+
shouldIncludeDeviceIdentity = true;
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
tag: 'to',
|
|
383
|
+
attrs: { jid },
|
|
384
|
+
content: [
|
|
385
|
+
{
|
|
386
|
+
tag: 'enc',
|
|
387
|
+
attrs: {
|
|
388
|
+
v: '2',
|
|
389
|
+
type,
|
|
390
|
+
...(extraAttrs || {})
|
|
391
|
+
},
|
|
392
|
+
content: ciphertext
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
};
|
|
396
|
+
});
|
|
250
397
|
return node;
|
|
251
|
-
})
|
|
398
|
+
});
|
|
399
|
+
const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
|
|
252
400
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
253
401
|
};
|
|
254
402
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
255
403
|
const meId = authState.creds.me.id;
|
|
256
|
-
|
|
257
|
-
const
|
|
404
|
+
const meLid = authState.creds.me?.lid;
|
|
405
|
+
const isRetryResend = Boolean(participant?.jid);
|
|
406
|
+
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
258
407
|
const statusJid = 'status@broadcast';
|
|
408
|
+
const { user, server } = jidDecode(jid);
|
|
259
409
|
const isGroup = server === 'g.us';
|
|
260
410
|
const isStatus = jid === statusJid;
|
|
261
411
|
const isLid = server === 'lid';
|
|
262
412
|
const isNewsletter = server === 'newsletter';
|
|
263
|
-
|
|
413
|
+
const isGroupOrStatus = isGroup || isStatus;
|
|
414
|
+
const finalJid = jid;
|
|
415
|
+
msgId = msgId || generateMessageIDV2(meId);
|
|
264
416
|
useUserDevicesCache = useUserDevicesCache !== false;
|
|
265
417
|
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
266
418
|
const participants = [];
|
|
267
|
-
const destinationJid = !isStatus ?
|
|
419
|
+
const destinationJid = !isStatus ? finalJid : statusJid;
|
|
268
420
|
const binaryNodeContent = [];
|
|
269
421
|
const devices = [];
|
|
270
422
|
const meMsg = {
|
|
@@ -276,14 +428,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
276
428
|
};
|
|
277
429
|
const extraAttrs = {};
|
|
278
430
|
if (participant) {
|
|
279
|
-
// when the retry request is not for a group
|
|
280
|
-
// only send to the specific device that asked for a retry
|
|
281
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
282
431
|
if (!isGroup && !isStatus) {
|
|
283
432
|
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
|
|
284
433
|
}
|
|
285
434
|
const { user, device } = jidDecode(participant.jid);
|
|
286
|
-
devices.push({
|
|
435
|
+
devices.push({
|
|
436
|
+
user,
|
|
437
|
+
device,
|
|
438
|
+
jid: participant.jid
|
|
439
|
+
});
|
|
287
440
|
}
|
|
288
441
|
await authState.keys.transaction(async () => {
|
|
289
442
|
const mediaType = getMediaType(message);
|
|
@@ -291,7 +444,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
291
444
|
extraAttrs['mediatype'] = mediaType;
|
|
292
445
|
}
|
|
293
446
|
if (isNewsletter) {
|
|
294
|
-
// Patch message if needed, then encode as plaintext
|
|
295
447
|
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
296
448
|
const bytes = encodeNewsletterMessage(patched);
|
|
297
449
|
binaryNodeContent.push({
|
|
@@ -314,119 +466,198 @@ export const makeMessagesSocket = (config) => {
|
|
|
314
466
|
return;
|
|
315
467
|
}
|
|
316
468
|
if (normalizeMessageContent(message)?.pinInChatMessage) {
|
|
317
|
-
extraAttrs['decrypt-fail'] = 'hide';
|
|
469
|
+
extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
|
|
318
470
|
}
|
|
319
|
-
if (
|
|
471
|
+
if (isGroupOrStatus && !isRetryResend) {
|
|
320
472
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
321
473
|
(async () => {
|
|
322
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
474
|
+
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined; // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
|
|
323
475
|
if (groupData && Array.isArray(groupData?.participants)) {
|
|
324
476
|
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
|
|
325
477
|
}
|
|
326
478
|
else if (!isStatus) {
|
|
327
|
-
groupData = await groupMetadata(jid);
|
|
479
|
+
groupData = await groupMetadata(jid); // TODO: start storing group participant list + addr mode in Signal & stop relying on this
|
|
328
480
|
}
|
|
329
481
|
return groupData;
|
|
330
482
|
})(),
|
|
331
483
|
(async () => {
|
|
332
484
|
if (!participant && !isStatus) {
|
|
333
|
-
|
|
485
|
+
// what if sender memory is less accurate than the cached metadata
|
|
486
|
+
// on participant change in group, we should do sender memory manipulation
|
|
487
|
+
const result = await authState.keys.get('sender-key-memory', [jid]); // TODO: check out what if the sender key memory doesn't include the LID stuff now?
|
|
334
488
|
return result[jid] || {};
|
|
335
489
|
}
|
|
336
490
|
return {};
|
|
337
491
|
})()
|
|
338
492
|
]);
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
493
|
+
const participantsList = groupData ? groupData.participants.map(p => p.id) : [];
|
|
494
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
495
|
+
additionalAttributes = {
|
|
496
|
+
...additionalAttributes,
|
|
497
|
+
expiration: groupData.ephemeralDuration.toString()
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
if (isStatus && statusJidList) {
|
|
501
|
+
participantsList.push(...statusJidList);
|
|
502
|
+
}
|
|
503
|
+
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
|
|
504
|
+
devices.push(...additionalDevices);
|
|
505
|
+
if (isGroup) {
|
|
506
|
+
additionalAttributes = {
|
|
507
|
+
...additionalAttributes,
|
|
508
|
+
addressing_mode: groupData?.addressingMode || 'lid'
|
|
509
|
+
};
|
|
352
510
|
}
|
|
353
511
|
const patched = await patchMessageBeforeSending(message);
|
|
354
512
|
if (Array.isArray(patched)) {
|
|
355
513
|
throw new Boom('Per-jid patching is not supported in groups');
|
|
356
514
|
}
|
|
357
515
|
const bytes = encodeWAMessage(patched);
|
|
516
|
+
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
|
|
517
|
+
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
358
518
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
359
519
|
group: destinationJid,
|
|
360
520
|
data: bytes,
|
|
361
|
-
meId
|
|
521
|
+
meId: groupSenderIdentity
|
|
362
522
|
});
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
if (!
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
523
|
+
const senderKeyRecipients = [];
|
|
524
|
+
for (const device of devices) {
|
|
525
|
+
const deviceJid = device.jid;
|
|
526
|
+
const hasKey = !!senderKeyMap[deviceJid];
|
|
527
|
+
if ((!hasKey || !!participant) &&
|
|
528
|
+
!isHostedLidUser(deviceJid) &&
|
|
529
|
+
!isHostedPnUser(deviceJid) &&
|
|
530
|
+
device.device !== 99) {
|
|
531
|
+
//todo: revamp all this logic
|
|
532
|
+
// the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
|
|
533
|
+
senderKeyRecipients.push(deviceJid);
|
|
534
|
+
senderKeyMap[deviceJid] = true;
|
|
371
535
|
}
|
|
372
536
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if (senderKeyJids.length) {
|
|
376
|
-
logger.debug({ senderKeyJids }, 'sending new sender key');
|
|
537
|
+
if (senderKeyRecipients.length) {
|
|
538
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
|
|
377
539
|
const senderKeyMsg = {
|
|
378
540
|
senderKeyDistributionMessage: {
|
|
379
541
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
380
542
|
groupId: destinationJid
|
|
381
543
|
}
|
|
382
544
|
};
|
|
383
|
-
|
|
384
|
-
|
|
545
|
+
const senderKeySessionTargets = senderKeyRecipients;
|
|
546
|
+
await assertSessions(senderKeySessionTargets);
|
|
547
|
+
const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
|
|
385
548
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
386
549
|
participants.push(...result.nodes);
|
|
387
550
|
}
|
|
388
551
|
binaryNodeContent.push({
|
|
389
552
|
tag: 'enc',
|
|
390
|
-
attrs: { v: '2', type: 'skmsg' },
|
|
553
|
+
attrs: { v: '2', type: 'skmsg', ...extraAttrs },
|
|
391
554
|
content: ciphertext
|
|
392
555
|
});
|
|
393
556
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
394
557
|
}
|
|
395
558
|
else {
|
|
396
|
-
|
|
397
|
-
if
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
559
|
+
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
560
|
+
// TODO: investigate if this is true
|
|
561
|
+
let ownId = meId;
|
|
562
|
+
if (isLid && meLid) {
|
|
563
|
+
ownId = meLid;
|
|
564
|
+
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
|
|
568
|
+
}
|
|
569
|
+
const { user: ownUser } = jidDecode(ownId);
|
|
570
|
+
if (!isRetryResend) {
|
|
571
|
+
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
572
|
+
devices.push({
|
|
573
|
+
user,
|
|
574
|
+
device: 0,
|
|
575
|
+
jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
|
|
576
|
+
});
|
|
577
|
+
if (user !== ownUser) {
|
|
578
|
+
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
579
|
+
const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
580
|
+
devices.push({
|
|
581
|
+
user: ownUserForAddressing,
|
|
582
|
+
device: 0,
|
|
583
|
+
jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
584
|
+
});
|
|
401
585
|
}
|
|
402
586
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
403
|
-
|
|
404
|
-
devices.
|
|
587
|
+
// Clear placeholders and enumerate actual devices
|
|
588
|
+
devices.length = 0;
|
|
589
|
+
// Use conversation-appropriate sender identity
|
|
590
|
+
const senderIdentity = isLid && meLid
|
|
591
|
+
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
592
|
+
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
593
|
+
// Enumerate devices for sender and target with consistent addressing
|
|
594
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
595
|
+
devices.push(...sessionDevices);
|
|
596
|
+
logger.debug({
|
|
597
|
+
deviceCount: devices.length,
|
|
598
|
+
devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
|
|
599
|
+
}, 'Device enumeration complete with unified addressing');
|
|
405
600
|
}
|
|
406
601
|
}
|
|
407
|
-
const
|
|
408
|
-
const
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
602
|
+
const allRecipients = [];
|
|
603
|
+
const meRecipients = [];
|
|
604
|
+
const otherRecipients = [];
|
|
605
|
+
const { user: mePnUser } = jidDecode(meId);
|
|
606
|
+
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
|
|
607
|
+
for (const { user, jid } of devices) {
|
|
608
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
609
|
+
if (isExactSenderDevice) {
|
|
610
|
+
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
// Check if this is our device (could match either PN or LID user)
|
|
614
|
+
const isMe = user === mePnUser || user === meLidUser;
|
|
413
615
|
if (isMe) {
|
|
414
|
-
|
|
616
|
+
meRecipients.push(jid);
|
|
415
617
|
}
|
|
416
618
|
else {
|
|
417
|
-
|
|
619
|
+
otherRecipients.push(jid);
|
|
418
620
|
}
|
|
419
|
-
|
|
621
|
+
allRecipients.push(jid);
|
|
420
622
|
}
|
|
421
|
-
await assertSessions(
|
|
623
|
+
await assertSessions(allRecipients);
|
|
422
624
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
423
|
-
|
|
424
|
-
createParticipantNodes(
|
|
625
|
+
// For own devices: use DSM if available (1:1 chats only)
|
|
626
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
627
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
425
628
|
]);
|
|
426
629
|
participants.push(...meNodes);
|
|
427
630
|
participants.push(...otherNodes);
|
|
631
|
+
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
632
|
+
extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
|
|
633
|
+
}
|
|
428
634
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
429
635
|
}
|
|
636
|
+
if (isRetryResend) {
|
|
637
|
+
const isParticipantLid = isLidUser(participant.jid);
|
|
638
|
+
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
|
|
639
|
+
const encodedMessageToSend = isMe
|
|
640
|
+
? encodeWAMessage({
|
|
641
|
+
deviceSentMessage: {
|
|
642
|
+
destinationJid,
|
|
643
|
+
message
|
|
644
|
+
}
|
|
645
|
+
})
|
|
646
|
+
: encodeWAMessage(message);
|
|
647
|
+
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
648
|
+
data: encodedMessageToSend,
|
|
649
|
+
jid: participant.jid
|
|
650
|
+
});
|
|
651
|
+
binaryNodeContent.push({
|
|
652
|
+
tag: 'enc',
|
|
653
|
+
attrs: {
|
|
654
|
+
v: '2',
|
|
655
|
+
type,
|
|
656
|
+
count: participant.count.toString()
|
|
657
|
+
},
|
|
658
|
+
content: encryptedContent
|
|
659
|
+
});
|
|
660
|
+
}
|
|
430
661
|
if (participants.length) {
|
|
431
662
|
if (additionalAttributes?.['category'] === 'peer') {
|
|
432
663
|
const peerNode = participants[0]?.content?.[0];
|
|
@@ -446,6 +677,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
446
677
|
tag: 'message',
|
|
447
678
|
attrs: {
|
|
448
679
|
id: msgId,
|
|
680
|
+
to: destinationJid,
|
|
449
681
|
type: getMessageType(message),
|
|
450
682
|
...(additionalAttributes || {})
|
|
451
683
|
},
|
|
@@ -479,19 +711,39 @@ export const makeMessagesSocket = (config) => {
|
|
|
479
711
|
});
|
|
480
712
|
logger.debug({ jid }, 'adding device identity');
|
|
481
713
|
}
|
|
714
|
+
const contactTcTokenData = !isGroup && !isRetryResend && !isStatus ? await authState.keys.get('tctoken', [destinationJid]) : {};
|
|
715
|
+
const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
|
|
716
|
+
if (tcTokenBuffer) {
|
|
717
|
+
;
|
|
718
|
+
stanza.content.push({
|
|
719
|
+
tag: 'tctoken',
|
|
720
|
+
attrs: {},
|
|
721
|
+
content: tcTokenBuffer
|
|
722
|
+
});
|
|
723
|
+
}
|
|
482
724
|
if (additionalNodes && additionalNodes.length > 0) {
|
|
483
725
|
;
|
|
484
726
|
stanza.content.push(...additionalNodes);
|
|
485
727
|
}
|
|
486
728
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
487
729
|
await sendNode(stanza);
|
|
488
|
-
|
|
730
|
+
// Add message to retry cache if enabled
|
|
731
|
+
if (messageRetryManager && !participant) {
|
|
732
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
733
|
+
}
|
|
734
|
+
}, meId);
|
|
489
735
|
return msgId;
|
|
490
736
|
};
|
|
491
737
|
const getMessageType = (message) => {
|
|
492
738
|
if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
|
|
493
739
|
return 'poll';
|
|
494
740
|
}
|
|
741
|
+
if (message.eventMessage) {
|
|
742
|
+
return 'event';
|
|
743
|
+
}
|
|
744
|
+
if (getMediaType(message) !== '') {
|
|
745
|
+
return 'media';
|
|
746
|
+
}
|
|
495
747
|
return 'text';
|
|
496
748
|
};
|
|
497
749
|
const getMediaType = (message) => {
|
|
@@ -540,6 +792,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
540
792
|
else if (message.groupInviteMessage) {
|
|
541
793
|
return 'url';
|
|
542
794
|
}
|
|
795
|
+
return '';
|
|
543
796
|
};
|
|
544
797
|
const getPrivacyTokens = async (jids) => {
|
|
545
798
|
const t = unixTimestampSeconds().toString();
|
|
@@ -583,6 +836,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
583
836
|
sendPeerDataOperationMessage,
|
|
584
837
|
createParticipantNodes,
|
|
585
838
|
getUSyncDevices,
|
|
839
|
+
messageRetryManager,
|
|
586
840
|
updateMediaMessage: async (message) => {
|
|
587
841
|
const content = assertMediaContent(message.message);
|
|
588
842
|
const mediaKey = content.mediaKey;
|
|
@@ -647,19 +901,21 @@ export const makeMessagesSocket = (config) => {
|
|
|
647
901
|
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
648
902
|
fetchOpts: {
|
|
649
903
|
timeout: 3000,
|
|
650
|
-
...(
|
|
904
|
+
...(httpRequestOptions || {})
|
|
651
905
|
},
|
|
652
906
|
logger,
|
|
653
907
|
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
654
908
|
}),
|
|
655
909
|
//TODO: CACHE
|
|
656
910
|
getProfilePicUrl: sock.profilePictureUrl,
|
|
911
|
+
getCallLink: sock.createCallLink,
|
|
657
912
|
upload: waUploadToServer,
|
|
658
913
|
mediaCache: config.mediaCache,
|
|
659
914
|
options: config.options,
|
|
660
915
|
messageId: options.messageId || generateMessageIDV2(sock.user?.id),
|
|
661
916
|
...options
|
|
662
917
|
});
|
|
918
|
+
const isEventMsg = 'event' in content && !!content.event;
|
|
663
919
|
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
664
920
|
const isEditMsg = 'edit' in content && !!content.edit;
|
|
665
921
|
const isPinMsg = 'pin' in content && !!content.pin;
|
|
@@ -690,8 +946,13 @@ export const makeMessagesSocket = (config) => {
|
|
|
690
946
|
}
|
|
691
947
|
});
|
|
692
948
|
}
|
|
693
|
-
if (
|
|
694
|
-
|
|
949
|
+
else if (isEventMsg) {
|
|
950
|
+
additionalNodes.push({
|
|
951
|
+
tag: 'meta',
|
|
952
|
+
attrs: {
|
|
953
|
+
event_type: 'creation'
|
|
954
|
+
}
|
|
955
|
+
});
|
|
695
956
|
}
|
|
696
957
|
await relayMessage(jid, fullMsg.message, {
|
|
697
958
|
messageId: fullMsg.key.id,
|
|
@@ -701,8 +962,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
701
962
|
additionalNodes
|
|
702
963
|
});
|
|
703
964
|
if (config.emitOwnEvents) {
|
|
704
|
-
process.nextTick(() => {
|
|
705
|
-
processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
965
|
+
process.nextTick(async () => {
|
|
966
|
+
await processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
706
967
|
});
|
|
707
968
|
}
|
|
708
969
|
return fullMsg;
|