@langitdeveloper/baileys 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Socket/messages-send.js +1233 -688
- package/package.json +1 -1
|
@@ -1,923 +1,1468 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
1
|
+
"use strict";
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
3
|
+
const { default: NodeCache } = require("@cacheable/node-cache");
|
|
4
|
+
const { Boom: Boom } = require("@hapi/boom");
|
|
5
|
+
const { randomBytes: randomBytes } = require("crypto");
|
|
6
|
+
const { proto: proto } = require("../../WAProto");
|
|
7
|
+
const {
|
|
8
|
+
DEFAULT_CACHE_TTLS: DEFAULT_CACHE_TTLS,
|
|
9
|
+
WA_DEFAULT_EPHEMERAL: WA_DEFAULT_EPHEMERAL,
|
|
10
|
+
} = require("../Defaults");
|
|
11
|
+
const {
|
|
12
|
+
delay: delay,
|
|
13
|
+
assertMediaContent: assertMediaContent,
|
|
14
|
+
bindWaitForEvent: bindWaitForEvent,
|
|
15
|
+
decryptMediaRetryData: decryptMediaRetryData,
|
|
16
|
+
encodeNewsletterMessage: encodeNewsletterMessage,
|
|
17
|
+
encodeSignedDeviceIdentity: encodeSignedDeviceIdentity,
|
|
18
|
+
encodeWAMessage: encodeWAMessage,
|
|
19
|
+
encryptMediaRetryRequest: encryptMediaRetryRequest,
|
|
20
|
+
extractDeviceJids: extractDeviceJids,
|
|
21
|
+
generateMessageID: generateMessageID,
|
|
22
|
+
generateParticipantHashV2: generateParticipantHashV2,
|
|
23
|
+
generateWAMessage: generateWAMessage,
|
|
24
|
+
generateWAMessageFromContent: generateWAMessageFromContent,
|
|
25
|
+
getStatusCodeForMediaRetry: getStatusCodeForMediaRetry,
|
|
26
|
+
getUrlFromDirectPath: getUrlFromDirectPath,
|
|
27
|
+
getWAUploadToServer: getWAUploadToServer,
|
|
28
|
+
MessageRetryManager: MessageRetryManager,
|
|
29
|
+
normalizeMessageContent: normalizeMessageContent,
|
|
30
|
+
parseAndInjectE2ESessions: parseAndInjectE2ESessions,
|
|
31
|
+
unixTimestampSeconds: unixTimestampSeconds,
|
|
32
|
+
prepareAlbumMessageContent: prepareAlbumMessageContent,
|
|
33
|
+
aggregateMessageKeysNotFromMe: aggregateMessageKeysNotFromMe,
|
|
34
|
+
} = require("../Utils");
|
|
35
|
+
const { WAMessageAddressingMode: WAMessageAddressingMode } = require("../Types");
|
|
36
|
+
const {
|
|
37
|
+
areJidsSameUser: areJidsSameUser,
|
|
38
|
+
getBinaryNodeChild: getBinaryNodeChild,
|
|
39
|
+
getBinaryNodeChildren: getBinaryNodeChildren,
|
|
40
|
+
getBinaryFilteredBizBot: getBinaryFilteredBizBot,
|
|
41
|
+
getBinaryFilteredButtons: getBinaryFilteredButtons,
|
|
42
|
+
isHostedLidUser: isHostedLidUser,
|
|
43
|
+
isHostedPnUser: isHostedPnUser,
|
|
44
|
+
isJidNewsletter: isJidNewsletter,
|
|
45
|
+
isJidGroup: isJidGroup,
|
|
46
|
+
isLidUser: isLidUser,
|
|
47
|
+
isPnUser: isPnUser,
|
|
48
|
+
jidDecode: jidDecode,
|
|
49
|
+
jidEncode: jidEncode,
|
|
50
|
+
jidNormalizedUser: jidNormalizedUser,
|
|
51
|
+
STORIES_JID: STORIES_JID,
|
|
52
|
+
S_WHATSAPP_NET: S_WHATSAPP_NET,
|
|
53
|
+
} = require("../WABinary");
|
|
54
|
+
const { USyncUser: USyncUser, USyncQuery: USyncQuery } = require("../WAUSync");
|
|
55
|
+
const { makeNewsletterSocket: makeNewsletterSocket } = require("./newsletter");
|
|
56
|
+
const { getUrlInfo: getUrlInfo } = require("../Utils/link-preview");
|
|
57
|
+
const { makeKeyedMutex: makeKeyedMutex } = require("../Utils/make-mutex");
|
|
20
58
|
const makeMessagesSocket = (config) => {
|
|
21
59
|
const {
|
|
22
|
-
logger,
|
|
23
|
-
linkPreviewImageThumbnailWidth,
|
|
24
|
-
generateHighQualityLinkPreview,
|
|
25
|
-
options:
|
|
26
|
-
patchMessageBeforeSending
|
|
60
|
+
logger: logger,
|
|
61
|
+
linkPreviewImageThumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
62
|
+
generateHighQualityLinkPreview: generateHighQualityLinkPreview,
|
|
63
|
+
options: httpRequestOptions,
|
|
64
|
+
patchMessageBeforeSending: patchMessageBeforeSending,
|
|
65
|
+
cachedGroupMetadata: cachedGroupMetadata,
|
|
66
|
+
enableRecentMessageCache: enableRecentMessageCache,
|
|
67
|
+
maxMsgRetryCount: maxMsgRetryCount,
|
|
27
68
|
} = config;
|
|
28
|
-
const
|
|
69
|
+
const conn = makeNewsletterSocket(config);
|
|
29
70
|
const {
|
|
30
|
-
ev,
|
|
31
|
-
authState,
|
|
32
|
-
|
|
33
|
-
signalRepository,
|
|
34
|
-
upsertMessage,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
sendNode,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
71
|
+
ev: ev,
|
|
72
|
+
authState: authState,
|
|
73
|
+
messageMutex: messageMutex,
|
|
74
|
+
signalRepository: signalRepository,
|
|
75
|
+
upsertMessage: upsertMessage,
|
|
76
|
+
createCallLink: createCallLink,
|
|
77
|
+
query: query,
|
|
78
|
+
fetchPrivacySettings: fetchPrivacySettings,
|
|
79
|
+
sendNode: sendNode,
|
|
80
|
+
groupQuery: groupQuery,
|
|
81
|
+
groupMetadata: groupMetadata,
|
|
82
|
+
groupToggleEphemeral: groupToggleEphemeral,
|
|
83
|
+
executeUSyncQuery: executeUSyncQuery,
|
|
84
|
+
newsletterMetadata: newsletterMetadata,
|
|
85
|
+
} = conn;
|
|
86
|
+
const userDevicesCache =
|
|
87
|
+
config.userDevicesCache ||
|
|
88
|
+
new NodeCache({
|
|
89
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
90
|
+
useClones: false,
|
|
91
|
+
});
|
|
92
|
+
const peerSessionsCache = new NodeCache({
|
|
93
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
94
|
+
useClones: false,
|
|
46
95
|
});
|
|
96
|
+
const messageRetryManager = enableRecentMessageCache
|
|
97
|
+
? new MessageRetryManager(logger, maxMsgRetryCount)
|
|
98
|
+
: null;
|
|
99
|
+
const encryptionMutex = makeKeyedMutex();
|
|
47
100
|
let mediaConn;
|
|
48
101
|
const refreshMediaConn = async (forceGet = false) => {
|
|
49
102
|
const media = await mediaConn;
|
|
50
|
-
if (
|
|
103
|
+
if (
|
|
104
|
+
!media ||
|
|
105
|
+
forceGet ||
|
|
106
|
+
new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1e3
|
|
107
|
+
) {
|
|
51
108
|
mediaConn = (async () => {
|
|
52
109
|
const result = await query({
|
|
53
|
-
tag:
|
|
54
|
-
attrs: {
|
|
55
|
-
|
|
56
|
-
xmlns: 'w:m',
|
|
57
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
58
|
-
},
|
|
59
|
-
content: [{ tag: 'media_conn', attrs: {} }]
|
|
110
|
+
tag: "iq",
|
|
111
|
+
attrs: { type: "set", xmlns: "w:m", to: S_WHATSAPP_NET },
|
|
112
|
+
content: [{ tag: "media_conn", attrs: {} }],
|
|
60
113
|
});
|
|
61
|
-
const mediaConnNode =
|
|
114
|
+
const mediaConnNode = getBinaryNodeChild(result, "media_conn");
|
|
62
115
|
const node = {
|
|
63
|
-
hosts:
|
|
116
|
+
hosts: getBinaryNodeChildren(mediaConnNode, "host").map(({ attrs: attrs }) => ({
|
|
64
117
|
hostname: attrs.hostname,
|
|
65
118
|
maxContentLengthBytes: +attrs.maxContentLengthBytes,
|
|
66
119
|
})),
|
|
67
120
|
auth: mediaConnNode.attrs.auth,
|
|
68
121
|
ttl: +mediaConnNode.attrs.ttl,
|
|
69
|
-
fetchDate: new Date()
|
|
122
|
+
fetchDate: new Date(),
|
|
70
123
|
};
|
|
71
|
-
logger.debug(
|
|
124
|
+
logger.debug("fetched media conn");
|
|
72
125
|
return node;
|
|
73
126
|
})();
|
|
74
127
|
}
|
|
75
128
|
return mediaConn;
|
|
76
129
|
};
|
|
77
|
-
/**
|
|
78
|
-
* generic send receipt function
|
|
79
|
-
* used for receipts of phone call, read, delivery etc.
|
|
80
|
-
* */
|
|
81
130
|
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
};
|
|
88
|
-
const isReadReceipt = type === 'read' || type === 'read-self';
|
|
131
|
+
if (!messageIds || messageIds.length === 0) {
|
|
132
|
+
throw new Boom("missing ids in receipt");
|
|
133
|
+
}
|
|
134
|
+
const node = { tag: "receipt", attrs: { id: messageIds[0] } };
|
|
135
|
+
const isReadReceipt = type === "read" || type === "read-self";
|
|
89
136
|
if (isReadReceipt) {
|
|
90
|
-
node.attrs.t =
|
|
137
|
+
node.attrs.t = unixTimestampSeconds().toString();
|
|
91
138
|
}
|
|
92
|
-
if (type ===
|
|
139
|
+
if (type === "sender" && (isPnUser(jid) || isLidUser(jid))) {
|
|
93
140
|
node.attrs.recipient = jid;
|
|
94
141
|
node.attrs.to = participant;
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
142
|
+
} else {
|
|
97
143
|
node.attrs.to = jid;
|
|
98
144
|
if (participant) {
|
|
99
145
|
node.attrs.participant = participant;
|
|
100
146
|
}
|
|
101
147
|
}
|
|
102
148
|
if (type) {
|
|
103
|
-
node.attrs.type =
|
|
149
|
+
node.attrs.type = type;
|
|
104
150
|
}
|
|
105
151
|
const remainingMessageIds = messageIds.slice(1);
|
|
106
152
|
if (remainingMessageIds.length) {
|
|
107
153
|
node.content = [
|
|
108
154
|
{
|
|
109
|
-
tag:
|
|
155
|
+
tag: "list",
|
|
110
156
|
attrs: {},
|
|
111
|
-
content: remainingMessageIds.map(id => ({
|
|
112
|
-
tag:
|
|
113
|
-
attrs: { id }
|
|
114
|
-
}))
|
|
115
|
-
}
|
|
157
|
+
content: remainingMessageIds.map((id) => ({
|
|
158
|
+
tag: "item",
|
|
159
|
+
attrs: { id: id },
|
|
160
|
+
})),
|
|
161
|
+
},
|
|
116
162
|
];
|
|
117
163
|
}
|
|
118
|
-
logger.debug({ attrs: node.attrs, messageIds },
|
|
164
|
+
logger.debug({ attrs: node.attrs, messageIds: messageIds }, "sending receipt for messages");
|
|
119
165
|
await sendNode(node);
|
|
120
166
|
};
|
|
121
|
-
/** Correctly bulk send receipts to multiple chats, participants */
|
|
122
167
|
const sendReceipts = async (keys, type) => {
|
|
123
|
-
const recps =
|
|
124
|
-
for (const { jid, participant, messageIds } of recps) {
|
|
168
|
+
const recps = aggregateMessageKeysNotFromMe(keys);
|
|
169
|
+
for (const { jid: jid, participant: participant, messageIds: messageIds } of recps) {
|
|
125
170
|
await sendReceipt(jid, participant, messageIds, type);
|
|
126
171
|
}
|
|
127
172
|
};
|
|
128
|
-
/** Bulk read messages. Keys can be from different chats & participants */
|
|
129
173
|
const readMessages = async (keys) => {
|
|
130
174
|
const privacySettings = await fetchPrivacySettings();
|
|
131
|
-
|
|
132
|
-
const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self';
|
|
175
|
+
const readType = privacySettings.readreceipts === "all" ? "read" : "read-self";
|
|
133
176
|
await sendReceipts(keys, readType);
|
|
134
177
|
};
|
|
135
|
-
/** Fetch all the devices we've to send a message to */
|
|
136
178
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
137
|
-
const deviceResults = []
|
|
138
|
-
|
|
179
|
+
const deviceResults = [];
|
|
139
180
|
if (!useCache) {
|
|
140
|
-
logger.debug(
|
|
181
|
+
logger.debug("not using cache for devices");
|
|
141
182
|
}
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
183
|
+
const toFetch = [];
|
|
184
|
+
const jidsWithUser = jids
|
|
185
|
+
.map((jid) => {
|
|
186
|
+
const decoded = jidDecode(jid);
|
|
187
|
+
const user = decoded?.user;
|
|
188
|
+
const device = decoded?.device;
|
|
189
|
+
const isExplicitDevice = typeof device === "number" && device >= 0;
|
|
190
|
+
if (isExplicitDevice && user) {
|
|
191
|
+
deviceResults.push({ user: user, device: device, jid: jid });
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
jid = jidNormalizedUser(jid);
|
|
195
|
+
return { jid: jid, user: user };
|
|
196
|
+
})
|
|
197
|
+
.filter((jid) => jid !== null);
|
|
198
|
+
let mgetDevices;
|
|
199
|
+
if (useCache && userDevicesCache.mget) {
|
|
200
|
+
const usersToFetch = jidsWithUser.map((j) => j?.user).filter(Boolean);
|
|
201
|
+
mgetDevices = await userDevicesCache.mget(usersToFetch);
|
|
202
|
+
}
|
|
203
|
+
for (const { jid: jid, user: user } of jidsWithUser) {
|
|
152
204
|
if (useCache) {
|
|
153
|
-
const devices =
|
|
154
|
-
|
|
205
|
+
const devices =
|
|
206
|
+
mgetDevices?.[user] ||
|
|
207
|
+
(userDevicesCache.mget ? undefined : await userDevicesCache.get(user));
|
|
155
208
|
if (devices) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
209
|
+
const devicesWithJid = devices.map((d) => ({
|
|
210
|
+
...d,
|
|
211
|
+
jid: jidEncode(d.user, d.server, d.device),
|
|
212
|
+
}));
|
|
213
|
+
deviceResults.push(...devicesWithJid);
|
|
214
|
+
logger.trace({ user: user }, "using cache for devices");
|
|
215
|
+
} else {
|
|
216
|
+
toFetch.push(jid);
|
|
162
217
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
else {
|
|
166
|
-
toFetch.push(jid)
|
|
218
|
+
} else {
|
|
219
|
+
toFetch.push(jid);
|
|
167
220
|
}
|
|
168
221
|
}
|
|
169
|
-
|
|
170
222
|
if (!toFetch.length) {
|
|
171
|
-
return deviceResults
|
|
223
|
+
return deviceResults;
|
|
172
224
|
}
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
225
|
+
const requestedLidUsers = new Set();
|
|
226
|
+
for (const jid of toFetch) {
|
|
227
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
228
|
+
const user = jidDecode(jid)?.user;
|
|
229
|
+
if (user) requestedLidUsers.add(user);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const query = new USyncQuery()
|
|
233
|
+
.withContext("message")
|
|
176
234
|
.withDeviceProtocol()
|
|
177
|
-
|
|
235
|
+
.withLIDProtocol();
|
|
178
236
|
for (const jid of toFetch) {
|
|
179
|
-
query.withUser(new
|
|
237
|
+
query.withUser(new USyncUser().withId(jid));
|
|
180
238
|
}
|
|
181
|
-
|
|
182
|
-
const result = await executeUSyncQuery(query)
|
|
183
|
-
|
|
239
|
+
const result = await executeUSyncQuery(query);
|
|
184
240
|
if (result) {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
241
|
+
const lidResults = result.list.filter((a) => !!a.lid);
|
|
242
|
+
if (lidResults.length > 0) {
|
|
243
|
+
logger.trace("Storing LID maps from device call");
|
|
244
|
+
await signalRepository.lidMapping.storeLIDPNMappings(
|
|
245
|
+
lidResults.map((a) => ({ lid: a.lid, pn: a.id }))
|
|
246
|
+
);
|
|
247
|
+
try {
|
|
248
|
+
const lids = lidResults.map((a) => a.lid);
|
|
249
|
+
if (lids.length) {
|
|
250
|
+
await assertSessions(lids, true);
|
|
251
|
+
}
|
|
252
|
+
} catch (e) {
|
|
253
|
+
logger.warn(
|
|
254
|
+
{ e: e, count: lidResults.length },
|
|
255
|
+
"failed to assert sessions for newly mapped LIDs"
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const extracted = extractDeviceJids(
|
|
260
|
+
result?.list,
|
|
261
|
+
authState.creds.me.id,
|
|
262
|
+
authState.creds.me.lid,
|
|
263
|
+
ignoreZeroDevices
|
|
264
|
+
);
|
|
265
|
+
const deviceMap = {};
|
|
188
266
|
for (const item of extracted) {
|
|
189
|
-
deviceMap[item.user] = deviceMap[item.user] || []
|
|
190
|
-
deviceMap[item.user]
|
|
191
|
-
deviceResults.push(item)
|
|
267
|
+
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
268
|
+
deviceMap[item.user]?.push(item);
|
|
192
269
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
270
|
+
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
271
|
+
const isLidUser = requestedLidUsers.has(user);
|
|
272
|
+
for (const item of userDevices) {
|
|
273
|
+
const finalJid = isLidUser
|
|
274
|
+
? jidEncode(user, item.server, item.device)
|
|
275
|
+
: jidEncode(item.user, item.server, item.device);
|
|
276
|
+
deviceResults.push({ ...item, jid: finalJid });
|
|
277
|
+
logger.debug(
|
|
278
|
+
{
|
|
279
|
+
user: item.user,
|
|
280
|
+
device: item.device,
|
|
281
|
+
finalJid: finalJid,
|
|
282
|
+
usedLid: isLidUser,
|
|
283
|
+
},
|
|
284
|
+
"Processed device with LID priority"
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (userDevicesCache.mset) {
|
|
289
|
+
await userDevicesCache.mset(
|
|
290
|
+
Object.entries(deviceMap).map(([key, value]) => ({
|
|
291
|
+
key: key,
|
|
292
|
+
value: value,
|
|
293
|
+
}))
|
|
294
|
+
);
|
|
295
|
+
} else {
|
|
296
|
+
for (const key in deviceMap) {
|
|
297
|
+
if (deviceMap[key]) await userDevicesCache.set(key, deviceMap[key]);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const userDeviceUpdates = {};
|
|
301
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
302
|
+
if (devices && devices.length > 0) {
|
|
303
|
+
userDeviceUpdates[userId] = devices.map((d) => d.device?.toString() || "0");
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
307
|
+
try {
|
|
308
|
+
await authState.keys.set({ "device-list": userDeviceUpdates });
|
|
309
|
+
logger.debug(
|
|
310
|
+
{ userCount: Object.keys(userDeviceUpdates).length },
|
|
311
|
+
"stored user device lists for bulk migration"
|
|
312
|
+
);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
logger.warn({ error: error }, "failed to store user device lists");
|
|
315
|
+
}
|
|
196
316
|
}
|
|
197
317
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
318
|
+
return deviceResults;
|
|
319
|
+
};
|
|
320
|
+
const updateMemberLabel = (jid, memberLabel) => {
|
|
321
|
+
if (!isJidGroup(jid)) {
|
|
322
|
+
throw new Error("Jid must a group!");
|
|
323
|
+
}
|
|
324
|
+
const protocolMessage = {
|
|
325
|
+
protocolMessage: {
|
|
326
|
+
type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
|
|
327
|
+
memberLabel: {
|
|
328
|
+
label: memberLabel?.slice(0, 30),
|
|
329
|
+
labelTimestamp: unixTimestampSeconds(),
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
return relayMessage(jid, protocolMessage, {
|
|
334
|
+
additionalNodes: [
|
|
335
|
+
{
|
|
336
|
+
tag: "meta",
|
|
337
|
+
attrs: { tag_reason: "user_update", appdata: "member_tag" },
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
});
|
|
341
|
+
};
|
|
201
342
|
const assertSessions = async (jids, force) => {
|
|
202
343
|
let didFetchNewSession = false;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
344
|
+
const uniqueJids = [...new Set(jids)];
|
|
345
|
+
const jidsRequiringFetch = [];
|
|
346
|
+
logger.debug({ jids: jids }, "assertSessions call with jids");
|
|
347
|
+
for (const jid of uniqueJids) {
|
|
348
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
349
|
+
const cachedSession = peerSessionsCache.get(signalId);
|
|
350
|
+
if (cachedSession !== undefined) {
|
|
351
|
+
if (cachedSession && !force) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
} else {
|
|
355
|
+
const sessionValidation = await signalRepository.validateSession(jid);
|
|
356
|
+
const hasSession = sessionValidation.exists;
|
|
357
|
+
peerSessionsCache.set(signalId, hasSession);
|
|
358
|
+
if (hasSession && !force) {
|
|
359
|
+
continue;
|
|
216
360
|
}
|
|
217
361
|
}
|
|
362
|
+
jidsRequiringFetch.push(jid);
|
|
218
363
|
}
|
|
219
364
|
if (jidsRequiringFetch.length) {
|
|
220
|
-
|
|
365
|
+
const wireJids = [
|
|
366
|
+
...jidsRequiringFetch.filter((jid) => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
367
|
+
...(
|
|
368
|
+
(await signalRepository.lidMapping.getLIDsForPNs(
|
|
369
|
+
jidsRequiringFetch.filter((jid) => !!isPnUser(jid) || !!isHostedPnUser(jid))
|
|
370
|
+
)) || []
|
|
371
|
+
).map((a) => a.lid),
|
|
372
|
+
];
|
|
373
|
+
logger.debug(
|
|
374
|
+
{ jidsRequiringFetch: jidsRequiringFetch, wireJids: wireJids },
|
|
375
|
+
"fetching sessions"
|
|
376
|
+
);
|
|
221
377
|
const result = await query({
|
|
222
|
-
tag:
|
|
223
|
-
attrs: {
|
|
224
|
-
xmlns: 'encrypt',
|
|
225
|
-
type: 'get',
|
|
226
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
227
|
-
},
|
|
378
|
+
tag: "iq",
|
|
379
|
+
attrs: { xmlns: "encrypt", type: "get", to: S_WHATSAPP_NET },
|
|
228
380
|
content: [
|
|
229
381
|
{
|
|
230
|
-
tag:
|
|
382
|
+
tag: "key",
|
|
231
383
|
attrs: {},
|
|
232
|
-
content:
|
|
233
|
-
|
|
234
|
-
attrs
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
384
|
+
content: wireJids.map((jid) => {
|
|
385
|
+
const attrs = { jid: jid };
|
|
386
|
+
if (force) attrs.reason = "identity";
|
|
387
|
+
return { tag: "user", attrs: attrs };
|
|
388
|
+
}),
|
|
389
|
+
},
|
|
390
|
+
],
|
|
238
391
|
});
|
|
239
|
-
await
|
|
392
|
+
await parseAndInjectE2ESessions(result, signalRepository);
|
|
240
393
|
didFetchNewSession = true;
|
|
394
|
+
for (const wireJid of wireJids) {
|
|
395
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
|
|
396
|
+
peerSessionsCache.set(signalId, true);
|
|
397
|
+
}
|
|
241
398
|
}
|
|
242
399
|
return didFetchNewSession;
|
|
243
400
|
};
|
|
244
|
-
|
|
245
|
-
|
|
246
401
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
247
402
|
if (!authState.creds.me?.id) {
|
|
248
|
-
throw new
|
|
403
|
+
throw new Boom("Not authenticated");
|
|
249
404
|
}
|
|
250
|
-
|
|
251
405
|
const protocolMessage = {
|
|
252
406
|
protocolMessage: {
|
|
253
407
|
peerDataOperationRequestMessage: pdoMessage,
|
|
254
|
-
type:
|
|
255
|
-
}
|
|
408
|
+
type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE,
|
|
409
|
+
},
|
|
256
410
|
};
|
|
257
|
-
const meJid =
|
|
411
|
+
const meJid = jidNormalizedUser(authState.creds.me.id);
|
|
258
412
|
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
259
|
-
additionalAttributes: {
|
|
260
|
-
|
|
261
|
-
// eslint-disable-next-line camelcase
|
|
262
|
-
push_priority: 'high_force',
|
|
263
|
-
},
|
|
413
|
+
additionalAttributes: { category: "peer", push_priority: "high_force" },
|
|
414
|
+
additionalNodes: [{ tag: "meta", attrs: { appdata: "default" } }],
|
|
264
415
|
});
|
|
265
416
|
return msgId;
|
|
266
417
|
};
|
|
267
|
-
const createParticipantNodes = async (
|
|
268
|
-
|
|
269
|
-
|
|
418
|
+
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
419
|
+
if (!recipientJids.length) {
|
|
420
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
421
|
+
}
|
|
422
|
+
const patched = await patchMessageBeforeSending(message, recipientJids);
|
|
423
|
+
const patchedMessages = Array.isArray(patched)
|
|
424
|
+
? patched
|
|
425
|
+
: recipientJids.map((jid) => ({ recipientJid: jid, message: patched }));
|
|
270
426
|
let shouldIncludeDeviceIdentity = false;
|
|
271
|
-
const nodes = await Promise.all(jids.map(async (jid) => {
|
|
272
|
-
const { type, ciphertext } = await signalRepository
|
|
273
|
-
.encryptMessage({ jid, data: bytes });
|
|
274
|
-
if (type === 'pkmsg') {
|
|
275
|
-
shouldIncludeDeviceIdentity = true;
|
|
276
|
-
}
|
|
277
|
-
const node = {
|
|
278
|
-
tag: 'to',
|
|
279
|
-
attrs: { jid },
|
|
280
|
-
content: [{
|
|
281
|
-
tag: 'enc',
|
|
282
|
-
attrs: {
|
|
283
|
-
v: '2',
|
|
284
|
-
type,
|
|
285
|
-
...extraAttrs || {}
|
|
286
|
-
},
|
|
287
|
-
content: ciphertext
|
|
288
|
-
}]
|
|
289
|
-
};
|
|
290
|
-
return node;
|
|
291
|
-
}));
|
|
292
|
-
return { nodes, shouldIncludeDeviceIdentity };
|
|
293
|
-
}; //apela
|
|
294
|
-
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, cachedGroupMetadata, useCachedGroupMetadata, statusJidList, AI = true }) => {
|
|
295
427
|
const meId = authState.creds.me.id;
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
428
|
+
const meLid = authState.creds.me?.lid;
|
|
429
|
+
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
430
|
+
const encryptionPromises = patchedMessages.map(
|
|
431
|
+
async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
432
|
+
if (!jid) return null;
|
|
433
|
+
let msgToEncrypt = patchedMessage;
|
|
434
|
+
if (dsmMessage) {
|
|
435
|
+
const { user: targetUser } = jidDecode(jid);
|
|
436
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
437
|
+
const ownLidUser = meLidUser;
|
|
438
|
+
const isOwnUser =
|
|
439
|
+
targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
440
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
441
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
442
|
+
msgToEncrypt = dsmMessage;
|
|
443
|
+
logger.debug(
|
|
444
|
+
{ jid: jid, targetUser: targetUser },
|
|
445
|
+
"Using DSM for own device"
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
450
|
+
const mutexKey = jid;
|
|
451
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
452
|
+
const { type: type, ciphertext: ciphertext } =
|
|
453
|
+
await signalRepository.encryptMessage({ jid: jid, data: bytes });
|
|
454
|
+
if (type === "pkmsg") {
|
|
455
|
+
shouldIncludeDeviceIdentity = true;
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
tag: "to",
|
|
459
|
+
attrs: { jid: jid },
|
|
460
|
+
content: [
|
|
461
|
+
{
|
|
462
|
+
tag: "enc",
|
|
463
|
+
attrs: { v: "2", type: type, ...(extraAttrs || {}) },
|
|
464
|
+
content: ciphertext,
|
|
465
|
+
},
|
|
466
|
+
],
|
|
467
|
+
};
|
|
468
|
+
});
|
|
469
|
+
return node;
|
|
470
|
+
}
|
|
471
|
+
);
|
|
472
|
+
const nodes = (await Promise.all(encryptionPromises)).filter((node) => node !== null);
|
|
473
|
+
return {
|
|
474
|
+
nodes: nodes,
|
|
475
|
+
shouldIncludeDeviceIdentity: shouldIncludeDeviceIdentity,
|
|
476
|
+
};
|
|
477
|
+
};
|
|
478
|
+
const profilePictureUrl = async (jid) => {
|
|
479
|
+
if (isJidNewsletter(jid)) {
|
|
480
|
+
const metadata = await conn.newsletterMetadata("JID", jid);
|
|
481
|
+
return getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || "");
|
|
482
|
+
} else {
|
|
483
|
+
const result = await query({
|
|
484
|
+
tag: "iq",
|
|
485
|
+
attrs: {
|
|
486
|
+
target: jidNormalizedUser(jid),
|
|
487
|
+
to: S_WHATSAPP_NET,
|
|
488
|
+
type: "get",
|
|
489
|
+
xmlns: "w:profile:picture",
|
|
490
|
+
},
|
|
491
|
+
content: [{ tag: "picture", attrs: { type: "image", query: "url" } }],
|
|
492
|
+
});
|
|
493
|
+
const child = getBinaryNodeChild(result, "picture");
|
|
494
|
+
return child?.attrs?.url || null;
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
const relayMessage = async (
|
|
498
|
+
jid,
|
|
499
|
+
message,
|
|
500
|
+
{
|
|
501
|
+
messageId: msgId,
|
|
502
|
+
participant: participant,
|
|
503
|
+
additionalAttributes: additionalAttributes,
|
|
504
|
+
useUserDevicesCache: useUserDevicesCache,
|
|
505
|
+
useCachedGroupMetadata: useCachedGroupMetadata,
|
|
506
|
+
statusJidList: statusJidList,
|
|
507
|
+
additionalNodes: additionalNodes,
|
|
508
|
+
AI: AI = false,
|
|
509
|
+
}
|
|
510
|
+
) => {
|
|
511
|
+
const meId = authState.creds.me.id;
|
|
512
|
+
const meLid = authState.creds.me?.lid;
|
|
513
|
+
const isRetryResend = Boolean(participant?.jid);
|
|
514
|
+
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
515
|
+
let didPushAdditional = false;
|
|
516
|
+
const statusJid = "status@broadcast";
|
|
517
|
+
const { user: user, server: server } = jidDecode(jid);
|
|
518
|
+
const isGroup = server === "g.us";
|
|
301
519
|
const isStatus = jid === statusJid;
|
|
302
|
-
const isLid = server ===
|
|
303
|
-
const
|
|
304
|
-
const
|
|
305
|
-
|
|
520
|
+
const isLid = server === "lid";
|
|
521
|
+
const isNewsletter = server === "newsletter";
|
|
522
|
+
const isGroupOrStatus = isGroup || isStatus;
|
|
523
|
+
const finalJid = jid;
|
|
524
|
+
msgId = msgId || generateMessageID(meId);
|
|
306
525
|
useUserDevicesCache = useUserDevicesCache !== false;
|
|
307
|
-
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
|
526
|
+
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
308
527
|
const participants = [];
|
|
309
|
-
const destinationJid =
|
|
528
|
+
const destinationJid = !isStatus ? finalJid : statusJid;
|
|
310
529
|
const binaryNodeContent = [];
|
|
311
530
|
const devices = [];
|
|
312
531
|
const meMsg = {
|
|
313
|
-
deviceSentMessage: {
|
|
314
|
-
|
|
315
|
-
message
|
|
316
|
-
}
|
|
532
|
+
deviceSentMessage: { destinationJid: destinationJid, message: message },
|
|
533
|
+
messageContextInfo: message.messageContextInfo,
|
|
317
534
|
};
|
|
318
|
-
const extraAttrs = {}
|
|
319
|
-
const
|
|
535
|
+
const extraAttrs = {};
|
|
536
|
+
const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/;
|
|
537
|
+
const messages = normalizeMessageContent(message);
|
|
320
538
|
const buttonType = getButtonType(messages);
|
|
539
|
+
const pollMessage =
|
|
540
|
+
messages.pollCreationMessage ||
|
|
541
|
+
messages.pollCreationMessageV2 ||
|
|
542
|
+
messages.pollCreationMessageV3;
|
|
321
543
|
if (participant) {
|
|
322
|
-
// when the retry request is not for a group
|
|
323
|
-
// only send to the specific device that asked for a retry
|
|
324
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
325
544
|
if (!isGroup && !isStatus) {
|
|
326
|
-
additionalAttributes = {
|
|
545
|
+
additionalAttributes = {
|
|
546
|
+
...additionalAttributes,
|
|
547
|
+
device_fanout: "false",
|
|
548
|
+
};
|
|
327
549
|
}
|
|
328
|
-
const { user, device } =
|
|
329
|
-
devices.push({ user, device });
|
|
550
|
+
const { user: user, device: device } = jidDecode(participant.jid);
|
|
551
|
+
devices.push({ user: user, device: device, jid: participant.jid });
|
|
330
552
|
}
|
|
331
553
|
await authState.keys.transaction(async () => {
|
|
332
|
-
const mediaType = getMediaType(
|
|
333
|
-
|
|
554
|
+
const mediaType = getMediaType(message);
|
|
334
555
|
if (mediaType) {
|
|
335
|
-
extraAttrs[
|
|
556
|
+
extraAttrs["mediatype"] = mediaType;
|
|
557
|
+
}
|
|
558
|
+
if (isNewsletter) {
|
|
559
|
+
|
|
560
|
+
const patched = patchMessageBeforeSending
|
|
561
|
+
? await patchMessageBeforeSending(message, [])
|
|
562
|
+
: message
|
|
563
|
+
|
|
564
|
+
const mediaType = getMediaType(patched)
|
|
565
|
+
|
|
566
|
+
if (mediaType) {
|
|
567
|
+
extraAttrs["mediatype"] = mediaType
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (
|
|
571
|
+
patched.interactiveMessage &&
|
|
572
|
+
!extraAttrs["mediatype"]
|
|
573
|
+
) {
|
|
574
|
+
extraAttrs["mediatype"] = "interactive"
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const bytes = encodeNewsletterMessage(patched)
|
|
578
|
+
|
|
579
|
+
binaryNodeContent.push({
|
|
580
|
+
tag: "plaintext",
|
|
581
|
+
attrs: extraAttrs,
|
|
582
|
+
content: bytes
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
const stanza = {
|
|
586
|
+
tag: "message",
|
|
587
|
+
attrs: {
|
|
588
|
+
to: jid,
|
|
589
|
+
id: msgId,
|
|
590
|
+
type: getTypeMessage(patched),
|
|
591
|
+
...(additionalAttributes || {}),
|
|
592
|
+
},
|
|
593
|
+
content: binaryNodeContent,
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
logger.debug(
|
|
597
|
+
{
|
|
598
|
+
msgId,
|
|
599
|
+
mediaType,
|
|
600
|
+
extraAttrs
|
|
601
|
+
},
|
|
602
|
+
`sending newsletter message to ${jid}`
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
await sendNode(stanza)
|
|
606
|
+
|
|
607
|
+
return
|
|
608
|
+
}
|
|
609
|
+
if (
|
|
610
|
+
messages.pinInChatMessage ||
|
|
611
|
+
messages.keepInChatMessage ||
|
|
612
|
+
message.reactionMessage ||
|
|
613
|
+
message.protocolMessage?.editedMessage
|
|
614
|
+
) {
|
|
615
|
+
extraAttrs["decrypt-fail"] = "hide";
|
|
336
616
|
}
|
|
337
|
-
|
|
338
|
-
if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
|
|
339
|
-
extraAttrs['decrypt-fail'] = 'hide'
|
|
340
|
-
}
|
|
341
|
-
|
|
342
617
|
if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
|
|
343
|
-
extraAttrs[
|
|
618
|
+
extraAttrs["native_flow_name"] =
|
|
619
|
+
messages.interactiveResponseMessage.nativeFlowResponseMessage?.name ||
|
|
620
|
+
"menu_options";
|
|
344
621
|
}
|
|
345
|
-
|
|
346
|
-
if (isGroup || isStatus) {
|
|
622
|
+
if (isGroupOrStatus && !isRetryResend) {
|
|
347
623
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
348
624
|
(async () => {
|
|
349
|
-
let groupData =
|
|
350
|
-
|
|
351
|
-
|
|
625
|
+
let groupData =
|
|
626
|
+
useCachedGroupMetadata && cachedGroupMetadata
|
|
627
|
+
? await cachedGroupMetadata(jid)
|
|
628
|
+
: undefined;
|
|
629
|
+
if (groupData && Array.isArray(groupData?.participants)) {
|
|
630
|
+
logger.trace(
|
|
631
|
+
{ jid: jid, participants: groupData.participants.length },
|
|
632
|
+
"using cached group metadata"
|
|
633
|
+
);
|
|
634
|
+
} else if (!isStatus) {
|
|
635
|
+
groupData = await groupMetadata(jid);
|
|
352
636
|
}
|
|
353
|
-
|
|
354
|
-
else if (!isStatus) {
|
|
355
|
-
groupData = await groupMetadata(jid)
|
|
356
|
-
}
|
|
357
|
-
|
|
358
637
|
return groupData;
|
|
359
638
|
})(),
|
|
360
639
|
(async () => {
|
|
361
640
|
if (!participant && !isStatus) {
|
|
362
|
-
const result = await authState.keys.get(
|
|
363
|
-
return result[jid] || {}
|
|
641
|
+
const result = await authState.keys.get("sender-key-memory", [jid]);
|
|
642
|
+
return result[jid] || {};
|
|
364
643
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
})()
|
|
644
|
+
return {};
|
|
645
|
+
})(),
|
|
369
646
|
]);
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
647
|
+
const participantsList = groupData ? groupData.participants.map((p) => p.id) : [];
|
|
648
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
649
|
+
additionalAttributes = {
|
|
650
|
+
...additionalAttributes,
|
|
651
|
+
expiration: groupData.ephemeralDuration.toString(),
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
if (isStatus && statusJidList) {
|
|
655
|
+
participantsList.push(...statusJidList);
|
|
656
|
+
}
|
|
657
|
+
const additionalDevices = await getUSyncDevices(
|
|
658
|
+
participantsList,
|
|
659
|
+
!!useUserDevicesCache,
|
|
660
|
+
false
|
|
661
|
+
);
|
|
662
|
+
devices.push(...additionalDevices);
|
|
663
|
+
if (isGroup) {
|
|
664
|
+
additionalAttributes = {
|
|
665
|
+
...additionalAttributes,
|
|
666
|
+
addressing_mode: groupData?.addressingMode || "lid",
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
const patched = await patchMessageBeforeSending(message);
|
|
670
|
+
if (Array.isArray(patched)) {
|
|
671
|
+
throw new Boom("Per-jid patching is not supported in groups");
|
|
672
|
+
}
|
|
673
|
+
const bytes = encodeWAMessage(patched);
|
|
674
|
+
const groupAddressingMode =
|
|
675
|
+
additionalAttributes?.["addressing_mode"] || groupData?.addressingMode || "lid";
|
|
676
|
+
const groupSenderIdentity = groupAddressingMode === "lid" && meLid ? meLid : meId;
|
|
677
|
+
const {
|
|
678
|
+
ciphertext: ciphertext,
|
|
679
|
+
senderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
680
|
+
} = await signalRepository.encryptGroupMessage({
|
|
394
681
|
group: destinationJid,
|
|
395
682
|
data: bytes,
|
|
396
|
-
meId,
|
|
683
|
+
meId: groupSenderIdentity,
|
|
397
684
|
});
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const
|
|
402
|
-
if (
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
685
|
+
const senderKeyRecipients = [];
|
|
686
|
+
for (const device of devices) {
|
|
687
|
+
const deviceJid = device.jid;
|
|
688
|
+
const hasKey = !!senderKeyMap[deviceJid];
|
|
689
|
+
if (
|
|
690
|
+
(!hasKey || !!participant) &&
|
|
691
|
+
!isHostedLidUser(deviceJid) &&
|
|
692
|
+
!isHostedPnUser(deviceJid) &&
|
|
693
|
+
device.device !== 99
|
|
694
|
+
) {
|
|
695
|
+
senderKeyRecipients.push(deviceJid);
|
|
696
|
+
senderKeyMap[deviceJid] = true;
|
|
406
697
|
}
|
|
407
698
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (senderKeyJids.length) {
|
|
411
|
-
logger.debug({ senderKeyJids }, 'sending new sender key');
|
|
699
|
+
if (senderKeyRecipients.length) {
|
|
700
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, "sending new sender key");
|
|
412
701
|
const senderKeyMsg = {
|
|
413
702
|
senderKeyDistributionMessage: {
|
|
414
703
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
415
|
-
groupId: destinationJid
|
|
416
|
-
}
|
|
704
|
+
groupId: destinationJid,
|
|
705
|
+
},
|
|
417
706
|
};
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
707
|
+
const senderKeySessionTargets = senderKeyRecipients;
|
|
708
|
+
await assertSessions(senderKeySessionTargets);
|
|
709
|
+
const result = await createParticipantNodes(
|
|
710
|
+
senderKeyRecipients,
|
|
711
|
+
senderKeyMsg,
|
|
712
|
+
extraAttrs
|
|
713
|
+
);
|
|
714
|
+
shouldIncludeDeviceIdentity =
|
|
715
|
+
shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
421
716
|
participants.push(...result.nodes);
|
|
422
717
|
}
|
|
423
718
|
binaryNodeContent.push({
|
|
424
|
-
tag:
|
|
425
|
-
attrs: { v:
|
|
426
|
-
content: ciphertext
|
|
719
|
+
tag: "enc",
|
|
720
|
+
attrs: { v: "2", type: "skmsg", ...extraAttrs },
|
|
721
|
+
content: ciphertext,
|
|
427
722
|
});
|
|
428
|
-
await authState.keys.set({
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
723
|
+
await authState.keys.set({
|
|
724
|
+
"sender-key-memory": { [jid]: senderKeyMap },
|
|
725
|
+
});
|
|
726
|
+
} else {
|
|
727
|
+
let ownId = meId;
|
|
728
|
+
if (isLid && meLid) {
|
|
729
|
+
ownId = meLid;
|
|
730
|
+
logger.debug(
|
|
731
|
+
{ to: jid, ownId: ownId },
|
|
732
|
+
"Using LID identity for @lid conversation"
|
|
733
|
+
);
|
|
734
|
+
} else {
|
|
735
|
+
logger.debug(
|
|
736
|
+
{ to: jid, ownId: ownId },
|
|
737
|
+
"Using PN identity for @s.whatsapp.net conversation"
|
|
738
|
+
);
|
|
441
739
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
740
|
+
const { user: ownUser } = jidDecode(ownId);
|
|
741
|
+
if (!isRetryResend) {
|
|
742
|
+
const targetUserServer = isLid ? "lid" : "s.whatsapp.net";
|
|
743
|
+
devices.push({
|
|
744
|
+
user: user,
|
|
745
|
+
device: 0,
|
|
746
|
+
jid: jidEncode(user, targetUserServer, 0),
|
|
747
|
+
});
|
|
748
|
+
if (user !== ownUser) {
|
|
749
|
+
const ownUserServer = isLid ? "lid" : "s.whatsapp.net";
|
|
750
|
+
const ownUserForAddressing =
|
|
751
|
+
isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
752
|
+
devices.push({
|
|
753
|
+
user: ownUserForAddressing,
|
|
754
|
+
device: 0,
|
|
755
|
+
jid: jidEncode(ownUserForAddressing, ownUserServer, 0),
|
|
756
|
+
});
|
|
459
757
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
758
|
+
if (additionalAttributes?.["category"] !== "peer") {
|
|
759
|
+
devices.length = 0;
|
|
760
|
+
const senderIdentity =
|
|
761
|
+
isLid && meLid
|
|
762
|
+
? jidEncode(jidDecode(meLid)?.user, "lid", undefined)
|
|
763
|
+
: jidEncode(jidDecode(meId)?.user, "s.whatsapp.net", undefined);
|
|
764
|
+
const sessionDevices = await getUSyncDevices(
|
|
765
|
+
[senderIdentity, jid],
|
|
766
|
+
true,
|
|
767
|
+
false
|
|
768
|
+
);
|
|
769
|
+
devices.push(...sessionDevices);
|
|
770
|
+
logger.debug(
|
|
771
|
+
{
|
|
772
|
+
deviceCount: devices.length,
|
|
773
|
+
devices: devices.map(
|
|
774
|
+
(d) => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`
|
|
775
|
+
),
|
|
776
|
+
},
|
|
777
|
+
"Device enumeration complete with unified addressing"
|
|
778
|
+
);
|
|
465
779
|
}
|
|
466
780
|
}
|
|
467
|
-
const allRecipients = []
|
|
468
|
-
const meRecipients = []
|
|
469
|
-
const otherRecipients = []
|
|
470
|
-
const { user: mePnUser } =
|
|
471
|
-
const { user: meLidUser } = meLid ?
|
|
472
|
-
for (const { user,
|
|
473
|
-
const
|
|
474
|
-
const isExactSenderDevice = encodedJid === meId || (meLid && encodedJid === meLid)
|
|
781
|
+
const allRecipients = [];
|
|
782
|
+
const meRecipients = [];
|
|
783
|
+
const otherRecipients = [];
|
|
784
|
+
const { user: mePnUser } = jidDecode(meId);
|
|
785
|
+
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
|
|
786
|
+
for (const { user: user, jid: jid } of devices) {
|
|
787
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
475
788
|
if (isExactSenderDevice) {
|
|
476
|
-
logger.debug(
|
|
477
|
-
|
|
789
|
+
logger.debug(
|
|
790
|
+
{ jid: jid, meId: meId, meLid: meLid },
|
|
791
|
+
"Skipping exact sender device (whatsmeow pattern)"
|
|
792
|
+
);
|
|
793
|
+
continue;
|
|
478
794
|
}
|
|
479
|
-
const isMe = user === mePnUser || user === meLidUser
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
} else {
|
|
485
|
-
ptcp = false
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
if (!ptcp) {
|
|
489
|
-
if (isMe) {
|
|
490
|
-
meRecipients.push(encodedJid)
|
|
491
|
-
} else {
|
|
492
|
-
otherRecipients.push(encodedJid)
|
|
493
|
-
}
|
|
494
|
-
allRecipients.push(encodedJid)
|
|
795
|
+
const isMe = user === mePnUser || user === meLidUser;
|
|
796
|
+
if (isMe) {
|
|
797
|
+
meRecipients.push(jid);
|
|
798
|
+
} else {
|
|
799
|
+
otherRecipients.push(jid);
|
|
495
800
|
}
|
|
801
|
+
allRecipients.push(jid);
|
|
496
802
|
}
|
|
497
|
-
await assertSessions(allRecipients
|
|
498
|
-
const [
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
]
|
|
803
|
+
await assertSessions(allRecipients);
|
|
804
|
+
const [
|
|
805
|
+
{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
|
|
806
|
+
{ nodes: otherNodes, shouldIncludeDeviceIdentity: s2 },
|
|
807
|
+
] = await Promise.all([
|
|
808
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
809
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg),
|
|
810
|
+
]);
|
|
502
811
|
participants.push(...meNodes);
|
|
503
812
|
participants.push(...otherNodes);
|
|
813
|
+
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
814
|
+
extraAttrs["phash"] = generateParticipantHashV2([
|
|
815
|
+
...meRecipients,
|
|
816
|
+
...otherRecipients,
|
|
817
|
+
]);
|
|
818
|
+
}
|
|
504
819
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
505
820
|
}
|
|
821
|
+
if (isRetryResend) {
|
|
822
|
+
const isParticipantLid = isLidUser(participant.jid);
|
|
823
|
+
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
|
|
824
|
+
const encodedMessageToSend = isMe
|
|
825
|
+
? encodeWAMessage({
|
|
826
|
+
deviceSentMessage: {
|
|
827
|
+
destinationJid: destinationJid,
|
|
828
|
+
message: message,
|
|
829
|
+
},
|
|
830
|
+
})
|
|
831
|
+
: encodeWAMessage(message);
|
|
832
|
+
const { type: type, ciphertext: encryptedContent } =
|
|
833
|
+
await signalRepository.encryptMessage({
|
|
834
|
+
data: encodedMessageToSend,
|
|
835
|
+
jid: participant.jid,
|
|
836
|
+
});
|
|
837
|
+
binaryNodeContent.push({
|
|
838
|
+
tag: "enc",
|
|
839
|
+
attrs: { v: "2", type: type, count: participant.count.toString() },
|
|
840
|
+
content: encryptedContent,
|
|
841
|
+
});
|
|
842
|
+
}
|
|
506
843
|
if (participants.length) {
|
|
507
|
-
if (additionalAttributes?.[
|
|
508
|
-
const peerNode = participants[0]?.content?.[0]
|
|
509
|
-
|
|
844
|
+
if (additionalAttributes?.["category"] === "peer") {
|
|
845
|
+
const peerNode = participants[0]?.content?.[0];
|
|
510
846
|
if (peerNode) {
|
|
511
|
-
binaryNodeContent.push(peerNode)
|
|
847
|
+
binaryNodeContent.push(peerNode);
|
|
512
848
|
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
else {
|
|
849
|
+
} else {
|
|
516
850
|
binaryNodeContent.push({
|
|
517
|
-
tag:
|
|
851
|
+
tag: "participants",
|
|
518
852
|
attrs: {},
|
|
519
|
-
content: participants
|
|
520
|
-
})
|
|
853
|
+
content: participants,
|
|
854
|
+
});
|
|
521
855
|
}
|
|
522
856
|
}
|
|
523
|
-
|
|
524
857
|
const stanza = {
|
|
525
|
-
tag:
|
|
858
|
+
tag: "message",
|
|
526
859
|
attrs: {
|
|
527
860
|
id: msgId,
|
|
528
|
-
|
|
529
|
-
|
|
861
|
+
to: destinationJid,
|
|
862
|
+
type: getTypeMessage(message),
|
|
863
|
+
...(additionalAttributes || {}),
|
|
530
864
|
},
|
|
531
|
-
content: binaryNodeContent
|
|
532
|
-
}
|
|
533
|
-
// if the participant to send to is explicitly specified (generally retry recp)
|
|
534
|
-
// ensure the message is only sent to that person
|
|
535
|
-
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
865
|
+
content: binaryNodeContent,
|
|
866
|
+
};
|
|
536
867
|
if (participant) {
|
|
537
|
-
if (
|
|
868
|
+
if (isJidGroup(destinationJid)) {
|
|
538
869
|
stanza.attrs.to = destinationJid;
|
|
539
870
|
stanza.attrs.participant = participant.jid;
|
|
540
|
-
}
|
|
541
|
-
else if (WABinary_1.areJidsSameUser(participant.jid, meId)) {
|
|
871
|
+
} else if (areJidsSameUser(participant.jid, meId)) {
|
|
542
872
|
stanza.attrs.to = participant.jid;
|
|
543
873
|
stanza.attrs.recipient = destinationJid;
|
|
544
|
-
}
|
|
545
|
-
else {
|
|
874
|
+
} else {
|
|
546
875
|
stanza.attrs.to = participant.jid;
|
|
547
876
|
}
|
|
548
|
-
}
|
|
549
|
-
else {
|
|
877
|
+
} else {
|
|
550
878
|
stanza.attrs.to = destinationJid;
|
|
551
879
|
}
|
|
552
880
|
if (shouldIncludeDeviceIdentity) {
|
|
553
881
|
stanza.content.push({
|
|
554
|
-
tag:
|
|
882
|
+
tag: "device-identity",
|
|
555
883
|
attrs: {},
|
|
556
|
-
content:
|
|
884
|
+
content: encodeSignedDeviceIdentity(authState.creds.account, true),
|
|
557
885
|
});
|
|
558
|
-
logger.debug({ jid },
|
|
886
|
+
logger.debug({ jid: jid }, "adding device identity");
|
|
559
887
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
888
|
+
const contactTcTokenData =
|
|
889
|
+
!isGroup && !isRetryResend && !isStatus
|
|
890
|
+
? await authState.keys.get("tctoken", [destinationJid])
|
|
891
|
+
: {};
|
|
892
|
+
const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
|
|
893
|
+
if (tcTokenBuffer) {
|
|
894
|
+
stanza.content.push({
|
|
895
|
+
tag: "tctoken",
|
|
896
|
+
attrs: {},
|
|
897
|
+
content: tcTokenBuffer,
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
|
|
901
|
+
stanza.content.push({ tag: "multicast", attrs: {} });
|
|
902
|
+
}
|
|
903
|
+
if (pollMessage || messages.eventMessage) {
|
|
904
|
+
stanza.content.push({
|
|
905
|
+
tag: "meta",
|
|
906
|
+
attrs: messages.eventMessage
|
|
907
|
+
? { event_type: "creation" }
|
|
908
|
+
: isNewsletter
|
|
909
|
+
? {
|
|
910
|
+
polltype: "creation",
|
|
911
|
+
contenttype: pollMessage?.pollContentType === 2 ? "image" : "text",
|
|
912
|
+
}
|
|
913
|
+
: { polltype: "creation" },
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
if (!isNewsletter && buttonType) {
|
|
917
|
+
const buttonsNode = getButtonArgs(messages);
|
|
918
|
+
const filteredButtons = getBinaryFilteredButtons(
|
|
919
|
+
additionalNodes ? additionalNodes : []
|
|
920
|
+
);
|
|
921
|
+
if (filteredButtons) {
|
|
922
|
+
stanza.content.push(...additionalNodes);
|
|
923
|
+
didPushAdditional = true;
|
|
924
|
+
} else {
|
|
925
|
+
stanza.content.push(buttonsNode);
|
|
567
926
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
927
|
+
}
|
|
928
|
+
if (AI && isPrivate) {
|
|
929
|
+
const botNode = { tag: "bot", attrs: { biz_bot: "1" } };
|
|
930
|
+
const filteredBizBot = getBinaryFilteredBizBot(
|
|
931
|
+
additionalNodes ? additionalNodes : []
|
|
932
|
+
);
|
|
571
933
|
if (filteredBizBot) {
|
|
572
|
-
stanza.content.push(...additionalNodes)
|
|
573
|
-
didPushAdditional = true
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
else {
|
|
577
|
-
stanza.content.push(botNode)
|
|
934
|
+
stanza.content.push(...additionalNodes);
|
|
935
|
+
didPushAdditional = true;
|
|
936
|
+
} else {
|
|
937
|
+
stanza.content.push(botNode);
|
|
578
938
|
}
|
|
579
939
|
}
|
|
580
|
-
|
|
581
|
-
if(!isNewsletter && buttonType && !isStatus) {
|
|
582
|
-
const content = WABinary_1.getAdditionalNode(buttonType)
|
|
583
|
-
const filteredNode = WABinary_1.getBinaryNodeFilter(additionalNodes)
|
|
584
|
-
|
|
585
|
-
if (filteredNode) {
|
|
586
|
-
didPushAdditional = true
|
|
587
|
-
stanza.content.push(...additionalNodes)
|
|
588
|
-
}
|
|
589
|
-
else {
|
|
590
|
-
stanza.content.push(...content)
|
|
591
|
-
}
|
|
592
|
-
logger.debug({ jid }, 'adding business node')
|
|
593
|
-
}
|
|
594
|
-
|
|
595
940
|
if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
|
|
596
941
|
stanza.content.push(...additionalNodes);
|
|
597
942
|
}
|
|
598
|
-
|
|
599
|
-
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
943
|
+
logger.debug({ msgId: msgId }, `sending message to ${participants.length} devices`);
|
|
600
944
|
await sendNode(stanza);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
key: {
|
|
607
|
-
remoteJid: jid,
|
|
608
|
-
fromMe: true,
|
|
609
|
-
id: msgId
|
|
610
|
-
},
|
|
611
|
-
message: message,
|
|
612
|
-
messageTimestamp: Utils_1.unixTimestampSeconds(new Date()),
|
|
613
|
-
messageStubParameters: [],
|
|
614
|
-
participant: WABinary_1.isJidGroup(jid) || WABinary_1.isJidStatusBroadcast(jid) ? meId : undefined,
|
|
615
|
-
status: Types_1.WAMessageStatus.PENDING
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON)
|
|
619
|
-
// return msgId;
|
|
945
|
+
if (messageRetryManager && !participant) {
|
|
946
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
947
|
+
}
|
|
948
|
+
}, meId);
|
|
949
|
+
return msgId;
|
|
620
950
|
};
|
|
621
951
|
const getTypeMessage = (msg) => {
|
|
622
|
-
|
|
623
|
-
if (
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
else {
|
|
630
|
-
return
|
|
952
|
+
const message = normalizeMessageContent(msg);
|
|
953
|
+
if (
|
|
954
|
+
message.pollCreationMessage ||
|
|
955
|
+
message.pollCreationMessageV2 ||
|
|
956
|
+
message.pollCreationMessageV3
|
|
957
|
+
) {
|
|
958
|
+
return "poll";
|
|
959
|
+
} else if (message.reactionMessage) {
|
|
960
|
+
return "reaction";
|
|
961
|
+
} else if (message.eventMessage) {
|
|
962
|
+
return "event";
|
|
963
|
+
} else if (getMediaType(message)) {
|
|
964
|
+
return "media";
|
|
965
|
+
} else {
|
|
966
|
+
return "text";
|
|
631
967
|
}
|
|
632
|
-
}
|
|
633
|
-
|
|
968
|
+
};
|
|
634
969
|
const getMediaType = (message) => {
|
|
635
970
|
if (message.imageMessage) {
|
|
636
|
-
return
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
|
|
971
|
+
return "image";
|
|
972
|
+
} else if (message.stickerMessage) {
|
|
973
|
+
return message.stickerMessage.isLottie
|
|
974
|
+
? "1p_sticker"
|
|
975
|
+
: message.stickerMessage.isAvatar
|
|
976
|
+
? "avatar_sticker"
|
|
977
|
+
: "sticker";
|
|
978
|
+
} else if (message.videoMessage) {
|
|
979
|
+
return message.videoMessage.gifPlayback ? "gif" : "video";
|
|
980
|
+
} else if (message.audioMessage) {
|
|
981
|
+
return message.audioMessage.ptt ? "ptt" : "audio";
|
|
982
|
+
} else if (message.ptvMessage) {
|
|
983
|
+
return "ptv";
|
|
984
|
+
} else if (message.albumMessage) {
|
|
985
|
+
return "collection";
|
|
986
|
+
} else if (message.contactMessage) {
|
|
987
|
+
return "vcard";
|
|
988
|
+
} else if (message.documentMessage) {
|
|
989
|
+
return "document";
|
|
990
|
+
} else if (message.stickerPackMessage) {
|
|
991
|
+
return "sticker_pack";
|
|
992
|
+
} else if (message.contactsArrayMessage) {
|
|
993
|
+
return "contact_array";
|
|
994
|
+
} else if (message.locationMessage) {
|
|
995
|
+
return "location";
|
|
996
|
+
} else if (message.liveLocationMessage) {
|
|
997
|
+
return "livelocation";
|
|
998
|
+
} else if (message.listMessage) {
|
|
999
|
+
return "list";
|
|
1000
|
+
} else if (message.listResponseMessage) {
|
|
1001
|
+
return "list_response";
|
|
1002
|
+
} else if (message.buttonsResponseMessage) {
|
|
1003
|
+
return "buttons_response";
|
|
1004
|
+
} else if (message.orderMessage) {
|
|
1005
|
+
return "order";
|
|
1006
|
+
} else if (message.productMessage) {
|
|
1007
|
+
return "product";
|
|
1008
|
+
} else if (message.interactiveResponseMessage) {
|
|
1009
|
+
return "native_flow_response";
|
|
1010
|
+
} else if (/https:\/\/wa\.me\/c\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
1011
|
+
return "cataloglink";
|
|
1012
|
+
} else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
1013
|
+
return "productlink";
|
|
1014
|
+
} else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
|
|
1015
|
+
return "url";
|
|
646
1016
|
}
|
|
647
|
-
|
|
648
|
-
return 'document'
|
|
649
|
-
}
|
|
650
|
-
else if (message.contactsArrayMessage) {
|
|
651
|
-
return 'contact_array'
|
|
652
|
-
}
|
|
653
|
-
else if (message.liveLocationMessage) {
|
|
654
|
-
return 'livelocation'
|
|
655
|
-
}
|
|
656
|
-
else if (message.stickerMessage) {
|
|
657
|
-
return 'sticker'
|
|
658
|
-
}
|
|
659
|
-
else if (message.listMessage) {
|
|
660
|
-
return 'list'
|
|
661
|
-
}
|
|
662
|
-
else if (message.listResponseMessage) {
|
|
663
|
-
return 'list_response'
|
|
664
|
-
}
|
|
665
|
-
else if (message.buttonsResponseMessage) {
|
|
666
|
-
return 'buttons_response'
|
|
667
|
-
}
|
|
668
|
-
else if (message.orderMessage) {
|
|
669
|
-
return 'order'
|
|
670
|
-
}
|
|
671
|
-
else if (message.productMessage) {
|
|
672
|
-
return 'product'
|
|
673
|
-
}
|
|
674
|
-
else if (message.interactiveResponseMessage) {
|
|
675
|
-
return 'native_flow_response'
|
|
676
|
-
}
|
|
677
|
-
else if (message.groupInviteMessage) {
|
|
678
|
-
return 'url'
|
|
679
|
-
}
|
|
680
|
-
else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
681
|
-
return 'productlink'
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
1017
|
+
};
|
|
685
1018
|
const getButtonType = (message) => {
|
|
686
1019
|
if (message.listMessage) {
|
|
687
|
-
return
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_and_pay') {
|
|
693
|
-
return 'review_and_pay'
|
|
694
|
-
}
|
|
695
|
-
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'review_order') {
|
|
696
|
-
return 'review_order'
|
|
697
|
-
}
|
|
698
|
-
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_info') {
|
|
699
|
-
return 'payment_info'
|
|
700
|
-
}
|
|
701
|
-
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_status') {
|
|
702
|
-
return 'payment_status'
|
|
1020
|
+
return "list";
|
|
1021
|
+
} else if (message.buttonsMessage) {
|
|
1022
|
+
return "buttons";
|
|
1023
|
+
} else if (message.interactiveMessage?.nativeFlowMessage) {
|
|
1024
|
+
return "native_flow";
|
|
703
1025
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
1026
|
+
};
|
|
1027
|
+
const getButtonArgs = (message) => {
|
|
1028
|
+
const nativeFlow = message.interactiveMessage?.nativeFlowMessage;
|
|
1029
|
+
const firstButtonName = nativeFlow?.buttons?.[0]?.name;
|
|
1030
|
+
const nativeFlowSpecials = [
|
|
1031
|
+
"mpm",
|
|
1032
|
+
"cta_catalog",
|
|
1033
|
+
"send_location",
|
|
1034
|
+
"call_permission_request",
|
|
1035
|
+
"wa_payment_transaction_details",
|
|
1036
|
+
"automated_greeting_message_view_catalog",
|
|
1037
|
+
];
|
|
1038
|
+
if (
|
|
1039
|
+
nativeFlow &&
|
|
1040
|
+
(firstButtonName === "review_and_pay" || firstButtonName === "payment_info")
|
|
1041
|
+
) {
|
|
1042
|
+
return {
|
|
1043
|
+
tag: "biz",
|
|
1044
|
+
attrs: {
|
|
1045
|
+
native_flow_name:
|
|
1046
|
+
firstButtonName === "review_and_pay" ? "order_details" : firstButtonName,
|
|
1047
|
+
},
|
|
1048
|
+
};
|
|
1049
|
+
} else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
|
|
1050
|
+
return {
|
|
1051
|
+
tag: "biz",
|
|
1052
|
+
attrs: {
|
|
1053
|
+
actual_actors: "2",
|
|
1054
|
+
host_storage: "2",
|
|
1055
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1056
|
+
},
|
|
1057
|
+
content: [
|
|
1058
|
+
{
|
|
1059
|
+
tag: "interactive",
|
|
1060
|
+
attrs: { type: "native_flow", v: "1" },
|
|
1061
|
+
content: [{ tag: "native_flow", attrs: { v: "2", name: firstButtonName } }],
|
|
1062
|
+
},
|
|
1063
|
+
{ tag: "quality_control", attrs: { source_type: "third_party" } },
|
|
1064
|
+
],
|
|
1065
|
+
};
|
|
1066
|
+
} else if (nativeFlow || message.buttonsMessage) {
|
|
1067
|
+
return {
|
|
1068
|
+
tag: "biz",
|
|
1069
|
+
attrs: {
|
|
1070
|
+
actual_actors: "2",
|
|
1071
|
+
host_storage: "2",
|
|
1072
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1073
|
+
},
|
|
1074
|
+
content: [
|
|
1075
|
+
{
|
|
1076
|
+
tag: "interactive",
|
|
1077
|
+
attrs: { type: "native_flow", v: "1" },
|
|
1078
|
+
content: [{ tag: "native_flow", attrs: { v: "9", name: "mixed" } }],
|
|
1079
|
+
},
|
|
1080
|
+
{ tag: "quality_control", attrs: { source_type: "third_party" } },
|
|
1081
|
+
],
|
|
1082
|
+
};
|
|
1083
|
+
} else if (message.listMessage) {
|
|
1084
|
+
return {
|
|
1085
|
+
tag: "biz",
|
|
1086
|
+
attrs: {
|
|
1087
|
+
actual_actors: "2",
|
|
1088
|
+
host_storage: "2",
|
|
1089
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1090
|
+
},
|
|
1091
|
+
content: [
|
|
1092
|
+
{ tag: "list", attrs: { v: "2", type: "product_list" } },
|
|
1093
|
+
{ tag: "quality_control", attrs: { source_type: "third_party" } },
|
|
1094
|
+
],
|
|
1095
|
+
};
|
|
1096
|
+
} else {
|
|
1097
|
+
return {
|
|
1098
|
+
tag: "biz",
|
|
1099
|
+
attrs: {
|
|
1100
|
+
actual_actors: "2",
|
|
1101
|
+
host_storage: "2",
|
|
1102
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1103
|
+
},
|
|
1104
|
+
};
|
|
712
1105
|
}
|
|
713
|
-
}
|
|
1106
|
+
};
|
|
714
1107
|
const getPrivacyTokens = async (jids) => {
|
|
715
|
-
const t =
|
|
1108
|
+
const t = unixTimestampSeconds().toString();
|
|
716
1109
|
const result = await query({
|
|
717
|
-
tag:
|
|
718
|
-
attrs: {
|
|
719
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
720
|
-
type: 'set',
|
|
721
|
-
xmlns: 'privacy'
|
|
722
|
-
},
|
|
1110
|
+
tag: "iq",
|
|
1111
|
+
attrs: { to: S_WHATSAPP_NET, type: "set", xmlns: "privacy" },
|
|
723
1112
|
content: [
|
|
724
1113
|
{
|
|
725
|
-
tag:
|
|
1114
|
+
tag: "tokens",
|
|
726
1115
|
attrs: {},
|
|
727
|
-
content: jids.map(jid => ({
|
|
728
|
-
tag:
|
|
1116
|
+
content: jids.map((jid) => ({
|
|
1117
|
+
tag: "token",
|
|
729
1118
|
attrs: {
|
|
730
|
-
jid:
|
|
731
|
-
t,
|
|
732
|
-
type:
|
|
733
|
-
}
|
|
734
|
-
}))
|
|
735
|
-
}
|
|
736
|
-
]
|
|
1119
|
+
jid: jidNormalizedUser(jid),
|
|
1120
|
+
t: t,
|
|
1121
|
+
type: "trusted_contact",
|
|
1122
|
+
},
|
|
1123
|
+
})),
|
|
1124
|
+
},
|
|
1125
|
+
],
|
|
737
1126
|
});
|
|
738
1127
|
return result;
|
|
739
|
-
}
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
1128
|
+
};
|
|
1129
|
+
const getEphemeralGroup = (jid) => {
|
|
1130
|
+
if (!isJidGroup(jid)) throw new TypeError("Jid should originate from a group!");
|
|
1131
|
+
return groupQuery(jid, "get", [{ tag: "query", attrs: { request: "interactive" } }])
|
|
1132
|
+
.then((groups) => getBinaryNodeChild(groups, "group"))
|
|
1133
|
+
.then((metadata) => getBinaryNodeChild(metadata, "ephemeral")?.attrs?.expiration || 0);
|
|
1134
|
+
};
|
|
1135
|
+
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
1136
|
+
const waitForMsgMediaUpdate = bindWaitForEvent(ev, "messages.media-update");
|
|
743
1137
|
return {
|
|
744
|
-
...
|
|
745
|
-
getPrivacyTokens,
|
|
746
|
-
assertSessions,
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
readMessages,
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
1138
|
+
...conn,
|
|
1139
|
+
getPrivacyTokens: getPrivacyTokens,
|
|
1140
|
+
assertSessions: assertSessions,
|
|
1141
|
+
profilePictureUrl: profilePictureUrl,
|
|
1142
|
+
relayMessage: relayMessage,
|
|
1143
|
+
sendReceipt: sendReceipt,
|
|
1144
|
+
sendReceipts: sendReceipts,
|
|
1145
|
+
readMessages: readMessages,
|
|
1146
|
+
getUSyncDevices: getUSyncDevices,
|
|
1147
|
+
refreshMediaConn: refreshMediaConn,
|
|
1148
|
+
waUploadToServer: waUploadToServer,
|
|
1149
|
+
getEphemeralGroup: getEphemeralGroup,
|
|
1150
|
+
fetchPrivacySettings: fetchPrivacySettings,
|
|
1151
|
+
messageRetryManager: messageRetryManager,
|
|
1152
|
+
createParticipantNodes: createParticipantNodes,
|
|
1153
|
+
sendPeerDataOperationMessage: sendPeerDataOperationMessage,
|
|
1154
|
+
updateMemberLabel: updateMemberLabel,
|
|
758
1155
|
updateMediaMessage: async (message) => {
|
|
759
|
-
const content =
|
|
1156
|
+
const content = assertMediaContent(message.message);
|
|
760
1157
|
const mediaKey = content.mediaKey;
|
|
761
1158
|
const meId = authState.creds.me.id;
|
|
762
|
-
const node =
|
|
1159
|
+
const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
|
|
763
1160
|
let error = undefined;
|
|
764
1161
|
await Promise.all([
|
|
765
1162
|
sendNode(node),
|
|
766
|
-
waitForMsgMediaUpdate(update => {
|
|
767
|
-
const result = update.find(c => c.key.id === message.key.id);
|
|
1163
|
+
waitForMsgMediaUpdate(async (update) => {
|
|
1164
|
+
const result = update.find((c) => c.key.id === message.key.id);
|
|
768
1165
|
if (result) {
|
|
769
1166
|
if (result.error) {
|
|
770
1167
|
error = result.error;
|
|
771
|
-
}
|
|
772
|
-
else {
|
|
1168
|
+
} else {
|
|
773
1169
|
try {
|
|
774
|
-
const media =
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1170
|
+
const media = await decryptMediaRetryData(
|
|
1171
|
+
result.media,
|
|
1172
|
+
mediaKey,
|
|
1173
|
+
result.key.id
|
|
1174
|
+
);
|
|
1175
|
+
if (
|
|
1176
|
+
media.result !== proto.MediaRetryNotification.ResultType.SUCCESS
|
|
1177
|
+
) {
|
|
1178
|
+
const resultStr =
|
|
1179
|
+
proto.MediaRetryNotification.ResultType[media.result];
|
|
1180
|
+
throw new Boom(
|
|
1181
|
+
`Media re-upload failed by device (${resultStr})`,
|
|
1182
|
+
{
|
|
1183
|
+
data: media,
|
|
1184
|
+
statusCode:
|
|
1185
|
+
getStatusCodeForMediaRetry(media.result) || 404,
|
|
1186
|
+
}
|
|
1187
|
+
);
|
|
778
1188
|
}
|
|
779
1189
|
content.directPath = media.directPath;
|
|
780
|
-
content.url =
|
|
781
|
-
logger.debug(
|
|
782
|
-
|
|
783
|
-
|
|
1190
|
+
content.url = getUrlFromDirectPath(content.directPath);
|
|
1191
|
+
logger.debug(
|
|
1192
|
+
{ directPath: media.directPath, key: result.key },
|
|
1193
|
+
"media update successful"
|
|
1194
|
+
);
|
|
1195
|
+
} catch (err) {
|
|
784
1196
|
error = err;
|
|
785
1197
|
}
|
|
786
1198
|
}
|
|
787
1199
|
return true;
|
|
788
1200
|
}
|
|
789
|
-
})
|
|
1201
|
+
}),
|
|
790
1202
|
]);
|
|
791
1203
|
if (error) {
|
|
792
1204
|
throw error;
|
|
793
1205
|
}
|
|
794
|
-
ev.emit(
|
|
795
|
-
{
|
|
796
|
-
key: message.key,
|
|
797
|
-
update: {
|
|
798
|
-
message: message.message
|
|
799
|
-
}
|
|
800
|
-
}
|
|
1206
|
+
ev.emit("messages.update", [
|
|
1207
|
+
{ key: message.key, update: { message: message.message } },
|
|
801
1208
|
]);
|
|
802
1209
|
return message;
|
|
803
1210
|
},
|
|
1211
|
+
sendStatusMentions: async (content, jids = []) => {
|
|
1212
|
+
const userJid = jidNormalizedUser(authState.creds.me.id);
|
|
1213
|
+
let allUsers = new Set();
|
|
1214
|
+
allUsers.add(userJid);
|
|
1215
|
+
for (const id of jids) {
|
|
1216
|
+
const isGroup = isJidGroup(id);
|
|
1217
|
+
const isPrivate = isPnUser(id);
|
|
1218
|
+
if (isGroup) {
|
|
1219
|
+
try {
|
|
1220
|
+
const metadata =
|
|
1221
|
+
(await cachedGroupMetadata(id)) || (await groupMetadata(id));
|
|
1222
|
+
const participants = metadata.participants.map((p) =>
|
|
1223
|
+
jidNormalizedUser(p.id)
|
|
1224
|
+
);
|
|
1225
|
+
participants.forEach((jid) => allUsers.add(jid));
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
logger.error(`Error getting metadata for group ${id}: ${error}`);
|
|
1228
|
+
}
|
|
1229
|
+
} else if (isPrivate) {
|
|
1230
|
+
allUsers.add(jidNormalizedUser(id));
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
const uniqueUsers = Array.from(allUsers);
|
|
1234
|
+
const getRandomHexColor = () =>
|
|
1235
|
+
"#" +
|
|
1236
|
+
Math.floor(Math.random() * 16777215)
|
|
1237
|
+
.toString(16)
|
|
1238
|
+
.padStart(6, "0");
|
|
1239
|
+
const isMedia = content.image || content.video || content.audio;
|
|
1240
|
+
const isAudio = !!content.audio;
|
|
1241
|
+
const messageContent = { ...content };
|
|
1242
|
+
if (isMedia && !isAudio) {
|
|
1243
|
+
if (messageContent.text) {
|
|
1244
|
+
messageContent.caption = messageContent.text;
|
|
1245
|
+
delete messageContent.text;
|
|
1246
|
+
}
|
|
1247
|
+
delete messageContent.ptt;
|
|
1248
|
+
delete messageContent.font;
|
|
1249
|
+
delete messageContent.backgroundColor;
|
|
1250
|
+
delete messageContent.textColor;
|
|
1251
|
+
}
|
|
1252
|
+
if (isAudio) {
|
|
1253
|
+
delete messageContent.text;
|
|
1254
|
+
delete messageContent.caption;
|
|
1255
|
+
delete messageContent.font;
|
|
1256
|
+
delete messageContent.textColor;
|
|
1257
|
+
}
|
|
1258
|
+
const font = !isMedia ? content.font || Math.floor(Math.random() * 9) : undefined;
|
|
1259
|
+
const textColor = !isMedia ? content.textColor || getRandomHexColor() : undefined;
|
|
1260
|
+
const backgroundColor =
|
|
1261
|
+
!isMedia || isAudio ? content.backgroundColor || getRandomHexColor() : undefined;
|
|
1262
|
+
const ptt = isAudio
|
|
1263
|
+
? typeof content.ptt === "boolean"
|
|
1264
|
+
? content.ptt
|
|
1265
|
+
: true
|
|
1266
|
+
: undefined;
|
|
1267
|
+
let msg;
|
|
1268
|
+
let mediaHandle;
|
|
1269
|
+
try {
|
|
1270
|
+
msg = await generateWAMessage(STORIES_JID, messageContent, {
|
|
1271
|
+
logger: logger,
|
|
1272
|
+
userJid: userJid,
|
|
1273
|
+
getUrlInfo: (text) =>
|
|
1274
|
+
getUrlInfo(text, {
|
|
1275
|
+
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1276
|
+
fetchOpts: { timeout: 3e3, ...(httpRequestOptions || {}) },
|
|
1277
|
+
logger: logger,
|
|
1278
|
+
uploadImage: generateHighQualityLinkPreview
|
|
1279
|
+
? waUploadToServer
|
|
1280
|
+
: undefined,
|
|
1281
|
+
}),
|
|
1282
|
+
upload: async (encFilePath, opts) => {
|
|
1283
|
+
const up = await waUploadToServer(encFilePath, { ...opts });
|
|
1284
|
+
mediaHandle = up.handle;
|
|
1285
|
+
return up;
|
|
1286
|
+
},
|
|
1287
|
+
mediaCache: config.mediaCache,
|
|
1288
|
+
options: config.options,
|
|
1289
|
+
font: font,
|
|
1290
|
+
textColor: textColor,
|
|
1291
|
+
backgroundColor: backgroundColor,
|
|
1292
|
+
ptt: ptt,
|
|
1293
|
+
});
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
logger.error(`Error generating message: ${error}`);
|
|
1296
|
+
throw error;
|
|
1297
|
+
}
|
|
1298
|
+
await relayMessage(STORIES_JID, msg.message, {
|
|
1299
|
+
messageId: msg.key.id,
|
|
1300
|
+
statusJidList: uniqueUsers,
|
|
1301
|
+
additionalNodes: [
|
|
1302
|
+
{
|
|
1303
|
+
tag: "meta",
|
|
1304
|
+
attrs: {},
|
|
1305
|
+
content: [
|
|
1306
|
+
{
|
|
1307
|
+
tag: "mentioned_users",
|
|
1308
|
+
attrs: {},
|
|
1309
|
+
content: jids.map((jid) => ({
|
|
1310
|
+
tag: "to",
|
|
1311
|
+
attrs: { jid: jidNormalizedUser(jid) },
|
|
1312
|
+
})),
|
|
1313
|
+
},
|
|
1314
|
+
],
|
|
1315
|
+
},
|
|
1316
|
+
],
|
|
1317
|
+
});
|
|
1318
|
+
for (const id of jids) {
|
|
1319
|
+
try {
|
|
1320
|
+
const normalizedId = jidNormalizedUser(id);
|
|
1321
|
+
const isPrivate = isPnUser(normalizedId);
|
|
1322
|
+
const type = isPrivate ? "statusMentionMessage" : "groupStatusMentionMessage";
|
|
1323
|
+
const protocolMessage = {
|
|
1324
|
+
[type]: {
|
|
1325
|
+
message: { protocolMessage: { key: msg.key, type: 25 } },
|
|
1326
|
+
},
|
|
1327
|
+
messageContextInfo: { messageSecret: randomBytes(32) },
|
|
1328
|
+
};
|
|
1329
|
+
const statusMsg = await generateWAMessageFromContent(
|
|
1330
|
+
normalizedId,
|
|
1331
|
+
protocolMessage,
|
|
1332
|
+
{}
|
|
1333
|
+
);
|
|
1334
|
+
await relayMessage(normalizedId, statusMsg.message, {
|
|
1335
|
+
additionalNodes: [
|
|
1336
|
+
{
|
|
1337
|
+
tag: "meta",
|
|
1338
|
+
attrs: isPrivate
|
|
1339
|
+
? { is_status_mention: "true" }
|
|
1340
|
+
: { is_group_status_mention: "true" },
|
|
1341
|
+
},
|
|
1342
|
+
],
|
|
1343
|
+
});
|
|
1344
|
+
await delay(2e3);
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
logger.error(`Error sending to ${id}: ${error}`);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
return msg;
|
|
1350
|
+
},
|
|
804
1351
|
sendMessage: async (jid, content, options = {}) => {
|
|
805
1352
|
const userJid = authState.creds.me.id;
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
const { disappearingMessagesInChat } = content
|
|
813
|
-
|
|
814
|
-
const value = typeof disappearingMessagesInChat === 'boolean' ?
|
|
815
|
-
(disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
|
|
816
|
-
disappearingMessagesInChat
|
|
817
|
-
|
|
818
|
-
await groupToggleEphemeral(jid, value)
|
|
1353
|
+
const additionalAttributes = {};
|
|
1354
|
+
if (!options.ephemeralExpiration) {
|
|
1355
|
+
if (isJidGroup(jid)) {
|
|
1356
|
+
const expiration = await getEphemeralGroup(jid);
|
|
1357
|
+
options.ephemeralExpiration = expiration;
|
|
1358
|
+
}
|
|
819
1359
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
...getParticipantAttr()
|
|
840
|
-
});
|
|
841
|
-
|
|
842
|
-
case 'INTERACTIVE':
|
|
843
|
-
const interactiveContent = await rahmi.handleInteractive(content, jid, quoted);
|
|
844
|
-
const interactiveMsg = await Utils_1.generateWAMessageFromContent(jid, interactiveContent, { quoted });
|
|
845
|
-
return await relayMessage(jid, interactiveMsg.message, {
|
|
846
|
-
messageId: interactiveMsg.key.id,
|
|
847
|
-
...getParticipantAttr()
|
|
848
|
-
});
|
|
849
|
-
case 'ALBUM':
|
|
850
|
-
return await rahmi.handleAlbum(content, jid, quoted)
|
|
851
|
-
case 'EVENT':
|
|
852
|
-
return await rahmi.handleEvent(content, jid, quoted)
|
|
853
|
-
case 'POLL_RESULT':
|
|
854
|
-
return await rahmi.handlePollResult(content, jid, quoted)
|
|
855
|
-
case 'GROUP_STORY':
|
|
856
|
-
return await rahmi.handleGroupStory(content, jid, quoted)
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
const fullMsg = await Utils_1.generateWAMessage(jid, content, {
|
|
860
|
-
logger,
|
|
861
|
-
userJid,
|
|
862
|
-
quoted,
|
|
863
|
-
getUrlInfo: text => link_preview_1.getUrlInfo(text, {
|
|
864
|
-
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
865
|
-
fetchOpts: {
|
|
866
|
-
timeout: 3000,
|
|
867
|
-
...axiosOptions || {}
|
|
1360
|
+
if (
|
|
1361
|
+
typeof content === "object" &&
|
|
1362
|
+
"disappearingMessagesInChat" in content &&
|
|
1363
|
+
typeof content["disappearingMessagesInChat"] !== "undefined" &&
|
|
1364
|
+
isJidGroup(jid)
|
|
1365
|
+
) {
|
|
1366
|
+
const { disappearingMessagesInChat: disappearingMessagesInChat } = content;
|
|
1367
|
+
const value =
|
|
1368
|
+
typeof disappearingMessagesInChat === "boolean"
|
|
1369
|
+
? disappearingMessagesInChat
|
|
1370
|
+
? WA_DEFAULT_EPHEMERAL
|
|
1371
|
+
: 0
|
|
1372
|
+
: disappearingMessagesInChat;
|
|
1373
|
+
await groupToggleEphemeral(jid, value);
|
|
1374
|
+
} else if (typeof content === "object" && "album" in content && content.album) {
|
|
1375
|
+
const albumMsg = await prepareAlbumMessageContent(jid, content.album, {
|
|
1376
|
+
conn: {
|
|
1377
|
+
relayMessage: relayMessage,
|
|
1378
|
+
waUploadToServer: waUploadToServer,
|
|
868
1379
|
},
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
})
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1380
|
+
userJid: userJid,
|
|
1381
|
+
...options,
|
|
1382
|
+
});
|
|
1383
|
+
for (const media of albumMsg) {
|
|
1384
|
+
await delay(options.delay || 500);
|
|
1385
|
+
await relayMessage(jid, media.message, {
|
|
1386
|
+
messageId: media.key.id,
|
|
1387
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1388
|
+
additionalAttributes: additionalAttributes,
|
|
1389
|
+
statusJidList: options.statusJidList,
|
|
1390
|
+
additionalNodes: options.additionalNodes,
|
|
1391
|
+
AI: options.ai,
|
|
876
1392
|
});
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1393
|
+
}
|
|
1394
|
+
return albumMsg;
|
|
1395
|
+
} else {
|
|
1396
|
+
let mediaHandle;
|
|
1397
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
1398
|
+
logger: logger,
|
|
1399
|
+
userJid: userJid,
|
|
1400
|
+
getUrlInfo: (text) =>
|
|
1401
|
+
getUrlInfo(text, {
|
|
1402
|
+
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1403
|
+
fetchOpts: { timeout: 3e3, ...(httpRequestOptions || {}) },
|
|
1404
|
+
logger: logger,
|
|
1405
|
+
uploadImage: generateHighQualityLinkPreview
|
|
1406
|
+
? waUploadToServer
|
|
1407
|
+
: undefined,
|
|
1408
|
+
}),
|
|
1409
|
+
getProfilePicUrl: profilePictureUrl,
|
|
1410
|
+
getCallLink: createCallLink,
|
|
1411
|
+
upload: async (encFilePath, opts) => {
|
|
1412
|
+
const up = await waUploadToServer(encFilePath, {
|
|
1413
|
+
...opts,
|
|
1414
|
+
newsletter: isJidNewsletter(jid),
|
|
1415
|
+
});
|
|
1416
|
+
mediaHandle = up.handle;
|
|
1417
|
+
return up;
|
|
1418
|
+
},
|
|
1419
|
+
mediaCache: config.mediaCache,
|
|
1420
|
+
options: config.options,
|
|
1421
|
+
messageId: generateMessageID(userJid),
|
|
1422
|
+
...options,
|
|
902
1423
|
});
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1424
|
+
const isPin = "pin" in content && !!content.pin;
|
|
1425
|
+
const isEdit = "edit" in content && !!content.edit;
|
|
1426
|
+
const isDelete = "delete" in content && !!content.delete;
|
|
1427
|
+
const isKeep = "keep" in content && !!content.keep && content.keep?.type === 2;
|
|
1428
|
+
if (isDelete || isKeep) {
|
|
1429
|
+
if (
|
|
1430
|
+
(isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) ||
|
|
1431
|
+
isJidNewsletter(jid)
|
|
1432
|
+
) {
|
|
1433
|
+
additionalAttributes.edit = "8";
|
|
1434
|
+
} else {
|
|
1435
|
+
additionalAttributes.edit = "7";
|
|
1436
|
+
}
|
|
1437
|
+
} else if (isEdit) {
|
|
1438
|
+
additionalAttributes.edit = isJidNewsletter(jid) ? "3" : "1";
|
|
1439
|
+
} else if (isPin) {
|
|
1440
|
+
additionalAttributes.edit = "2";
|
|
1441
|
+
}
|
|
1442
|
+
if (mediaHandle) {
|
|
1443
|
+
additionalAttributes["media_id"] = mediaHandle;
|
|
1444
|
+
}
|
|
1445
|
+
if ("cachedGroupMetadata" in options) {
|
|
1446
|
+
console.warn(
|
|
1447
|
+
"cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config."
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
await relayMessage(jid, fullMsg.message, {
|
|
1451
|
+
messageId: fullMsg.key.id,
|
|
1452
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1453
|
+
additionalAttributes: additionalAttributes,
|
|
1454
|
+
statusJidList: options.statusJidList,
|
|
1455
|
+
additionalNodes: options.additionalNodes,
|
|
1456
|
+
AI: options.ai,
|
|
916
1457
|
});
|
|
1458
|
+
if (config.emitOwnEvents) {
|
|
1459
|
+
process.nextTick(async () => {
|
|
1460
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, "append"));
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
return fullMsg;
|
|
917
1464
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
}
|
|
921
|
-
}
|
|
1465
|
+
},
|
|
1466
|
+
};
|
|
922
1467
|
};
|
|
923
|
-
exports
|
|
1468
|
+
module.exports = { makeMessagesSocket: makeMessagesSocket };
|