@baileys-md/baileys 11.2.4 → 12.0.1
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 +5311 -0
- package/WAProto/index.js +70084 -131686
- package/lib/Defaults/index.js +118 -117
- 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 +13 -0
- package/lib/Signal/Group/group-session-builder.js +32 -0
- package/lib/Signal/Group/group_cipher.js +84 -0
- package/lib/Signal/Group/index.js +13 -0
- package/lib/Signal/Group/keyhelper.js +20 -0
- package/lib/Signal/Group/sender-chain-key.js +28 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +65 -0
- package/lib/Signal/Group/sender-key-message.js +68 -0
- package/{WASignalGroup/sender_key_name.js → lib/Signal/Group/sender-key-name.js} +10 -28
- package/lib/Signal/Group/sender-key-record.js +43 -0
- package/lib/Signal/Group/sender-key-state.js +86 -0
- package/lib/Signal/Group/sender-message-key.js +28 -0
- package/lib/Signal/libsignal.js +314 -151
- package/lib/Signal/lid-mapping.js +155 -0
- package/lib/Socket/Client/index.js +4 -19
- package/lib/Socket/Client/types.js +13 -0
- package/lib/Socket/Client/websocket.js +52 -0
- package/lib/Socket/business.js +359 -242
- package/lib/Socket/chats.js +847 -844
- package/lib/Socket/communities.js +413 -0
- package/lib/Socket/groups.js +304 -319
- package/lib/Socket/index.js +15 -9
- package/lib/Socket/messages-recv.js +1109 -989
- package/lib/Socket/messages-send.js +611 -347
- package/lib/Socket/mex.js +45 -0
- package/lib/Socket/newsletter.js +230 -231
- package/lib/Socket/socket.js +795 -616
- package/lib/Store/index.js +6 -8
- package/lib/Store/make-cache-manager-store.js +73 -81
- package/lib/Store/make-in-memory-store.js +286 -427
- 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/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 -198
- package/lib/Utils/baileys-event-stream.js +42 -61
- package/lib/Utils/browser-utils.js +25 -0
- package/lib/Utils/business.js +213 -214
- package/lib/Utils/chat-utils.js +711 -689
- package/lib/Utils/crypto.js +112 -133
- package/lib/Utils/decode-wa-message.js +254 -186
- package/lib/Utils/event-buffer.js +510 -502
- package/lib/Utils/generics.js +318 -408
- package/lib/Utils/history.js +83 -90
- package/lib/Utils/index.js +21 -33
- 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 +113 -0
- package/lib/Utils/messages-media.js +575 -671
- package/lib/Utils/messages.js +354 -462
- package/lib/Utils/noise-handler.js +138 -149
- package/lib/Utils/pre-key-manager.js +85 -0
- package/lib/Utils/process-message.js +323 -354
- package/lib/Utils/signal.js +148 -130
- package/lib/Utils/use-multi-file-auth-state.js +109 -91
- package/lib/Utils/validate-connection.js +183 -190
- package/lib/WABinary/constants.js +1298 -35
- 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 +88 -64
- 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 -33
- package/package.json +52 -57
- package/README.md +0 -2
- package/WASignalGroup/GroupProtocol.js +0 -1697
- package/WASignalGroup/ciphertext_message.js +0 -16
- package/WASignalGroup/group_cipher.js +0 -120
- package/WASignalGroup/group_session_builder.js +0 -46
- package/WASignalGroup/index.js +0 -5
- package/WASignalGroup/keyhelper.js +0 -21
- package/WASignalGroup/protobufs.js +0 -3
- package/WASignalGroup/queue_job.js +0 -69
- package/WASignalGroup/sender_chain_key.js +0 -50
- package/WASignalGroup/sender_key_distribution_message.js +0 -78
- package/WASignalGroup/sender_key_message.js +0 -92
- package/WASignalGroup/sender_key_record.js +0 -56
- package/WASignalGroup/sender_key_state.js +0 -129
- package/WASignalGroup/sender_message_key.js +0 -39
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.js +0 -62
- package/lib/Socket/registration.js +0 -166
- package/lib/Socket/usync.js +0 -70
- package/lib/Store/make-mongo-store.js +0 -567
|
@@ -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,307 +209,500 @@ 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 })));
|
|
156
261
|
}
|
|
157
|
-
|
|
158
|
-
|
|
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
|
+
}
|
|
273
|
+
}
|
|
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 = {
|
|
280
452
|
deviceSentMessage: {
|
|
281
453
|
destinationJid,
|
|
282
454
|
message
|
|
283
|
-
}
|
|
455
|
+
},
|
|
456
|
+
messageContextInfo: message.messageContextInfo
|
|
284
457
|
};
|
|
285
458
|
const extraAttrs = {};
|
|
459
|
+
const messages = normalizeMessageContent(message)
|
|
460
|
+
const buttonType = getButtonType(messages);
|
|
286
461
|
if (participant) {
|
|
287
|
-
// when the retry request is not for a group
|
|
288
|
-
// only send to the specific device that asked for a retry
|
|
289
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
290
462
|
if (!isGroup && !isStatus) {
|
|
291
|
-
additionalAttributes = {
|
|
463
|
+
additionalAttributes = {
|
|
464
|
+
...additionalAttributes,
|
|
465
|
+
device_fanout: 'false'
|
|
466
|
+
};
|
|
292
467
|
}
|
|
293
|
-
const { user, device } =
|
|
294
|
-
devices.push({
|
|
468
|
+
const { user, device } = jidDecode(participant.jid);
|
|
469
|
+
devices.push({
|
|
470
|
+
user,
|
|
471
|
+
device,
|
|
472
|
+
jid: participant.jid
|
|
473
|
+
});
|
|
295
474
|
}
|
|
296
475
|
await authState.keys.transaction(async () => {
|
|
297
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
|
|
298
476
|
const mediaType = getMediaType(message);
|
|
299
477
|
if (mediaType) {
|
|
300
478
|
extraAttrs['mediatype'] = mediaType;
|
|
301
479
|
}
|
|
302
|
-
|
|
303
|
-
|
|
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
|
|
304
510
|
}
|
|
511
|
+
|
|
305
512
|
if (isGroup || isStatus) {
|
|
306
513
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
307
514
|
(async () => {
|
|
308
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
309
|
-
if (groupData && Array.isArray(groupData
|
|
310
|
-
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');
|
|
311
521
|
}
|
|
312
522
|
else if (!isStatus) {
|
|
313
|
-
groupData = await groupMetadata(jid);
|
|
523
|
+
groupData = await groupMetadata(jid); // TODO: start storing group participant list + addr mode in Signal & stop relying on this
|
|
314
524
|
}
|
|
315
525
|
return groupData;
|
|
316
526
|
})(),
|
|
317
527
|
(async () => {
|
|
318
528
|
if (!participant && !isStatus) {
|
|
319
|
-
|
|
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?
|
|
320
532
|
return result[jid] || {};
|
|
321
533
|
}
|
|
322
534
|
return {};
|
|
323
535
|
})()
|
|
324
536
|
]);
|
|
325
537
|
if (!participant) {
|
|
326
|
-
const participantsList =
|
|
538
|
+
const participantsList = groupData && !isStatus ? groupData.participants.map(p => p.id) : [];
|
|
327
539
|
if (isStatus && statusJidList) {
|
|
328
540
|
participantsList.push(...statusJidList);
|
|
329
541
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
542
|
+
// if (!isStatus) {
|
|
543
|
+
// additionalAttributes = {
|
|
544
|
+
// ...additionalAttributes,
|
|
545
|
+
// addressing_mode: groupData?.addressingMode || 'pn'
|
|
546
|
+
// };
|
|
547
|
+
// }
|
|
337
548
|
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
|
|
338
549
|
devices.push(...additionalDevices);
|
|
339
550
|
}
|
|
551
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
552
|
+
additionalAttributes = {
|
|
553
|
+
...additionalAttributes,
|
|
554
|
+
expiration: groupData.ephemeralDuration.toString()
|
|
555
|
+
};
|
|
556
|
+
}
|
|
340
557
|
const patched = await patchMessageBeforeSending(message);
|
|
341
558
|
if (Array.isArray(patched)) {
|
|
342
|
-
throw new
|
|
559
|
+
throw new Boom('Per-jid patching is not supported in groups');
|
|
343
560
|
}
|
|
344
|
-
const bytes =
|
|
561
|
+
const bytes = encodeWAMessage(patched);
|
|
562
|
+
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
|
|
563
|
+
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
345
564
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
346
565
|
group: destinationJid,
|
|
347
566
|
data: bytes,
|
|
348
|
-
meId
|
|
567
|
+
meId: groupSenderIdentity
|
|
349
568
|
});
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const
|
|
354
|
-
if (!
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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;
|
|
358
581
|
}
|
|
359
582
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
if (senderKeyJids.length) {
|
|
363
|
-
logger.debug({ senderKeyJids }, 'sending new sender key');
|
|
583
|
+
if (senderKeyRecipients.length) {
|
|
584
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
|
|
364
585
|
const senderKeyMsg = {
|
|
365
586
|
senderKeyDistributionMessage: {
|
|
366
587
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
367
588
|
groupId: destinationJid
|
|
368
589
|
}
|
|
369
590
|
};
|
|
370
|
-
|
|
371
|
-
|
|
591
|
+
const senderKeySessionTargets = senderKeyRecipients;
|
|
592
|
+
await assertSessions(senderKeySessionTargets);
|
|
593
|
+
const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
|
|
372
594
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
373
595
|
participants.push(...result.nodes);
|
|
374
596
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (((_d = message.protocolMessage) === null || _d === void 0 ? void 0 : _d.type) === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
|
|
390
|
-
msgId = (_e = message.protocolMessage.key) === null || _e === void 0 ? void 0 : _e.id;
|
|
391
|
-
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
|
+
});
|
|
392
611
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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 } });
|
|
396
623
|
}
|
|
397
|
-
const bytes = (0, Utils_1.encodeNewsletterMessage)(patched);
|
|
398
|
-
binaryNodeContent.push({
|
|
399
|
-
tag: 'plaintext',
|
|
400
|
-
attrs: mediaType ? { mediatype: mediaType } : {},
|
|
401
|
-
content: bytes
|
|
402
|
-
});
|
|
403
624
|
}
|
|
404
625
|
else {
|
|
405
|
-
|
|
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);
|
|
406
637
|
if (!participant) {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
+
});
|
|
652
|
+
}
|
|
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,60 +745,60 @@ 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
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
+
}
|
|
507
774
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
content: [{
|
|
520
|
-
tag: 'native_flow',
|
|
521
|
-
attrs: { name: 'quick_reply' }
|
|
522
|
-
}]
|
|
523
|
-
}]
|
|
524
|
-
});
|
|
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)
|
|
525
786
|
}
|
|
787
|
+
logger.debug({ jid }, 'adding business node')
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
|
|
791
|
+
stanza.content.push(...additionalNodes);
|
|
526
792
|
}
|
|
527
793
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
528
794
|
await sendNode(stanza);
|
|
529
|
-
|
|
795
|
+
// Add message to retry cache if enabled
|
|
796
|
+
if (messageRetryManager && !participant) {
|
|
797
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
798
|
+
}
|
|
799
|
+
}, meId);
|
|
530
800
|
return msgId;
|
|
531
801
|
};
|
|
532
|
-
/*const getMessageType = (message) => {
|
|
533
|
-
if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3 || message.pollUpdateMessage) {
|
|
534
|
-
return 'poll';
|
|
535
|
-
}
|
|
536
|
-
return 'text';
|
|
537
|
-
};*/
|
|
538
802
|
const getTypeMessage = (msg) => {
|
|
539
803
|
if (msg.viewOnceMessage) {
|
|
540
804
|
return getTypeMessage(msg.viewOnceMessage.message);
|
|
@@ -553,9 +817,9 @@ const makeMessagesSocket = (config) => {
|
|
|
553
817
|
}
|
|
554
818
|
else if (msg.reactionMessage) {
|
|
555
819
|
return 'reaction';
|
|
556
|
-
}
|
|
820
|
+
}
|
|
557
821
|
else if (msg.pollCreationMessage || msg.pollCreationMessageV2 || msg.pollCreationMessageV3 || msg.pollUpdateMessage) {
|
|
558
|
-
return '
|
|
822
|
+
return 'poll';
|
|
559
823
|
}
|
|
560
824
|
else if (getMediaType(msg)) {
|
|
561
825
|
return 'media';
|
|
@@ -566,90 +830,89 @@ const makeMessagesSocket = (config) => {
|
|
|
566
830
|
};
|
|
567
831
|
const getMediaType = (message) => {
|
|
568
832
|
if (message.imageMessage) {
|
|
569
|
-
return 'image'
|
|
833
|
+
return 'image'
|
|
570
834
|
}
|
|
571
835
|
else if (message.videoMessage) {
|
|
572
|
-
return message.videoMessage.gifPlayback ? 'gif' : 'video'
|
|
836
|
+
return message.videoMessage.gifPlayback ? 'gif' : 'video'
|
|
573
837
|
}
|
|
574
838
|
else if (message.audioMessage) {
|
|
575
|
-
return message.audioMessage.ptt ? 'ptt' : 'audio'
|
|
839
|
+
return message.audioMessage.ptt ? 'ptt' : 'audio'
|
|
576
840
|
}
|
|
577
841
|
else if (message.contactMessage) {
|
|
578
|
-
return 'vcard'
|
|
842
|
+
return 'vcard'
|
|
579
843
|
}
|
|
580
844
|
else if (message.documentMessage) {
|
|
581
|
-
return 'document'
|
|
845
|
+
return 'document'
|
|
582
846
|
}
|
|
583
847
|
else if (message.contactsArrayMessage) {
|
|
584
|
-
return 'contact_array'
|
|
848
|
+
return 'contact_array'
|
|
585
849
|
}
|
|
586
850
|
else if (message.liveLocationMessage) {
|
|
587
|
-
return 'livelocation'
|
|
851
|
+
return 'livelocation'
|
|
588
852
|
}
|
|
589
853
|
else if (message.stickerMessage) {
|
|
590
|
-
return 'sticker'
|
|
854
|
+
return 'sticker'
|
|
591
855
|
}
|
|
592
856
|
else if (message.listMessage) {
|
|
593
|
-
return 'list'
|
|
857
|
+
return 'list'
|
|
594
858
|
}
|
|
595
859
|
else if (message.listResponseMessage) {
|
|
596
|
-
return 'list_response'
|
|
860
|
+
return 'list_response'
|
|
597
861
|
}
|
|
598
862
|
else if (message.buttonsResponseMessage) {
|
|
599
|
-
return 'buttons_response'
|
|
863
|
+
return 'buttons_response'
|
|
600
864
|
}
|
|
601
865
|
else if (message.orderMessage) {
|
|
602
|
-
return 'order'
|
|
866
|
+
return 'order'
|
|
603
867
|
}
|
|
604
868
|
else if (message.productMessage) {
|
|
605
|
-
return 'product'
|
|
869
|
+
return 'product'
|
|
606
870
|
}
|
|
607
871
|
else if (message.interactiveResponseMessage) {
|
|
608
|
-
return 'native_flow_response'
|
|
872
|
+
return 'native_flow_response'
|
|
609
873
|
}
|
|
610
874
|
else if (message.groupInviteMessage) {
|
|
611
|
-
return 'url'
|
|
875
|
+
return 'url'
|
|
612
876
|
}
|
|
613
|
-
|
|
877
|
+
else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
878
|
+
return 'productlink'
|
|
879
|
+
}
|
|
880
|
+
}
|
|
614
881
|
const getButtonType = (message) => {
|
|
615
|
-
if (message.
|
|
616
|
-
return '
|
|
882
|
+
if (message.listMessage) {
|
|
883
|
+
return 'list'
|
|
617
884
|
}
|
|
618
|
-
else if (message.
|
|
619
|
-
return '
|
|
885
|
+
else if (message.buttonsMessage) {
|
|
886
|
+
return 'buttons'
|
|
620
887
|
}
|
|
621
|
-
else if (message.
|
|
622
|
-
return '
|
|
888
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_and_pay') {
|
|
889
|
+
return 'review_and_pay'
|
|
623
890
|
}
|
|
624
|
-
else if (message.
|
|
625
|
-
return '
|
|
891
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_order') {
|
|
892
|
+
return 'review_order'
|
|
626
893
|
}
|
|
627
|
-
else if (message.
|
|
628
|
-
return '
|
|
894
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_info') {
|
|
895
|
+
return 'payment_info'
|
|
629
896
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
if (message.templateMessage) {
|
|
633
|
-
// TODO: Add attributes
|
|
634
|
-
return {};
|
|
897
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_status') {
|
|
898
|
+
return 'payment_status'
|
|
635
899
|
}
|
|
636
|
-
else if (message.
|
|
637
|
-
|
|
638
|
-
if (!type) {
|
|
639
|
-
throw new boom_1.Boom('Expected list type inside message');
|
|
640
|
-
}
|
|
641
|
-
return { v: '2', type: ListType[type].toLowerCase() };
|
|
900
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_method') {
|
|
901
|
+
return 'payment_method'
|
|
642
902
|
}
|
|
643
|
-
else {
|
|
644
|
-
return
|
|
903
|
+
else if (message.interactiveMessage && message.interactiveMessage?.nativeFlowMessage) {
|
|
904
|
+
return 'interactive'
|
|
645
905
|
}
|
|
646
|
-
|
|
906
|
+
else if (message.interactiveMessage?.nativeFlowMessage) {
|
|
907
|
+
return 'native_flow'
|
|
908
|
+
}
|
|
909
|
+
}
|
|
647
910
|
const getPrivacyTokens = async (jids) => {
|
|
648
|
-
const t =
|
|
911
|
+
const t = unixTimestampSeconds().toString();
|
|
649
912
|
const result = await query({
|
|
650
913
|
tag: 'iq',
|
|
651
914
|
attrs: {
|
|
652
|
-
to:
|
|
915
|
+
to: S_WHATSAPP_NET,
|
|
653
916
|
type: 'set',
|
|
654
917
|
xmlns: 'privacy'
|
|
655
918
|
},
|
|
@@ -660,7 +923,7 @@ const makeMessagesSocket = (config) => {
|
|
|
660
923
|
content: jids.map(jid => ({
|
|
661
924
|
tag: 'token',
|
|
662
925
|
attrs: {
|
|
663
|
-
jid:
|
|
926
|
+
jid: jidNormalizedUser(jid),
|
|
664
927
|
t,
|
|
665
928
|
type: 'trusted_contact'
|
|
666
929
|
}
|
|
@@ -670,8 +933,8 @@ const makeMessagesSocket = (config) => {
|
|
|
670
933
|
});
|
|
671
934
|
return result;
|
|
672
935
|
};
|
|
673
|
-
const waUploadToServer =
|
|
674
|
-
const waitForMsgMediaUpdate =
|
|
936
|
+
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
937
|
+
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
675
938
|
return {
|
|
676
939
|
...sock,
|
|
677
940
|
getPrivacyTokens,
|
|
@@ -679,19 +942,19 @@ const makeMessagesSocket = (config) => {
|
|
|
679
942
|
relayMessage,
|
|
680
943
|
sendReceipt,
|
|
681
944
|
sendReceipts,
|
|
682
|
-
getButtonArgs,
|
|
683
945
|
readMessages,
|
|
684
946
|
refreshMediaConn,
|
|
685
947
|
waUploadToServer,
|
|
686
948
|
fetchPrivacySettings,
|
|
687
|
-
getUSyncDevices,
|
|
688
|
-
createParticipantNodes,
|
|
689
949
|
sendPeerDataOperationMessage,
|
|
950
|
+
createParticipantNodes,
|
|
951
|
+
getUSyncDevices,
|
|
952
|
+
messageRetryManager,
|
|
690
953
|
updateMediaMessage: async (message) => {
|
|
691
|
-
const content =
|
|
954
|
+
const content = assertMediaContent(message.message);
|
|
692
955
|
const mediaKey = content.mediaKey;
|
|
693
956
|
const meId = authState.creds.me.id;
|
|
694
|
-
const node = await
|
|
957
|
+
const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
|
|
695
958
|
let error = undefined;
|
|
696
959
|
await Promise.all([
|
|
697
960
|
sendNode(node),
|
|
@@ -703,13 +966,16 @@ const makeMessagesSocket = (config) => {
|
|
|
703
966
|
}
|
|
704
967
|
else {
|
|
705
968
|
try {
|
|
706
|
-
const media = await
|
|
707
|
-
if (media.result !==
|
|
708
|
-
const resultStr =
|
|
709
|
-
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
|
+
});
|
|
710
976
|
}
|
|
711
977
|
content.directPath = media.directPath;
|
|
712
|
-
content.url =
|
|
978
|
+
content.url = getUrlFromDirectPath(content.directPath);
|
|
713
979
|
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
|
|
714
980
|
}
|
|
715
981
|
catch (err) {
|
|
@@ -723,114 +989,112 @@ const makeMessagesSocket = (config) => {
|
|
|
723
989
|
if (error) {
|
|
724
990
|
throw error;
|
|
725
991
|
}
|
|
726
|
-
ev.emit('messages.update', [
|
|
727
|
-
{ key: message.key, update: { message: message.message } }
|
|
728
|
-
]);
|
|
992
|
+
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
729
993
|
return message;
|
|
730
994
|
},
|
|
731
995
|
sendMessage: async (jid, content, options = {}) => {
|
|
732
|
-
var _a, _b, _c;
|
|
733
996
|
const userJid = authState.creds.me.id;
|
|
734
997
|
if (typeof content === 'object' &&
|
|
735
998
|
'disappearingMessagesInChat' in content &&
|
|
736
999
|
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
737
|
-
|
|
1000
|
+
isJidGroup(jid)) {
|
|
738
1001
|
const { disappearingMessagesInChat } = content;
|
|
739
|
-
const value = typeof disappearingMessagesInChat === 'boolean'
|
|
740
|
-
|
|
741
|
-
|
|
1002
|
+
const value = typeof disappearingMessagesInChat === 'boolean'
|
|
1003
|
+
? disappearingMessagesInChat
|
|
1004
|
+
? WA_DEFAULT_EPHEMERAL
|
|
1005
|
+
: 0
|
|
1006
|
+
: disappearingMessagesInChat;
|
|
742
1007
|
await groupToggleEphemeral(jid, value);
|
|
743
1008
|
}
|
|
744
1009
|
else {
|
|
745
|
-
|
|
746
|
-
const fullMsg = await (0, Utils_1.generateWAMessage)(jid, content, {
|
|
1010
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
747
1011
|
logger,
|
|
748
1012
|
userJid,
|
|
749
|
-
getUrlInfo: text =>
|
|
1013
|
+
getUrlInfo: text => getUrlInfo(text, {
|
|
750
1014
|
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
751
1015
|
fetchOpts: {
|
|
752
1016
|
timeout: 3000,
|
|
753
|
-
...
|
|
1017
|
+
...(httpRequestOptions || {})
|
|
754
1018
|
},
|
|
755
1019
|
logger,
|
|
756
|
-
uploadImage: generateHighQualityLinkPreview
|
|
757
|
-
? waUploadToServer
|
|
758
|
-
: undefined
|
|
1020
|
+
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
759
1021
|
}),
|
|
1022
|
+
//TODO: CACHE
|
|
760
1023
|
getProfilePicUrl: sock.profilePictureUrl,
|
|
1024
|
+
getCallLink: sock.createCallLink,
|
|
761
1025
|
upload: async (readStream, opts) => {
|
|
762
|
-
const up = await waUploadToServer(readStream, {
|
|
763
|
-
|
|
1026
|
+
const up = await waUploadToServer(readStream, {
|
|
1027
|
+
...opts,
|
|
1028
|
+
newsletter: isJidNewsletter(jid)
|
|
1029
|
+
});
|
|
764
1030
|
return up;
|
|
765
1031
|
},
|
|
766
1032
|
mediaCache: config.mediaCache,
|
|
767
1033
|
options: config.options,
|
|
768
|
-
messageId:
|
|
769
|
-
...options
|
|
1034
|
+
messageId: generateMessageIDV2(sock.user?.id),
|
|
1035
|
+
...options
|
|
770
1036
|
});
|
|
1037
|
+
const isAiMsg = 'ai' in content && !!content.ai;
|
|
1038
|
+
const isEventMsg = 'event' in content && !!content.event;
|
|
771
1039
|
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
772
1040
|
const isEditMsg = 'edit' in content && !!content.edit;
|
|
773
1041
|
const isPinMsg = 'pin' in content && !!content.pin;
|
|
774
|
-
const isKeepMsg = 'keep' in content && content.keep;
|
|
775
1042
|
const isPollMessage = 'poll' in content && !!content.poll;
|
|
776
|
-
const isAiMsg = 'ai' in content && !!content.ai;
|
|
777
1043
|
const additionalAttributes = {};
|
|
778
1044
|
const additionalNodes = [];
|
|
779
1045
|
// required for delete
|
|
780
1046
|
if (isDeleteMsg) {
|
|
781
1047
|
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
782
|
-
if (
|
|
1048
|
+
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
783
1049
|
additionalAttributes.edit = '8';
|
|
784
1050
|
}
|
|
785
1051
|
else {
|
|
786
1052
|
additionalAttributes.edit = '7';
|
|
787
1053
|
}
|
|
788
|
-
// required for edit message
|
|
789
1054
|
}
|
|
790
1055
|
else if (isEditMsg) {
|
|
791
|
-
additionalAttributes.edit =
|
|
792
|
-
|
|
1056
|
+
additionalAttributes.edit = '1';
|
|
1057
|
+
}
|
|
1058
|
+
else if (isAiMsg) {
|
|
1059
|
+
additionalNodes.push({
|
|
1060
|
+
attrs: {
|
|
1061
|
+
biz_bot: '1'
|
|
1062
|
+
}, tag: "bot"
|
|
1063
|
+
});
|
|
793
1064
|
}
|
|
794
1065
|
else if (isPinMsg) {
|
|
795
1066
|
additionalAttributes.edit = '2';
|
|
796
|
-
// required for keep message
|
|
797
|
-
}
|
|
798
|
-
else if (isKeepMsg) {
|
|
799
|
-
additionalAttributes.edit = '6';
|
|
800
|
-
// required for polling message
|
|
801
1067
|
}
|
|
802
1068
|
else if (isPollMessage) {
|
|
803
1069
|
additionalNodes.push({
|
|
804
1070
|
tag: 'meta',
|
|
805
1071
|
attrs: {
|
|
806
1072
|
polltype: 'creation'
|
|
807
|
-
}
|
|
1073
|
+
}
|
|
808
1074
|
});
|
|
809
|
-
// required to display AI icon on message
|
|
810
1075
|
}
|
|
811
|
-
else if (
|
|
1076
|
+
else if (isEventMsg) {
|
|
812
1077
|
additionalNodes.push({
|
|
1078
|
+
tag: 'meta',
|
|
813
1079
|
attrs: {
|
|
814
|
-
|
|
815
|
-
}
|
|
816
|
-
tag: "bot"
|
|
1080
|
+
event_type: 'creation'
|
|
1081
|
+
}
|
|
817
1082
|
});
|
|
818
1083
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
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
|
+
});
|
|
826
1091
|
if (config.emitOwnEvents) {
|
|
827
1092
|
process.nextTick(() => {
|
|
828
|
-
processingMutex.mutex(() =>
|
|
1093
|
+
processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
829
1094
|
});
|
|
830
1095
|
}
|
|
831
1096
|
return fullMsg;
|
|
832
1097
|
}
|
|
833
1098
|
}
|
|
834
1099
|
};
|
|
835
|
-
};
|
|
836
|
-
exports.makeMessagesSocket = makeMessagesSocket;
|
|
1100
|
+
};
|