@sanzoffc/baileys 3.0.1 → 3.0.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/LICENSE +1 -1
- package/WAProto/WAProto.proto +769 -233
- package/WAProto/index.js +65801 -141371
- package/lib/Defaults/index.js +117 -114
- package/lib/Defaults/index.js.bak +123 -0
- package/lib/KeyDB/BinarySearch.js +20 -0
- package/lib/KeyDB/KeyedDB.js +167 -0
- package/lib/KeyDB/index.js +4 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -14
- package/lib/Signal/Group/group-session-builder.js +10 -42
- package/lib/Signal/Group/group_cipher.js +75 -87
- package/lib/Signal/Group/index.js +13 -57
- package/lib/Signal/Group/keyhelper.js +17 -52
- package/lib/Signal/Group/sender-chain-key.js +27 -33
- package/lib/Signal/Group/sender-key-distribution-message.js +62 -63
- package/lib/Signal/Group/sender-key-message.js +65 -66
- package/lib/Signal/Group/sender-key-name.js +45 -44
- package/lib/Signal/Group/sender-key-record.js +39 -49
- package/lib/Signal/Group/sender-key-state.js +80 -93
- package/lib/Signal/Group/sender-message-key.js +27 -28
- package/lib/Signal/libsignal.js +313 -163
- package/lib/Signal/lid-mapping.js +155 -0
- package/lib/Socket/Client/index.js +4 -18
- package/lib/Socket/Client/types.js +12 -12
- package/lib/Socket/Client/websocket.js +51 -71
- package/lib/Socket/Client/websocket.js.bak +53 -0
- package/lib/Socket/business.js +359 -242
- package/lib/Socket/chats.js +858 -945
- package/lib/Socket/communities.js +413 -0
- package/lib/Socket/groups.js +304 -324
- package/lib/Socket/index.js +15 -9
- package/lib/Socket/messages-recv.js +1105 -1046
- package/lib/Socket/messages-send.js +615 -389
- package/lib/Socket/mex.js +45 -0
- package/lib/Socket/newsletter.js +224 -227
- package/lib/Socket/socket.js +795 -621
- package/lib/Store/index.js +6 -8
- package/lib/Store/make-cache-manager-store.js +75 -0
- package/lib/Store/make-in-memory-store.js +286 -435
- package/lib/Store/make-ordered-dictionary.js +77 -79
- package/lib/Store/object-repository.js +24 -26
- package/lib/Types/Auth.js +3 -2
- package/lib/Types/Bussines.js +3 -0
- package/lib/Types/Call.js +3 -2
- package/lib/Types/Chat.js +9 -4
- package/lib/Types/Contact.js +3 -2
- package/lib/Types/Events.js +3 -2
- package/lib/Types/GroupMetadata.js +3 -2
- package/lib/Types/Label.js +24 -26
- package/lib/Types/LabelAssociation.js +6 -8
- package/lib/Types/Message.js +12 -7
- package/lib/Types/Newsletter.js +32 -17
- package/lib/Types/Newsletter.js.bak +33 -0
- package/lib/Types/Product.js +3 -2
- package/lib/Types/Signal.js +3 -2
- package/lib/Types/Socket.js +4 -2
- package/lib/Types/State.js +11 -2
- package/lib/Types/USync.js +3 -2
- package/lib/Types/index.js +27 -41
- package/lib/Utils/auth-utils.js +211 -191
- package/lib/Utils/baileys-event-stream.js +44 -0
- package/lib/Utils/browser-utils.js +21 -31
- package/lib/Utils/business.js +213 -214
- package/lib/Utils/chat-utils.js +711 -689
- package/lib/Utils/crypto.js +112 -175
- package/lib/Utils/decode-wa-message.js +254 -194
- package/lib/Utils/event-buffer.js +510 -500
- package/lib/Utils/generics.js +318 -430
- package/lib/Utils/history.js +83 -90
- package/lib/Utils/index.js +21 -35
- package/lib/Utils/link-preview.js +71 -116
- package/lib/Utils/logger.js +5 -7
- package/lib/Utils/lt-hash.js +40 -46
- package/lib/Utils/make-mutex.js +34 -41
- package/lib/Utils/message-retry-manager.js +33 -48
- package/lib/Utils/messages-media.js +573 -825
- package/lib/Utils/messages.js +349 -489
- package/lib/Utils/noise-handler.js +138 -144
- package/lib/Utils/pre-key-manager.js +85 -0
- package/lib/Utils/process-message.js +321 -384
- package/lib/Utils/signal.js +147 -139
- package/lib/Utils/use-multi-file-auth-state.js +95 -109
- package/lib/Utils/validate-connection.js +183 -212
- package/lib/WABinary/constants.js +1298 -1298
- package/lib/WABinary/decode.js +231 -256
- package/lib/WABinary/encode.js +207 -239
- package/lib/WABinary/generic-utils.js +119 -40
- package/lib/WABinary/index.js +7 -21
- package/lib/WABinary/jid-utils.js +87 -79
- package/lib/WABinary/types.js +3 -2
- package/lib/WAM/BinaryInfo.js +10 -12
- package/lib/WAM/constants.js +22851 -15348
- package/lib/WAM/encode.js +135 -136
- package/lib/WAM/index.js +5 -19
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -30
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +49 -53
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -28
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +36 -39
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -50
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +26 -20
- package/lib/WAUSync/Protocols/index.js +6 -20
- package/lib/WAUSync/USyncQuery.js +86 -85
- package/lib/WAUSync/USyncUser.js +23 -25
- package/lib/WAUSync/index.js +5 -19
- package/lib/index.js +18 -49
- package/package.json +65 -78
- package/README.MD +0 -1295
- package/WAProto/GenerateStatics.sh +0 -4
- package/WAProto/p.html +0 -1
- package/engine-requirements.js +0 -10
- package/lib/Defaults/wileys-version.json +0 -3
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/usync.js +0 -70
- package/lib/Utils/wileys-event-stream.js +0 -63
|
@@ -1,46 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import NodeCache from '@cacheable/node-cache';
|
|
2
|
+
import { Boom } from '@hapi/boom';
|
|
3
|
+
import { proto } from '../../WAProto/index.js';
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_CACHE_TTLS,
|
|
6
|
+
WA_DEFAULT_EPHEMERAL
|
|
7
|
+
} from '../Defaults/index.js';
|
|
8
|
+
import {
|
|
9
|
+
aggregateMessageKeysNotFromMe,
|
|
10
|
+
assertMediaContent,
|
|
11
|
+
bindWaitForEvent,
|
|
12
|
+
decryptMediaRetryData,
|
|
13
|
+
encodeNewsletterMessage,
|
|
14
|
+
encodeSignedDeviceIdentity,
|
|
15
|
+
encodeWAMessage,
|
|
16
|
+
encryptMediaRetryRequest,
|
|
17
|
+
extractDeviceJids,
|
|
18
|
+
generateMessageIDV2,
|
|
19
|
+
generateParticipantHashV2,
|
|
20
|
+
generateWAMessage,
|
|
21
|
+
getStatusCodeForMediaRetry,
|
|
22
|
+
getUrlFromDirectPath,
|
|
23
|
+
getWAUploadToServer,
|
|
24
|
+
MessageRetryManager,
|
|
25
|
+
normalizeMessageContent,
|
|
26
|
+
parseAndInjectE2ESessions,
|
|
27
|
+
unixTimestampSeconds
|
|
28
|
+
} from '../Utils/index.js';
|
|
29
|
+
import {
|
|
30
|
+
areJidsSameUser,
|
|
31
|
+
getBinaryNodeChild,
|
|
32
|
+
getBinaryNodeChildren,
|
|
33
|
+
getAdditionalNode,
|
|
34
|
+
getBinaryNodeFilter,
|
|
35
|
+
isHostedLidUser,
|
|
36
|
+
isHostedPnUser,
|
|
37
|
+
isJidGroup,
|
|
38
|
+
isLidUser,
|
|
39
|
+
isPnUser,
|
|
40
|
+
jidDecode,
|
|
41
|
+
jidEncode,
|
|
42
|
+
isJidNewsletter,
|
|
43
|
+
jidNormalizedUser,
|
|
44
|
+
S_WHATSAPP_NET
|
|
45
|
+
} from '../WABinary/index.js';
|
|
46
|
+
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
47
|
+
import { makeKeyedMutex } from '../Utils/make-mutex.js';
|
|
48
|
+
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
49
|
+
import { makeNewsletterSocket } from './newsletter.js';
|
|
50
|
+
export const makeMessagesSocket = (config) => {
|
|
51
|
+
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
52
|
+
const sock = makeNewsletterSocket(config);
|
|
53
|
+
const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
|
|
54
|
+
const userDevicesCache = config.userDevicesCache ||
|
|
55
|
+
new NodeCache({
|
|
56
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
57
|
+
useClones: false
|
|
58
|
+
});
|
|
59
|
+
const peerSessionsCache = new NodeCache({
|
|
60
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
23
61
|
useClones: false
|
|
24
62
|
});
|
|
63
|
+
// Initialize message retry manager if enabled
|
|
64
|
+
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
65
|
+
// Prevent race conditions in Signal session encryption by user
|
|
66
|
+
const encryptionMutex = makeKeyedMutex();
|
|
25
67
|
let mediaConn;
|
|
26
68
|
const refreshMediaConn = async (forceGet = false) => {
|
|
27
69
|
const media = await mediaConn;
|
|
28
|
-
if (!media || forceGet ||
|
|
70
|
+
if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
|
|
29
71
|
mediaConn = (async () => {
|
|
30
72
|
const result = await query({
|
|
31
73
|
tag: 'iq',
|
|
32
74
|
attrs: {
|
|
33
75
|
type: 'set',
|
|
34
76
|
xmlns: 'w:m',
|
|
35
|
-
to:
|
|
77
|
+
to: S_WHATSAPP_NET
|
|
36
78
|
},
|
|
37
79
|
content: [{ tag: 'media_conn', attrs: {} }]
|
|
38
80
|
});
|
|
39
|
-
const mediaConnNode =
|
|
81
|
+
const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
|
|
82
|
+
// TODO: explore full length of data that whatsapp provides
|
|
40
83
|
const node = {
|
|
41
|
-
hosts:
|
|
84
|
+
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
42
85
|
hostname: attrs.hostname,
|
|
43
|
-
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
86
|
+
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
44
87
|
})),
|
|
45
88
|
auth: mediaConnNode.attrs.auth,
|
|
46
89
|
ttl: +mediaConnNode.attrs.ttl,
|
|
@@ -57,17 +100,20 @@ const makeMessagesSocket = (config) => {
|
|
|
57
100
|
* used for receipts of phone call, read, delivery etc.
|
|
58
101
|
* */
|
|
59
102
|
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
103
|
+
if (!messageIds || messageIds.length === 0) {
|
|
104
|
+
throw new Boom('missing ids in receipt');
|
|
105
|
+
}
|
|
60
106
|
const node = {
|
|
61
107
|
tag: 'receipt',
|
|
62
108
|
attrs: {
|
|
63
|
-
id: messageIds[0]
|
|
64
|
-
}
|
|
109
|
+
id: messageIds[0]
|
|
110
|
+
}
|
|
65
111
|
};
|
|
66
112
|
const isReadReceipt = type === 'read' || type === 'read-self';
|
|
67
113
|
if (isReadReceipt) {
|
|
68
|
-
node.attrs.t =
|
|
114
|
+
node.attrs.t = unixTimestampSeconds().toString();
|
|
69
115
|
}
|
|
70
|
-
if (type === 'sender' && (
|
|
116
|
+
if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
|
|
71
117
|
node.attrs.recipient = jid;
|
|
72
118
|
node.attrs.to = participant;
|
|
73
119
|
}
|
|
@@ -78,7 +124,7 @@ const makeMessagesSocket = (config) => {
|
|
|
78
124
|
}
|
|
79
125
|
}
|
|
80
126
|
if (type) {
|
|
81
|
-
node.attrs.type =
|
|
127
|
+
node.attrs.type = type;
|
|
82
128
|
}
|
|
83
129
|
const remainingMessageIds = messageIds.slice(1);
|
|
84
130
|
if (remainingMessageIds.length) {
|
|
@@ -98,7 +144,7 @@ const makeMessagesSocket = (config) => {
|
|
|
98
144
|
};
|
|
99
145
|
/** Correctly bulk send receipts to multiple chats, participants */
|
|
100
146
|
const sendReceipts = async (keys, type) => {
|
|
101
|
-
const recps =
|
|
147
|
+
const recps = aggregateMessageKeysNotFromMe(keys);
|
|
102
148
|
for (const { jid, participant, messageIds } of recps) {
|
|
103
149
|
await sendReceipt(jid, participant, messageIds, type);
|
|
104
150
|
}
|
|
@@ -112,20 +158,44 @@ const makeMessagesSocket = (config) => {
|
|
|
112
158
|
};
|
|
113
159
|
/** Fetch all the devices we've to send a message to */
|
|
114
160
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
115
|
-
var _a;
|
|
116
161
|
const deviceResults = [];
|
|
117
162
|
if (!useCache) {
|
|
118
163
|
logger.debug('not using cache for devices');
|
|
119
164
|
}
|
|
120
165
|
const toFetch = [];
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
166
|
+
const jidsWithUser = jids
|
|
167
|
+
.map(jid => {
|
|
168
|
+
const decoded = jidDecode(jid);
|
|
169
|
+
const user = decoded?.user;
|
|
170
|
+
const device = decoded?.device;
|
|
171
|
+
const isExplicitDevice = typeof device === 'number' && device >= 0;
|
|
172
|
+
if (isExplicitDevice && user) {
|
|
173
|
+
deviceResults.push({
|
|
174
|
+
user,
|
|
175
|
+
device,
|
|
176
|
+
jid
|
|
177
|
+
});
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
jid = jidNormalizedUser(jid);
|
|
181
|
+
return { jid, user };
|
|
182
|
+
})
|
|
183
|
+
.filter(jid => jid !== null);
|
|
184
|
+
let mgetDevices;
|
|
185
|
+
if (useCache && userDevicesCache.mget) {
|
|
186
|
+
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean);
|
|
187
|
+
mgetDevices = await userDevicesCache.mget(usersToFetch);
|
|
188
|
+
}
|
|
189
|
+
for (const { jid, user } of jidsWithUser) {
|
|
125
190
|
if (useCache) {
|
|
126
|
-
const devices =
|
|
191
|
+
const devices = mgetDevices?.[user] ||
|
|
192
|
+
(userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)));
|
|
127
193
|
if (devices) {
|
|
128
|
-
|
|
194
|
+
const devicesWithJid = devices.map(d => ({
|
|
195
|
+
...d,
|
|
196
|
+
jid: jidEncode(d.user, d.server, d.device)
|
|
197
|
+
}));
|
|
198
|
+
deviceResults.push(...devicesWithJid);
|
|
129
199
|
logger.trace({ user }, 'using cache for devices');
|
|
130
200
|
}
|
|
131
201
|
else {
|
|
@@ -139,141 +209,243 @@ const makeMessagesSocket = (config) => {
|
|
|
139
209
|
if (!toFetch.length) {
|
|
140
210
|
return deviceResults;
|
|
141
211
|
}
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
212
|
+
const requestedLidUsers = new Set();
|
|
213
|
+
for (const jid of toFetch) {
|
|
214
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
215
|
+
const user = jidDecode(jid)?.user;
|
|
216
|
+
if (user)
|
|
217
|
+
requestedLidUsers.add(user);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
|
|
145
221
|
for (const jid of toFetch) {
|
|
146
|
-
query.withUser(new
|
|
222
|
+
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
|
|
147
223
|
}
|
|
148
224
|
const result = await sock.executeUSyncQuery(query);
|
|
149
225
|
if (result) {
|
|
150
|
-
|
|
226
|
+
// TODO: LID MAP this stuff (lid protocol will now return lid with devices)
|
|
227
|
+
const lidResults = result.list.filter(a => !!a.lid);
|
|
228
|
+
if (lidResults.length > 0) {
|
|
229
|
+
logger.trace('Storing LID maps from device call');
|
|
230
|
+
await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
|
|
231
|
+
}
|
|
232
|
+
const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices);
|
|
151
233
|
const deviceMap = {};
|
|
152
234
|
for (const item of extracted) {
|
|
153
235
|
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
154
|
-
deviceMap[item.user]
|
|
155
|
-
|
|
236
|
+
deviceMap[item.user]?.push(item);
|
|
237
|
+
}
|
|
238
|
+
// Process each user's devices as a group for bulk LID migration
|
|
239
|
+
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
240
|
+
const isLidUser = requestedLidUsers.has(user);
|
|
241
|
+
// Process all devices for this user
|
|
242
|
+
for (const item of userDevices) {
|
|
243
|
+
const finalJid = isLidUser
|
|
244
|
+
? jidEncode(user, item.server, item.device)
|
|
245
|
+
: jidEncode(item.user, item.server, item.device);
|
|
246
|
+
deviceResults.push({
|
|
247
|
+
...item,
|
|
248
|
+
jid: finalJid
|
|
249
|
+
});
|
|
250
|
+
logger.debug({
|
|
251
|
+
user: item.user,
|
|
252
|
+
device: item.device,
|
|
253
|
+
finalJid,
|
|
254
|
+
usedLid: isLidUser
|
|
255
|
+
}, 'Processed device with LID priority');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (userDevicesCache.mset) {
|
|
259
|
+
// if the cache supports mset, we can set all devices in one go
|
|
260
|
+
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
for (const key in deviceMap) {
|
|
264
|
+
if (deviceMap[key])
|
|
265
|
+
await userDevicesCache.set(key, deviceMap[key]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const userDeviceUpdates = {};
|
|
269
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
270
|
+
if (devices && devices.length > 0) {
|
|
271
|
+
userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
|
|
272
|
+
}
|
|
156
273
|
}
|
|
157
|
-
|
|
158
|
-
|
|
274
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
275
|
+
try {
|
|
276
|
+
await authState.keys.set({ 'device-list': userDeviceUpdates });
|
|
277
|
+
logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration');
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
logger.warn({ error }, 'failed to store user device lists');
|
|
281
|
+
}
|
|
159
282
|
}
|
|
160
283
|
}
|
|
161
284
|
return deviceResults;
|
|
162
285
|
};
|
|
163
|
-
const assertSessions = async (jids
|
|
286
|
+
const assertSessions = async (jids) => {
|
|
164
287
|
let didFetchNewSession = false;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
.jidToSignalProtocolAddress(jid);
|
|
176
|
-
if (!sessions[signalId]) {
|
|
177
|
-
jidsRequiringFetch.push(jid);
|
|
288
|
+
const uniqueJids = [...new Set(jids)]; // Deduplicate JIDs
|
|
289
|
+
const jidsRequiringFetch = [];
|
|
290
|
+
logger.debug({ jids }, 'assertSessions call with jids');
|
|
291
|
+
// Check peerSessionsCache and validate sessions using libsignal loadSession
|
|
292
|
+
for (const jid of uniqueJids) {
|
|
293
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
294
|
+
const cachedSession = peerSessionsCache.get(signalId);
|
|
295
|
+
if (cachedSession !== undefined) {
|
|
296
|
+
if (cachedSession) {
|
|
297
|
+
continue; // Session exists in cache
|
|
178
298
|
}
|
|
179
299
|
}
|
|
300
|
+
else {
|
|
301
|
+
const sessionValidation = await signalRepository.validateSession(jid);
|
|
302
|
+
const hasSession = sessionValidation.exists;
|
|
303
|
+
peerSessionsCache.set(signalId, hasSession);
|
|
304
|
+
if (hasSession) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
jidsRequiringFetch.push(jid);
|
|
180
309
|
}
|
|
181
310
|
if (jidsRequiringFetch.length) {
|
|
182
|
-
|
|
311
|
+
// LID if mapped, otherwise original
|
|
312
|
+
const wireJids = [
|
|
313
|
+
...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
314
|
+
...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
|
|
315
|
+
];
|
|
316
|
+
logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions');
|
|
183
317
|
const result = await query({
|
|
184
318
|
tag: 'iq',
|
|
185
319
|
attrs: {
|
|
186
320
|
xmlns: 'encrypt',
|
|
187
321
|
type: 'get',
|
|
188
|
-
to:
|
|
322
|
+
to: S_WHATSAPP_NET
|
|
189
323
|
},
|
|
190
324
|
content: [
|
|
191
325
|
{
|
|
192
326
|
tag: 'key',
|
|
193
327
|
attrs: {},
|
|
194
|
-
content:
|
|
328
|
+
content: wireJids.map(jid => ({
|
|
195
329
|
tag: 'user',
|
|
196
|
-
attrs: { jid }
|
|
330
|
+
attrs: { jid }
|
|
197
331
|
}))
|
|
198
332
|
}
|
|
199
333
|
]
|
|
200
334
|
});
|
|
201
|
-
await
|
|
335
|
+
await parseAndInjectE2ESessions(result, signalRepository);
|
|
202
336
|
didFetchNewSession = true;
|
|
337
|
+
// Cache fetched sessions using wire JIDs
|
|
338
|
+
for (const wireJid of wireJids) {
|
|
339
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
|
|
340
|
+
peerSessionsCache.set(signalId, true);
|
|
341
|
+
}
|
|
203
342
|
}
|
|
204
343
|
return didFetchNewSession;
|
|
205
344
|
};
|
|
206
345
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
207
|
-
var _a;
|
|
208
346
|
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
209
|
-
if (!
|
|
210
|
-
throw new
|
|
347
|
+
if (!authState.creds.me?.id) {
|
|
348
|
+
throw new Boom('Not authenticated');
|
|
211
349
|
}
|
|
212
350
|
const protocolMessage = {
|
|
213
351
|
protocolMessage: {
|
|
214
352
|
peerDataOperationRequestMessage: pdoMessage,
|
|
215
|
-
type:
|
|
353
|
+
type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
|
|
216
354
|
}
|
|
217
355
|
};
|
|
218
|
-
const meJid =
|
|
356
|
+
const meJid = jidNormalizedUser(authState.creds.me.id);
|
|
219
357
|
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
220
358
|
additionalAttributes: {
|
|
221
359
|
category: 'peer',
|
|
222
|
-
|
|
223
|
-
push_priority: 'high_force',
|
|
360
|
+
push_priority: 'high_force'
|
|
224
361
|
},
|
|
362
|
+
additionalNodes: [
|
|
363
|
+
{
|
|
364
|
+
tag: 'meta',
|
|
365
|
+
attrs: { appdata: 'default' }
|
|
366
|
+
}
|
|
367
|
+
]
|
|
225
368
|
});
|
|
226
369
|
return msgId;
|
|
227
370
|
};
|
|
228
|
-
const createParticipantNodes = async (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched];
|
|
371
|
+
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
372
|
+
if (!recipientJids.length) {
|
|
373
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
232
374
|
}
|
|
375
|
+
const patched = await patchMessageBeforeSending(message, recipientJids);
|
|
376
|
+
const patchedMessages = Array.isArray(patched)
|
|
377
|
+
? patched
|
|
378
|
+
: recipientJids.map(jid => ({ recipientJid: jid, message: patched }));
|
|
233
379
|
let shouldIncludeDeviceIdentity = false;
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
380
|
+
const meId = authState.creds.me.id;
|
|
381
|
+
const meLid = authState.creds.me?.lid;
|
|
382
|
+
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
383
|
+
const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
384
|
+
if (!jid)
|
|
385
|
+
return null;
|
|
386
|
+
let msgToEncrypt = patchedMessage;
|
|
387
|
+
if (dsmMessage) {
|
|
388
|
+
const { user: targetUser } = jidDecode(jid);
|
|
389
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
390
|
+
const ownLidUser = meLidUser;
|
|
391
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
392
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
393
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
394
|
+
msgToEncrypt = dsmMessage;
|
|
395
|
+
logger.debug({ jid, targetUser }, 'Using DSM for own device');
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
399
|
+
const mutexKey = jid;
|
|
400
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
401
|
+
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
402
|
+
jid,
|
|
403
|
+
data: bytes
|
|
404
|
+
});
|
|
405
|
+
if (type === 'pkmsg') {
|
|
406
|
+
shouldIncludeDeviceIdentity = true;
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
tag: 'to',
|
|
410
|
+
attrs: { jid },
|
|
411
|
+
content: [
|
|
412
|
+
{
|
|
413
|
+
tag: 'enc',
|
|
414
|
+
attrs: {
|
|
415
|
+
v: '2',
|
|
416
|
+
type,
|
|
417
|
+
...(extraAttrs || {})
|
|
418
|
+
},
|
|
419
|
+
content: ciphertext
|
|
420
|
+
}
|
|
421
|
+
]
|
|
422
|
+
};
|
|
423
|
+
});
|
|
258
424
|
return node;
|
|
259
|
-
})
|
|
425
|
+
});
|
|
426
|
+
const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
|
|
260
427
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
261
428
|
};
|
|
262
|
-
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
263
|
-
|
|
429
|
+
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, AI = false }) => {
|
|
430
|
+
// let shouldIncludeDeviceIdentity = false;
|
|
431
|
+
let didPushAdditional = false
|
|
264
432
|
const meId = authState.creds.me.id;
|
|
265
|
-
|
|
266
|
-
const
|
|
433
|
+
const meLid = authState.creds.me?.lid;
|
|
434
|
+
const isRetryResend = Boolean(participant?.jid);
|
|
435
|
+
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
267
436
|
const statusJid = 'status@broadcast';
|
|
437
|
+
const { user, server } = jidDecode(jid);
|
|
268
438
|
const isGroup = server === 'g.us';
|
|
269
|
-
const isNewsletter = server === 'newsletter';
|
|
270
439
|
const isStatus = jid === statusJid;
|
|
271
440
|
const isLid = server === 'lid';
|
|
272
|
-
|
|
441
|
+
const isNewsletter = server === 'newsletter';
|
|
442
|
+
const isPrivate = server === 's.whatsapp.net'
|
|
443
|
+
const finalJid = jid;
|
|
444
|
+
msgId = msgId || generateMessageIDV2(meId);
|
|
273
445
|
useUserDevicesCache = useUserDevicesCache !== false;
|
|
274
446
|
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
275
447
|
const participants = [];
|
|
276
|
-
const destinationJid =
|
|
448
|
+
const destinationJid = !isStatus ? finalJid : statusJid;
|
|
277
449
|
const binaryNodeContent = [];
|
|
278
450
|
const devices = [];
|
|
279
451
|
const meMsg = {
|
|
@@ -284,162 +456,253 @@ const makeMessagesSocket = (config) => {
|
|
|
284
456
|
messageContextInfo: message.messageContextInfo
|
|
285
457
|
};
|
|
286
458
|
const extraAttrs = {};
|
|
459
|
+
const messages = normalizeMessageContent(message)
|
|
460
|
+
const buttonType = getButtonType(messages);
|
|
287
461
|
if (participant) {
|
|
288
|
-
// when the retry request is not for a group
|
|
289
|
-
// only send to the specific device that asked for a retry
|
|
290
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
291
462
|
if (!isGroup && !isStatus) {
|
|
292
|
-
additionalAttributes = {
|
|
463
|
+
additionalAttributes = {
|
|
464
|
+
...additionalAttributes,
|
|
465
|
+
device_fanout: 'false'
|
|
466
|
+
};
|
|
293
467
|
}
|
|
294
|
-
const { user, device } =
|
|
295
|
-
devices.push({
|
|
468
|
+
const { user, device } = jidDecode(participant.jid);
|
|
469
|
+
devices.push({
|
|
470
|
+
user,
|
|
471
|
+
device,
|
|
472
|
+
jid: participant.jid
|
|
473
|
+
});
|
|
296
474
|
}
|
|
297
475
|
await authState.keys.transaction(async () => {
|
|
298
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
|
|
299
476
|
const mediaType = getMediaType(message);
|
|
300
477
|
if (mediaType) {
|
|
301
478
|
extraAttrs['mediatype'] = mediaType;
|
|
302
479
|
}
|
|
303
|
-
|
|
304
|
-
|
|
480
|
+
|
|
481
|
+
if (isNewsletter) {
|
|
482
|
+
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
483
|
+
const bytes = encodeNewsletterMessage(patched);
|
|
484
|
+
binaryNodeContent.push({
|
|
485
|
+
tag: "plaintext",
|
|
486
|
+
attrs: mediaType ? { mediatype: mediaType } : {},
|
|
487
|
+
content: bytes
|
|
488
|
+
});
|
|
489
|
+
const stanza = {
|
|
490
|
+
tag: "message",
|
|
491
|
+
attrs: {
|
|
492
|
+
to: jid,
|
|
493
|
+
id: msgId,
|
|
494
|
+
type: getTypeMessage(message),
|
|
495
|
+
...(additionalAttributes || {})
|
|
496
|
+
},
|
|
497
|
+
content: binaryNodeContent
|
|
498
|
+
};
|
|
499
|
+
logger.debug({ msgId }, `sending newsletter message to ${jid}`);
|
|
500
|
+
await sendNode(stanza);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
|
|
505
|
+
extraAttrs['decrypt-fail'] = 'hide'
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
|
|
509
|
+
extraAttrs['native_flow_name'] = messages.interactiveResponseMessage?.nativeFlowResponseMessage.name
|
|
305
510
|
}
|
|
511
|
+
|
|
306
512
|
if (isGroup || isStatus) {
|
|
307
513
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
308
514
|
(async () => {
|
|
309
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
310
|
-
if (groupData && Array.isArray(groupData
|
|
311
|
-
logger.trace({
|
|
515
|
+
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?
|
|
516
|
+
if (groupData && Array.isArray(groupData?.participants)) {
|
|
517
|
+
logger.trace({
|
|
518
|
+
jid,
|
|
519
|
+
participants: groupData.participants.length
|
|
520
|
+
}, 'using cached group metadata');
|
|
312
521
|
}
|
|
313
522
|
else if (!isStatus) {
|
|
314
|
-
groupData = await groupMetadata(jid);
|
|
523
|
+
groupData = await groupMetadata(jid); // TODO: start storing group participant list + addr mode in Signal & stop relying on this
|
|
315
524
|
}
|
|
316
525
|
return groupData;
|
|
317
526
|
})(),
|
|
318
527
|
(async () => {
|
|
319
528
|
if (!participant && !isStatus) {
|
|
320
|
-
|
|
529
|
+
// what if sender memory is less accurate than the cached metadata
|
|
530
|
+
// on participant change in group, we should do sender memory manipulation
|
|
531
|
+
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?
|
|
321
532
|
return result[jid] || {};
|
|
322
533
|
}
|
|
323
534
|
return {};
|
|
324
535
|
})()
|
|
325
536
|
]);
|
|
326
537
|
if (!participant) {
|
|
327
|
-
const participantsList =
|
|
538
|
+
const participantsList = groupData && !isStatus ? groupData.participants.map(p => p.id) : [];
|
|
328
539
|
if (isStatus && statusJidList) {
|
|
329
540
|
participantsList.push(...statusJidList);
|
|
330
541
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
542
|
+
// if (!isStatus) {
|
|
543
|
+
// additionalAttributes = {
|
|
544
|
+
// ...additionalAttributes,
|
|
545
|
+
// addressing_mode: groupData?.addressingMode || 'pn'
|
|
546
|
+
// };
|
|
547
|
+
// }
|
|
338
548
|
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
|
|
339
549
|
devices.push(...additionalDevices);
|
|
340
550
|
}
|
|
551
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
552
|
+
additionalAttributes = {
|
|
553
|
+
...additionalAttributes,
|
|
554
|
+
expiration: groupData.ephemeralDuration.toString()
|
|
555
|
+
};
|
|
556
|
+
}
|
|
341
557
|
const patched = await patchMessageBeforeSending(message);
|
|
342
558
|
if (Array.isArray(patched)) {
|
|
343
|
-
throw new
|
|
559
|
+
throw new Boom('Per-jid patching is not supported in groups');
|
|
344
560
|
}
|
|
345
|
-
const bytes =
|
|
561
|
+
const bytes = encodeWAMessage(patched);
|
|
562
|
+
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
|
|
563
|
+
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
346
564
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
347
565
|
group: destinationJid,
|
|
348
566
|
data: bytes,
|
|
349
|
-
meId
|
|
567
|
+
meId: groupSenderIdentity
|
|
350
568
|
});
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const
|
|
355
|
-
if (!
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
569
|
+
const senderKeyRecipients = [];
|
|
570
|
+
for (const device of devices) {
|
|
571
|
+
const deviceJid = device.jid;
|
|
572
|
+
const hasKey = !!senderKeyMap[deviceJid];
|
|
573
|
+
if ((!hasKey || !!participant) &&
|
|
574
|
+
!isHostedLidUser(deviceJid) &&
|
|
575
|
+
!isHostedPnUser(deviceJid) &&
|
|
576
|
+
device.device !== 99) {
|
|
577
|
+
//todo: revamp all this logic
|
|
578
|
+
// 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
|
|
579
|
+
senderKeyRecipients.push(deviceJid);
|
|
580
|
+
senderKeyMap[deviceJid] = true;
|
|
359
581
|
}
|
|
360
582
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if (senderKeyJids.length) {
|
|
364
|
-
logger.debug({ senderKeyJids }, 'sending new sender key');
|
|
583
|
+
if (senderKeyRecipients.length) {
|
|
584
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
|
|
365
585
|
const senderKeyMsg = {
|
|
366
586
|
senderKeyDistributionMessage: {
|
|
367
587
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
368
588
|
groupId: destinationJid
|
|
369
589
|
}
|
|
370
590
|
};
|
|
371
|
-
|
|
372
|
-
|
|
591
|
+
const senderKeySessionTargets = senderKeyRecipients;
|
|
592
|
+
await assertSessions(senderKeySessionTargets);
|
|
593
|
+
const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
|
|
373
594
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
374
595
|
participants.push(...result.nodes);
|
|
375
596
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
if (((_d = message.protocolMessage) === null || _d === void 0 ? void 0 : _d.type) === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
|
|
391
|
-
msgId = (_e = message.protocolMessage.key) === null || _e === void 0 ? void 0 : _e.id;
|
|
392
|
-
message = {};
|
|
597
|
+
if (isRetryResend) {
|
|
598
|
+
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
599
|
+
data: bytes,
|
|
600
|
+
jid: participant?.jid
|
|
601
|
+
});
|
|
602
|
+
binaryNodeContent.push({
|
|
603
|
+
tag: 'enc',
|
|
604
|
+
attrs: {
|
|
605
|
+
v: '2',
|
|
606
|
+
type,
|
|
607
|
+
count: participant.count.toString()
|
|
608
|
+
},
|
|
609
|
+
content: encryptedContent
|
|
610
|
+
});
|
|
393
611
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
612
|
+
else {
|
|
613
|
+
binaryNodeContent.push({
|
|
614
|
+
tag: 'enc',
|
|
615
|
+
attrs: {
|
|
616
|
+
v: '2',
|
|
617
|
+
type: 'skmsg',
|
|
618
|
+
...extraAttrs
|
|
619
|
+
},
|
|
620
|
+
content: ciphertext
|
|
621
|
+
});
|
|
622
|
+
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
397
623
|
}
|
|
398
|
-
const bytes = (0, Utils_1.encodeNewsletterMessage)(patched);
|
|
399
|
-
binaryNodeContent.push({
|
|
400
|
-
tag: 'plaintext',
|
|
401
|
-
attrs: mediaType ? { mediatype: mediaType } : {},
|
|
402
|
-
content: bytes
|
|
403
|
-
});
|
|
404
624
|
}
|
|
405
625
|
else {
|
|
406
|
-
|
|
626
|
+
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
627
|
+
// TODO: investigate if this is true
|
|
628
|
+
let ownId = meId;
|
|
629
|
+
if (isLid && meLid) {
|
|
630
|
+
ownId = meLid;
|
|
631
|
+
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
|
|
635
|
+
}
|
|
636
|
+
const { user: ownUser } = jidDecode(ownId);
|
|
407
637
|
if (!participant) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
638
|
+
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
639
|
+
devices.push({
|
|
640
|
+
user,
|
|
641
|
+
device: 0,
|
|
642
|
+
jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
|
|
643
|
+
});
|
|
644
|
+
if (user !== ownUser) {
|
|
645
|
+
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
646
|
+
const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
647
|
+
devices.push({
|
|
648
|
+
user: ownUserForAddressing,
|
|
649
|
+
device: 0,
|
|
650
|
+
jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
651
|
+
});
|
|
411
652
|
}
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
devices.
|
|
653
|
+
if (additionalAttributes?.['category'] !== 'peer') {
|
|
654
|
+
// Clear placeholders and enumerate actual devices
|
|
655
|
+
devices.length = 0;
|
|
656
|
+
// Use conversation-appropriate sender identity
|
|
657
|
+
const senderIdentity = isLid && meLid
|
|
658
|
+
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
659
|
+
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
660
|
+
// Enumerate devices for sender and target with consistent addressing
|
|
661
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
662
|
+
devices.push(...sessionDevices);
|
|
663
|
+
logger.debug({
|
|
664
|
+
deviceCount: devices.length,
|
|
665
|
+
devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
|
|
666
|
+
}, 'Device enumeration complete with unified addressing');
|
|
415
667
|
}
|
|
416
668
|
}
|
|
417
|
-
const
|
|
418
|
-
const
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
669
|
+
const allRecipients = [];
|
|
670
|
+
const meRecipients = [];
|
|
671
|
+
const otherRecipients = [];
|
|
672
|
+
const { user: mePnUser } = jidDecode(meId);
|
|
673
|
+
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
|
|
674
|
+
for (const { user, jid } of devices) {
|
|
675
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
676
|
+
if (isExactSenderDevice) {
|
|
677
|
+
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
// Check if this is our device (could match either PN or LID user)
|
|
681
|
+
const isMe = user === mePnUser || user === meLidUser;
|
|
423
682
|
if (isMe) {
|
|
424
|
-
|
|
683
|
+
meRecipients.push(jid);
|
|
425
684
|
}
|
|
426
685
|
else {
|
|
427
|
-
|
|
686
|
+
otherRecipients.push(jid);
|
|
428
687
|
}
|
|
429
|
-
|
|
688
|
+
allRecipients.push(jid);
|
|
430
689
|
}
|
|
431
|
-
await assertSessions(
|
|
690
|
+
await assertSessions(allRecipients);
|
|
432
691
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
433
|
-
|
|
434
|
-
createParticipantNodes(
|
|
692
|
+
// For own devices: use DSM if available (1:1 chats only)
|
|
693
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
694
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
435
695
|
]);
|
|
436
696
|
participants.push(...meNodes);
|
|
437
697
|
participants.push(...otherNodes);
|
|
698
|
+
/* if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
699
|
+
extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
|
|
700
|
+
}*/
|
|
438
701
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
439
702
|
}
|
|
440
703
|
if (participants.length) {
|
|
441
|
-
if (
|
|
442
|
-
const peerNode =
|
|
704
|
+
if (additionalAttributes?.['category'] === 'peer') {
|
|
705
|
+
const peerNode = participants[0]?.content?.[0];
|
|
443
706
|
if (peerNode) {
|
|
444
707
|
binaryNodeContent.push(peerNode); // push only enc
|
|
445
708
|
}
|
|
@@ -456,7 +719,8 @@ const makeMessagesSocket = (config) => {
|
|
|
456
719
|
tag: 'message',
|
|
457
720
|
attrs: {
|
|
458
721
|
id: msgId,
|
|
459
|
-
|
|
722
|
+
to: destinationJid,
|
|
723
|
+
type: getTypeMessage(messages),
|
|
460
724
|
...(additionalAttributes || {})
|
|
461
725
|
},
|
|
462
726
|
content: binaryNodeContent
|
|
@@ -465,11 +729,11 @@ const makeMessagesSocket = (config) => {
|
|
|
465
729
|
// ensure the message is only sent to that person
|
|
466
730
|
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
467
731
|
if (participant) {
|
|
468
|
-
if (
|
|
732
|
+
if (isJidGroup(destinationJid)) {
|
|
469
733
|
stanza.attrs.to = destinationJid;
|
|
470
734
|
stanza.attrs.participant = participant.jid;
|
|
471
735
|
}
|
|
472
|
-
else if (
|
|
736
|
+
else if (areJidsSameUser(participant.jid, meId)) {
|
|
473
737
|
stanza.attrs.to = participant.jid;
|
|
474
738
|
stanza.attrs.recipient = destinationJid;
|
|
475
739
|
}
|
|
@@ -481,50 +745,58 @@ const makeMessagesSocket = (config) => {
|
|
|
481
745
|
stanza.attrs.to = destinationJid;
|
|
482
746
|
}
|
|
483
747
|
if (shouldIncludeDeviceIdentity) {
|
|
748
|
+
;
|
|
484
749
|
stanza.content.push({
|
|
485
750
|
tag: 'device-identity',
|
|
486
751
|
attrs: {},
|
|
487
|
-
content:
|
|
752
|
+
content: encodeSignedDeviceIdentity(authState.creds.account, true)
|
|
488
753
|
});
|
|
489
754
|
logger.debug({ jid }, 'adding device identity');
|
|
490
755
|
}
|
|
491
|
-
if (
|
|
492
|
-
|
|
756
|
+
if (AI && isPrivate) {
|
|
757
|
+
const botNode = {
|
|
758
|
+
tag: 'bot',
|
|
759
|
+
attrs: {
|
|
760
|
+
biz_bot: '1'
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
const filteredBizBot = getBinaryNodeFilter(additionalNodes ? additionalNodes : [])
|
|
765
|
+
|
|
766
|
+
if (filteredBizBot) {
|
|
767
|
+
stanza.content.push(...additionalNodes)
|
|
768
|
+
didPushAdditional = true
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
else {
|
|
772
|
+
stanza.content.push(botNode)
|
|
773
|
+
}
|
|
493
774
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
v: '1'
|
|
506
|
-
},
|
|
507
|
-
content: [{
|
|
508
|
-
tag: 'native_flow',
|
|
509
|
-
attrs: { v: '9', name: 'mixed' }
|
|
510
|
-
}]
|
|
511
|
-
}];
|
|
512
|
-
}
|
|
513
|
-
else if (message === null || message === void 0 ? void 0 : message.listMessage) {
|
|
514
|
-
// list message only support in private chat
|
|
515
|
-
bizNode.content = [{
|
|
516
|
-
tag: 'list',
|
|
517
|
-
attrs: {
|
|
518
|
-
type: 'product_list',
|
|
519
|
-
v: '2'
|
|
520
|
-
}
|
|
521
|
-
}];
|
|
775
|
+
|
|
776
|
+
if(buttonType && !isStatus) {
|
|
777
|
+
const content = getAdditionalNode(buttonType)
|
|
778
|
+
const filteredNode = getBinaryNodeFilter(additionalNodes)
|
|
779
|
+
|
|
780
|
+
if (filteredNode) {
|
|
781
|
+
didPushAdditional = true
|
|
782
|
+
stanza.content.push(...additionalNodes)
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
stanza.content.push(...content)
|
|
522
786
|
}
|
|
523
|
-
|
|
787
|
+
logger.debug({ jid }, 'adding business node')
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
|
|
791
|
+
stanza.content.push(...additionalNodes);
|
|
524
792
|
}
|
|
525
793
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
526
794
|
await sendNode(stanza);
|
|
527
|
-
|
|
795
|
+
// Add message to retry cache if enabled
|
|
796
|
+
if (messageRetryManager && !participant) {
|
|
797
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
798
|
+
}
|
|
799
|
+
}, meId);
|
|
528
800
|
return msgId;
|
|
529
801
|
};
|
|
530
802
|
const getTypeMessage = (msg) => {
|
|
@@ -558,57 +830,89 @@ const makeMessagesSocket = (config) => {
|
|
|
558
830
|
};
|
|
559
831
|
const getMediaType = (message) => {
|
|
560
832
|
if (message.imageMessage) {
|
|
561
|
-
return 'image'
|
|
833
|
+
return 'image'
|
|
562
834
|
}
|
|
563
835
|
else if (message.videoMessage) {
|
|
564
|
-
return message.videoMessage.gifPlayback ? 'gif' : 'video'
|
|
836
|
+
return message.videoMessage.gifPlayback ? 'gif' : 'video'
|
|
565
837
|
}
|
|
566
838
|
else if (message.audioMessage) {
|
|
567
|
-
return message.audioMessage.ptt ? 'ptt' : 'audio'
|
|
839
|
+
return message.audioMessage.ptt ? 'ptt' : 'audio'
|
|
568
840
|
}
|
|
569
841
|
else if (message.contactMessage) {
|
|
570
|
-
return 'vcard'
|
|
842
|
+
return 'vcard'
|
|
571
843
|
}
|
|
572
844
|
else if (message.documentMessage) {
|
|
573
|
-
return 'document'
|
|
845
|
+
return 'document'
|
|
574
846
|
}
|
|
575
847
|
else if (message.contactsArrayMessage) {
|
|
576
|
-
return 'contact_array'
|
|
848
|
+
return 'contact_array'
|
|
577
849
|
}
|
|
578
850
|
else if (message.liveLocationMessage) {
|
|
579
|
-
return 'livelocation'
|
|
851
|
+
return 'livelocation'
|
|
580
852
|
}
|
|
581
853
|
else if (message.stickerMessage) {
|
|
582
|
-
return 'sticker'
|
|
854
|
+
return 'sticker'
|
|
583
855
|
}
|
|
584
856
|
else if (message.listMessage) {
|
|
585
|
-
return 'list'
|
|
857
|
+
return 'list'
|
|
586
858
|
}
|
|
587
859
|
else if (message.listResponseMessage) {
|
|
588
|
-
return 'list_response'
|
|
860
|
+
return 'list_response'
|
|
589
861
|
}
|
|
590
862
|
else if (message.buttonsResponseMessage) {
|
|
591
|
-
return 'buttons_response'
|
|
863
|
+
return 'buttons_response'
|
|
592
864
|
}
|
|
593
865
|
else if (message.orderMessage) {
|
|
594
|
-
return 'order'
|
|
866
|
+
return 'order'
|
|
595
867
|
}
|
|
596
868
|
else if (message.productMessage) {
|
|
597
|
-
return 'product'
|
|
869
|
+
return 'product'
|
|
598
870
|
}
|
|
599
871
|
else if (message.interactiveResponseMessage) {
|
|
600
|
-
return 'native_flow_response'
|
|
872
|
+
return 'native_flow_response'
|
|
601
873
|
}
|
|
602
874
|
else if (message.groupInviteMessage) {
|
|
603
|
-
return 'url'
|
|
875
|
+
return 'url'
|
|
604
876
|
}
|
|
605
|
-
|
|
877
|
+
else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
878
|
+
return 'productlink'
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
const getButtonType = (message) => {
|
|
882
|
+
if (message.listMessage) {
|
|
883
|
+
return 'list'
|
|
884
|
+
}
|
|
885
|
+
else if (message.buttonsMessage) {
|
|
886
|
+
return 'buttons'
|
|
887
|
+
}
|
|
888
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_and_pay') {
|
|
889
|
+
return 'review_and_pay'
|
|
890
|
+
}
|
|
891
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_order') {
|
|
892
|
+
return 'review_order'
|
|
893
|
+
}
|
|
894
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_info') {
|
|
895
|
+
return 'payment_info'
|
|
896
|
+
}
|
|
897
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_status') {
|
|
898
|
+
return 'payment_status'
|
|
899
|
+
}
|
|
900
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_method') {
|
|
901
|
+
return 'payment_method'
|
|
902
|
+
}
|
|
903
|
+
else if (message.interactiveMessage && message.interactiveMessage?.nativeFlowMessage) {
|
|
904
|
+
return 'interactive'
|
|
905
|
+
}
|
|
906
|
+
else if (message.interactiveMessage?.nativeFlowMessage) {
|
|
907
|
+
return 'native_flow'
|
|
908
|
+
}
|
|
909
|
+
}
|
|
606
910
|
const getPrivacyTokens = async (jids) => {
|
|
607
|
-
const t =
|
|
911
|
+
const t = unixTimestampSeconds().toString();
|
|
608
912
|
const result = await query({
|
|
609
913
|
tag: 'iq',
|
|
610
914
|
attrs: {
|
|
611
|
-
to:
|
|
915
|
+
to: S_WHATSAPP_NET,
|
|
612
916
|
type: 'set',
|
|
613
917
|
xmlns: 'privacy'
|
|
614
918
|
},
|
|
@@ -619,7 +923,7 @@ const makeMessagesSocket = (config) => {
|
|
|
619
923
|
content: jids.map(jid => ({
|
|
620
924
|
tag: 'token',
|
|
621
925
|
attrs: {
|
|
622
|
-
jid:
|
|
926
|
+
jid: jidNormalizedUser(jid),
|
|
623
927
|
t,
|
|
624
928
|
type: 'trusted_contact'
|
|
625
929
|
}
|
|
@@ -629,8 +933,8 @@ const makeMessagesSocket = (config) => {
|
|
|
629
933
|
});
|
|
630
934
|
return result;
|
|
631
935
|
};
|
|
632
|
-
const waUploadToServer =
|
|
633
|
-
const waitForMsgMediaUpdate =
|
|
936
|
+
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
937
|
+
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
634
938
|
return {
|
|
635
939
|
...sock,
|
|
636
940
|
getPrivacyTokens,
|
|
@@ -642,14 +946,15 @@ const makeMessagesSocket = (config) => {
|
|
|
642
946
|
refreshMediaConn,
|
|
643
947
|
waUploadToServer,
|
|
644
948
|
fetchPrivacySettings,
|
|
645
|
-
getUSyncDevices,
|
|
646
|
-
createParticipantNodes,
|
|
647
949
|
sendPeerDataOperationMessage,
|
|
950
|
+
createParticipantNodes,
|
|
951
|
+
getUSyncDevices,
|
|
952
|
+
messageRetryManager,
|
|
648
953
|
updateMediaMessage: async (message) => {
|
|
649
|
-
const content =
|
|
954
|
+
const content = assertMediaContent(message.message);
|
|
650
955
|
const mediaKey = content.mediaKey;
|
|
651
956
|
const meId = authState.creds.me.id;
|
|
652
|
-
const node = await
|
|
957
|
+
const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
|
|
653
958
|
let error = undefined;
|
|
654
959
|
await Promise.all([
|
|
655
960
|
sendNode(node),
|
|
@@ -661,13 +966,16 @@ const makeMessagesSocket = (config) => {
|
|
|
661
966
|
}
|
|
662
967
|
else {
|
|
663
968
|
try {
|
|
664
|
-
const media = await
|
|
665
|
-
if (media.result !==
|
|
666
|
-
const resultStr =
|
|
667
|
-
throw new
|
|
969
|
+
const media = await decryptMediaRetryData(result.media, mediaKey, result.key.id);
|
|
970
|
+
if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
|
|
971
|
+
const resultStr = proto.MediaRetryNotification.ResultType[media.result];
|
|
972
|
+
throw new Boom(`Media re-upload failed by device (${resultStr})`, {
|
|
973
|
+
data: media,
|
|
974
|
+
statusCode: getStatusCodeForMediaRetry(media.result) || 404
|
|
975
|
+
});
|
|
668
976
|
}
|
|
669
977
|
content.directPath = media.directPath;
|
|
670
|
-
content.url =
|
|
978
|
+
content.url = getUrlFromDirectPath(content.directPath);
|
|
671
979
|
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
|
|
672
980
|
}
|
|
673
981
|
catch (err) {
|
|
@@ -681,194 +989,112 @@ const makeMessagesSocket = (config) => {
|
|
|
681
989
|
if (error) {
|
|
682
990
|
throw error;
|
|
683
991
|
}
|
|
684
|
-
ev.emit('messages.update', [
|
|
685
|
-
{ key: message.key, update: { message: message.message } }
|
|
686
|
-
]);
|
|
992
|
+
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
687
993
|
return message;
|
|
688
994
|
},
|
|
689
995
|
sendMessage: async (jid, content, options = {}) => {
|
|
690
|
-
var _a, _b, _c;
|
|
691
996
|
const userJid = authState.creds.me.id;
|
|
692
|
-
if (!options.ephemeralExpiration) {
|
|
693
|
-
if ((0, WABinary_1.isJidGroup)(jid)) {
|
|
694
|
-
const groups = await sock.groupQuery(jid, 'get', [{
|
|
695
|
-
tag: 'query',
|
|
696
|
-
attrs: {
|
|
697
|
-
request: 'interactive'
|
|
698
|
-
}
|
|
699
|
-
}]);
|
|
700
|
-
const metadata = (0, WABinary_1.getBinaryNodeChild)(groups, 'group');
|
|
701
|
-
const expiration = ((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(metadata, 'ephemeral')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.expiration) || 0;
|
|
702
|
-
options.ephemeralExpiration = expiration;
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
997
|
if (typeof content === 'object' &&
|
|
706
998
|
'disappearingMessagesInChat' in content &&
|
|
707
999
|
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
708
|
-
|
|
1000
|
+
isJidGroup(jid)) {
|
|
709
1001
|
const { disappearingMessagesInChat } = content;
|
|
710
|
-
const value = typeof disappearingMessagesInChat === 'boolean'
|
|
711
|
-
|
|
712
|
-
|
|
1002
|
+
const value = typeof disappearingMessagesInChat === 'boolean'
|
|
1003
|
+
? disappearingMessagesInChat
|
|
1004
|
+
? WA_DEFAULT_EPHEMERAL
|
|
1005
|
+
: 0
|
|
1006
|
+
: disappearingMessagesInChat;
|
|
713
1007
|
await groupToggleEphemeral(jid, value);
|
|
714
1008
|
}
|
|
715
|
-
if (typeof content === 'object' && 'album' in content && content.album) {
|
|
716
|
-
const { album, caption } = content;
|
|
717
|
-
if (caption && !album[0].caption) {
|
|
718
|
-
album[0].caption = caption;
|
|
719
|
-
}
|
|
720
|
-
let mediaHandle;
|
|
721
|
-
let mediaMsg;
|
|
722
|
-
const albumMsg = (0, Utils_1.generateWAMessageFromContent)(jid, {
|
|
723
|
-
albumMessage: {
|
|
724
|
-
expectedImageCount: album.filter(item => 'image' in item).length,
|
|
725
|
-
expectedVideoCount: album.filter(item => 'video' in item).length
|
|
726
|
-
}
|
|
727
|
-
}, { userJid, ...options });
|
|
728
|
-
await relayMessage(jid, albumMsg.message, {
|
|
729
|
-
messageId: albumMsg.key.id
|
|
730
|
-
});
|
|
731
|
-
for (const i in album) {
|
|
732
|
-
const media = album[i];
|
|
733
|
-
if ('image' in media) {
|
|
734
|
-
mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
|
|
735
|
-
image: media.image,
|
|
736
|
-
...(media.caption ? { caption: media.caption } : {}),
|
|
737
|
-
...options
|
|
738
|
-
}, {
|
|
739
|
-
userJid,
|
|
740
|
-
upload: async (readStream, opts) => {
|
|
741
|
-
const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
|
|
742
|
-
mediaHandle = up.handle;
|
|
743
|
-
return up;
|
|
744
|
-
},
|
|
745
|
-
...options,
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
else if ('video' in media) {
|
|
749
|
-
mediaMsg = await (0, Utils_1.generateWAMessage)(jid, {
|
|
750
|
-
video: media.video,
|
|
751
|
-
...(media.caption ? { caption: media.caption } : {}),
|
|
752
|
-
...(media.gifPlayback !== undefined ? { gifPlayback: media.gifPlayback } : {}),
|
|
753
|
-
...options
|
|
754
|
-
}, {
|
|
755
|
-
userJid,
|
|
756
|
-
upload: async (readStream, opts) => {
|
|
757
|
-
const up = await waUploadToServer(readStream, { ...opts, newsletter: (0, WABinary_1.isJidNewsletter)(jid) });
|
|
758
|
-
mediaHandle = up.handle;
|
|
759
|
-
return up;
|
|
760
|
-
},
|
|
761
|
-
...options,
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
if (mediaMsg) {
|
|
765
|
-
mediaMsg.message.messageContextInfo = {
|
|
766
|
-
messageSecret: (0, crypto_1.randomBytes)(32),
|
|
767
|
-
messageAssociation: {
|
|
768
|
-
associationType: 1,
|
|
769
|
-
parentMessageKey: albumMsg.key
|
|
770
|
-
}
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
await relayMessage(jid, mediaMsg.message, {
|
|
774
|
-
messageId: mediaMsg.key.id
|
|
775
|
-
});
|
|
776
|
-
if (albumMessageItemDelayMs > 0) {
|
|
777
|
-
await new Promise(resolve => setTimeout(resolve, albumMessageItemDelayMs));
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
return albumMsg;
|
|
781
|
-
}
|
|
782
1009
|
else {
|
|
783
|
-
|
|
784
|
-
const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
|
|
1010
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
785
1011
|
logger,
|
|
786
1012
|
userJid,
|
|
787
|
-
getUrlInfo: text =>
|
|
1013
|
+
getUrlInfo: text => getUrlInfo(text, {
|
|
788
1014
|
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
789
1015
|
fetchOpts: {
|
|
790
1016
|
timeout: 3000,
|
|
791
|
-
...
|
|
1017
|
+
...(httpRequestOptions || {})
|
|
792
1018
|
},
|
|
793
1019
|
logger,
|
|
794
|
-
uploadImage: generateHighQualityLinkPreview
|
|
795
|
-
? waUploadToServer
|
|
796
|
-
: undefined
|
|
1020
|
+
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
797
1021
|
}),
|
|
1022
|
+
//TODO: CACHE
|
|
798
1023
|
getProfilePicUrl: sock.profilePictureUrl,
|
|
1024
|
+
getCallLink: sock.createCallLink,
|
|
799
1025
|
upload: async (readStream, opts) => {
|
|
800
|
-
const up = await waUploadToServer(readStream, {
|
|
801
|
-
|
|
1026
|
+
const up = await waUploadToServer(readStream, {
|
|
1027
|
+
...opts,
|
|
1028
|
+
newsletter: isJidNewsletter(jid)
|
|
1029
|
+
});
|
|
802
1030
|
return up;
|
|
803
1031
|
},
|
|
804
1032
|
mediaCache: config.mediaCache,
|
|
805
1033
|
options: config.options,
|
|
806
|
-
messageId:
|
|
807
|
-
...options
|
|
1034
|
+
messageId: generateMessageIDV2(sock.user?.id),
|
|
1035
|
+
...options
|
|
808
1036
|
});
|
|
1037
|
+
const isAiMsg = 'ai' in content && !!content.ai;
|
|
1038
|
+
const isEventMsg = 'event' in content && !!content.event;
|
|
809
1039
|
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
810
1040
|
const isEditMsg = 'edit' in content && !!content.edit;
|
|
811
1041
|
const isPinMsg = 'pin' in content && !!content.pin;
|
|
812
|
-
const isKeepMsg = 'keep' in content && content.keep;
|
|
813
1042
|
const isPollMessage = 'poll' in content && !!content.poll;
|
|
814
|
-
const isAiMsg = 'ai' in content && !!content.ai;
|
|
815
1043
|
const additionalAttributes = {};
|
|
816
1044
|
const additionalNodes = [];
|
|
817
1045
|
// required for delete
|
|
818
1046
|
if (isDeleteMsg) {
|
|
819
1047
|
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
820
|
-
if (
|
|
1048
|
+
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
821
1049
|
additionalAttributes.edit = '8';
|
|
822
1050
|
}
|
|
823
1051
|
else {
|
|
824
1052
|
additionalAttributes.edit = '7';
|
|
825
1053
|
}
|
|
826
|
-
// required for edit message
|
|
827
1054
|
}
|
|
828
1055
|
else if (isEditMsg) {
|
|
829
|
-
additionalAttributes.edit =
|
|
830
|
-
|
|
1056
|
+
additionalAttributes.edit = '1';
|
|
1057
|
+
}
|
|
1058
|
+
else if (isAiMsg) {
|
|
1059
|
+
additionalNodes.push({
|
|
1060
|
+
attrs: {
|
|
1061
|
+
biz_bot: '1'
|
|
1062
|
+
}, tag: "bot"
|
|
1063
|
+
});
|
|
831
1064
|
}
|
|
832
1065
|
else if (isPinMsg) {
|
|
833
1066
|
additionalAttributes.edit = '2';
|
|
834
|
-
// required for keep message
|
|
835
|
-
}
|
|
836
|
-
else if (isKeepMsg) {
|
|
837
|
-
additionalAttributes.edit = '6';
|
|
838
|
-
// required for polling message
|
|
839
1067
|
}
|
|
840
1068
|
else if (isPollMessage) {
|
|
841
1069
|
additionalNodes.push({
|
|
842
1070
|
tag: 'meta',
|
|
843
1071
|
attrs: {
|
|
844
1072
|
polltype: 'creation'
|
|
845
|
-
}
|
|
1073
|
+
}
|
|
846
1074
|
});
|
|
847
|
-
// required to display AI icon on message
|
|
848
1075
|
}
|
|
849
|
-
else if (
|
|
1076
|
+
else if (isEventMsg) {
|
|
850
1077
|
additionalNodes.push({
|
|
1078
|
+
tag: 'meta',
|
|
851
1079
|
attrs: {
|
|
852
|
-
|
|
853
|
-
}
|
|
854
|
-
tag: "bot"
|
|
1080
|
+
event_type: 'creation'
|
|
1081
|
+
}
|
|
855
1082
|
});
|
|
856
1083
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1084
|
+
await relayMessage(jid, fullMsg.message, {
|
|
1085
|
+
messageId: fullMsg.key.id,
|
|
1086
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1087
|
+
additionalAttributes,
|
|
1088
|
+
statusJidList: options.statusJidList,
|
|
1089
|
+
additionalNodes: isAiMsg ? additionalNodes : options.additionalNodes
|
|
1090
|
+
});
|
|
864
1091
|
if (config.emitOwnEvents) {
|
|
865
1092
|
process.nextTick(() => {
|
|
866
|
-
processingMutex.mutex(() =>
|
|
1093
|
+
processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
867
1094
|
});
|
|
868
1095
|
}
|
|
869
1096
|
return fullMsg;
|
|
870
1097
|
}
|
|
871
1098
|
}
|
|
872
1099
|
};
|
|
873
|
-
};
|
|
874
|
-
exports.makeMessagesSocket = makeMessagesSocket;
|
|
1100
|
+
};
|