amiudmodz 6.2.2 → 6.2.5
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/Defaults/index.d.ts +8 -0
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +26 -10
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +3 -3
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +21 -14
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/business.d.ts +19 -12
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/chats.d.ts +2 -5
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +29 -11
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +19 -12
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts +1 -4
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/index.d.ts +2 -277
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/index.js +30 -1
- package/lib/Socket/index.js.map +1 -1
- package/lib/Socket/messages-recv.d.ts +19 -12
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +117 -28
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +18 -11
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +362 -250
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/mex.d.ts +1 -1
- package/lib/Socket/mex.d.ts.map +1 -1
- package/lib/Socket/mex.js +4 -4
- package/lib/Socket/mex.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +6 -7
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +74 -26
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +7 -26
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +10 -0
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +2 -1
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +59 -10
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js +6 -0
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/Mex.d.ts +2 -0
- package/lib/Types/Mex.d.ts.map +1 -1
- package/lib/Types/Mex.js +2 -0
- package/lib/Types/Mex.js.map +1 -1
- package/lib/Types/Socket.d.ts +18 -0
- package/lib/Types/Socket.d.ts.map +1 -1
- package/lib/Types/State.d.ts +10 -0
- package/lib/Types/State.d.ts.map +1 -1
- package/lib/Types/State.js.map +1 -1
- package/lib/Types/index.d.ts +1 -1
- package/lib/Types/index.d.ts.map +1 -1
- package/lib/Types/index.js +1 -0
- package/lib/Types/index.js.map +1 -1
- package/lib/Utils/MessageBuilder.d.ts +11 -10
- package/lib/Utils/MessageBuilder.d.ts.map +1 -1
- package/lib/Utils/MessageBuilder.js +14 -3
- package/lib/Utils/MessageBuilder.js.map +1 -1
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +23 -8
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/browser-utils.js +4 -4
- package/lib/Utils/browser-utils.js.map +1 -1
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +9 -5
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +8 -5
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/index.d.ts +6 -1
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +6 -1
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/messages-media.d.ts +12 -18
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +163 -65
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts +26 -71
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +1198 -328
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/tc-token-utils.d.ts.map +1 -1
- package/lib/Utils/tc-token-utils.js +2 -3
- package/lib/Utils/tc-token-utils.js.map +1 -1
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -1
- package/lib/Utils/use-multi-file-auth-state.js +30 -1
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -1
- package/lib/Utils/use-sqlite-auth-state.js +12 -12
- package/lib/Utils/validate-connection.d.ts.map +1 -1
- package/lib/Utils/validate-connection.js +5 -11
- package/lib/Utils/validate-connection.js.map +1 -1
- package/lib/WABinary/constants.d.ts +8 -0
- package/lib/WABinary/constants.d.ts.map +1 -1
- package/lib/WABinary/constants.js +72 -0
- package/lib/WABinary/constants.js.map +1 -1
- package/lib/WABinary/generic-utils.d.ts +1 -0
- package/lib/WABinary/generic-utils.d.ts.map +1 -1
- package/lib/WABinary/generic-utils.js +100 -1
- package/lib/WABinary/generic-utils.js.map +1 -1
- package/lib/WABinary/jid-utils.d.ts.map +1 -1
- package/lib/WABinary/jid-utils.js +45 -6
- package/lib/WABinary/jid-utils.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
1
2
|
import NodeCache from '@cacheable/node-cache';
|
|
2
3
|
import { Boom } from '@hapi/boom';
|
|
3
4
|
import { proto } from '../../WAProto/index.js';
|
|
4
|
-
import { DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
5
|
-
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent,
|
|
5
|
+
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
|
+
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, shouldIncludeBizBinaryNode, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
|
|
6
7
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
7
8
|
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
|
|
8
9
|
import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/reporting-utils.js';
|
|
9
10
|
import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, resolveTcTokenJid, shouldSendNewTcToken, storeTcTokensFromIqResult } from '../Utils/tc-token-utils.js';
|
|
10
|
-
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
|
+
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinaryNode, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isJidNewsletter, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
12
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
12
13
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
13
14
|
export const makeMessagesSocket = (config) => {
|
|
@@ -49,7 +50,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
49
50
|
content: [{ tag: 'media_conn', attrs: {} }]
|
|
50
51
|
});
|
|
51
52
|
const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
|
|
52
|
-
// TODO: explore full length of data that whatsapp provides
|
|
53
53
|
const node = {
|
|
54
54
|
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
55
55
|
hostname: attrs.hostname,
|
|
@@ -125,7 +125,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
125
125
|
/** Bulk read messages. Keys can be from different chats & participants */
|
|
126
126
|
const readMessages = async (keys) => {
|
|
127
127
|
const privacySettings = await fetchPrivacySettings();
|
|
128
|
-
// based on privacy settings, we have to change the read type
|
|
129
128
|
const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self';
|
|
130
129
|
await sendReceipts(keys, readType);
|
|
131
130
|
};
|
|
@@ -192,16 +191,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
192
191
|
}
|
|
193
192
|
const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
|
|
194
193
|
for (const jid of toFetch) {
|
|
195
|
-
query.withUser(new USyncUser().withId(jid));
|
|
194
|
+
query.withUser(new USyncUser().withId(jid));
|
|
196
195
|
}
|
|
197
196
|
const result = await sock.executeUSyncQuery(query);
|
|
198
197
|
if (result) {
|
|
199
|
-
// TODO: LID MAP this stuff (lid protocol will now return lid with devices)
|
|
200
198
|
const lidResults = result.list.filter(a => !!a.lid);
|
|
201
199
|
if (lidResults.length > 0) {
|
|
202
200
|
logger.trace('Storing LID maps from device call');
|
|
203
201
|
await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
|
|
204
|
-
// Force-refresh sessions for newly mapped LIDs to align identity addressing
|
|
205
202
|
try {
|
|
206
203
|
const lids = lidResults.map(a => a.lid);
|
|
207
204
|
if (lids.length) {
|
|
@@ -218,10 +215,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
218
215
|
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
219
216
|
deviceMap[item.user]?.push(item);
|
|
220
217
|
}
|
|
221
|
-
// Process each user's devices as a group for bulk LID migration
|
|
222
218
|
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
223
219
|
const isLidUser = requestedLidUsers.has(user);
|
|
224
|
-
// Process all devices for this user
|
|
225
220
|
for (const item of userDevices) {
|
|
226
221
|
const finalJid = isLidUser
|
|
227
222
|
? jidEncode(user, item.server, item.device)
|
|
@@ -240,7 +235,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
240
235
|
}
|
|
241
236
|
await devicesMutex.mutex(async () => {
|
|
242
237
|
if (userDevicesCache.mset) {
|
|
243
|
-
// if the cache supports mset, we can set all devices in one go
|
|
244
238
|
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
245
239
|
}
|
|
246
240
|
else {
|
|
@@ -308,7 +302,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
308
302
|
jidsRequiringFetch.push(jid);
|
|
309
303
|
}
|
|
310
304
|
if (jidsRequiringFetch.length) {
|
|
311
|
-
// LID if mapped, otherwise original
|
|
312
305
|
const wireJids = [
|
|
313
306
|
...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
314
307
|
...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
|
|
@@ -340,7 +333,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
340
333
|
return didFetchNewSession;
|
|
341
334
|
};
|
|
342
335
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
343
|
-
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
344
336
|
if (!authState.creds.me?.id) {
|
|
345
337
|
throw new Boom('Not authenticated');
|
|
346
338
|
}
|
|
@@ -425,7 +417,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
425
417
|
}
|
|
426
418
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
427
419
|
};
|
|
428
|
-
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
420
|
+
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, addBizAttributes }) => {
|
|
429
421
|
const meId = assertMeId(authState.creds);
|
|
430
422
|
const meLid = authState.creds.me?.lid;
|
|
431
423
|
const isRetryResend = Boolean(participant?.jid);
|
|
@@ -473,9 +465,12 @@ export const makeMessagesSocket = (config) => {
|
|
|
473
465
|
if (isNewsletter) {
|
|
474
466
|
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
475
467
|
const bytes = encodeNewsletterMessage(patched);
|
|
468
|
+
if (additionalNodes && additionalNodes.length > 0) {
|
|
469
|
+
binaryNodeContent.push(...additionalNodes);
|
|
470
|
+
}
|
|
476
471
|
binaryNodeContent.push({
|
|
477
472
|
tag: 'plaintext',
|
|
478
|
-
attrs:
|
|
473
|
+
attrs: extraAttrs,
|
|
479
474
|
content: bytes
|
|
480
475
|
});
|
|
481
476
|
const stanza = {
|
|
@@ -493,25 +488,23 @@ export const makeMessagesSocket = (config) => {
|
|
|
493
488
|
return;
|
|
494
489
|
}
|
|
495
490
|
if (normalizeMessageContent(message)?.pinInChatMessage || normalizeMessageContent(message)?.reactionMessage) {
|
|
496
|
-
extraAttrs['decrypt-fail'] = 'hide';
|
|
491
|
+
extraAttrs['decrypt-fail'] = 'hide';
|
|
497
492
|
}
|
|
498
493
|
if (isGroupOrStatus && !isRetryResend) {
|
|
499
494
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
500
495
|
(async () => {
|
|
501
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
496
|
+
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
|
|
502
497
|
if (groupData && Array.isArray(groupData?.participants)) {
|
|
503
498
|
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
|
|
504
499
|
}
|
|
505
500
|
else if (!isStatus) {
|
|
506
|
-
groupData = await groupMetadata(jid);
|
|
501
|
+
groupData = await groupMetadata(jid);
|
|
507
502
|
}
|
|
508
503
|
return groupData;
|
|
509
504
|
})(),
|
|
510
505
|
(async () => {
|
|
511
506
|
if (!participant && !isStatus) {
|
|
512
|
-
|
|
513
|
-
// on participant change in group, we should do sender memory manipulation
|
|
514
|
-
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?
|
|
507
|
+
const result = await authState.keys.get('sender-key-memory', [jid]);
|
|
515
508
|
return result[jid] || {};
|
|
516
509
|
}
|
|
517
510
|
return {};
|
|
@@ -556,8 +549,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
556
549
|
!isHostedLidUser(deviceJid) &&
|
|
557
550
|
!isHostedPnUser(deviceJid) &&
|
|
558
551
|
device.device !== 99) {
|
|
559
|
-
//todo: revamp all this logic
|
|
560
|
-
// 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
|
|
561
552
|
senderKeyRecipients.push(deviceJid);
|
|
562
553
|
senderKeyMap[deviceJid] = true;
|
|
563
554
|
}
|
|
@@ -584,8 +575,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
584
575
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
585
576
|
}
|
|
586
577
|
else {
|
|
587
|
-
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
588
|
-
// TODO: investigate if this is true
|
|
589
578
|
let ownId = meId;
|
|
590
579
|
if (isLid && meLid) {
|
|
591
580
|
ownId = meLid;
|
|
@@ -606,7 +595,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
606
595
|
devices.push({
|
|
607
596
|
user,
|
|
608
597
|
device: 0,
|
|
609
|
-
jid: jidEncode(user, targetUserServer, 0)
|
|
598
|
+
jid: jidEncode(user, targetUserServer, 0)
|
|
610
599
|
});
|
|
611
600
|
if (user !== ownUser) {
|
|
612
601
|
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
@@ -618,13 +607,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
618
607
|
});
|
|
619
608
|
}
|
|
620
609
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
621
|
-
// Clear placeholders and enumerate actual devices
|
|
622
610
|
devices.length = 0;
|
|
623
|
-
// Use conversation-appropriate sender identity
|
|
624
611
|
const senderIdentity = isLid && meLid
|
|
625
612
|
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
626
613
|
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
627
|
-
// Enumerate devices for sender and target with consistent addressing
|
|
628
614
|
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
629
615
|
devices.push(...sessionDevices);
|
|
630
616
|
logger.debug({
|
|
@@ -644,7 +630,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
644
630
|
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
645
631
|
continue;
|
|
646
632
|
}
|
|
647
|
-
// Check if this is our device (could match either PN or LID user)
|
|
648
633
|
const isMe = user === mePnUser || user === meLidUser;
|
|
649
634
|
if (isMe) {
|
|
650
635
|
meRecipients.push(jid);
|
|
@@ -656,7 +641,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
656
641
|
}
|
|
657
642
|
await assertSessions(allRecipients);
|
|
658
643
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
659
|
-
// For own devices: use DSM if available (1:1 chats only)
|
|
660
644
|
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
661
645
|
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
662
646
|
]);
|
|
@@ -724,7 +708,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
724
708
|
if (additionalAttributes?.['category'] === 'peer') {
|
|
725
709
|
const peerNode = participants[0]?.content?.[0];
|
|
726
710
|
if (peerNode) {
|
|
727
|
-
binaryNodeContent.push(peerNode);
|
|
711
|
+
binaryNodeContent.push(peerNode);
|
|
728
712
|
}
|
|
729
713
|
}
|
|
730
714
|
else {
|
|
@@ -745,9 +729,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
745
729
|
},
|
|
746
730
|
content: binaryNodeContent
|
|
747
731
|
};
|
|
748
|
-
// if the participant to send to is explicitly specified (generally retry recp)
|
|
749
|
-
// ensure the message is only sent to that person
|
|
750
|
-
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
751
732
|
if (participant) {
|
|
752
733
|
if (isJidGroup(destinationJid)) {
|
|
753
734
|
stanza.attrs.to = destinationJid;
|
|
@@ -796,19 +777,15 @@ export const makeMessagesSocket = (config) => {
|
|
|
796
777
|
logger.warn({ jid, trace: error?.stack }, 'failed to attach reporting token');
|
|
797
778
|
}
|
|
798
779
|
}
|
|
799
|
-
// WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
|
|
800
780
|
const isPeerMessage = additionalAttributes?.['category'] === 'peer';
|
|
801
781
|
const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage;
|
|
802
|
-
// Resolve destination to LID for tctoken storage — matches Signal session key pattern
|
|
803
782
|
const tcTokenJid = is1on1Send ? await resolveTcTokenJid(destinationJid, getLIDForPN) : destinationJid;
|
|
804
783
|
const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {};
|
|
805
784
|
const existingTokenEntry = contactTcTokenData[tcTokenJid];
|
|
806
785
|
let tcTokenBuffer = existingTokenEntry?.token;
|
|
807
|
-
// Treat expired tokens the same as missing — clear from cache
|
|
808
786
|
if (tcTokenBuffer?.length && isTcTokenExpired(existingTokenEntry?.timestamp)) {
|
|
809
787
|
logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing');
|
|
810
788
|
tcTokenBuffer = undefined;
|
|
811
|
-
// Preserve senderTimestamp so the fire-and-forget issuance dedupe survives cleanup.
|
|
812
789
|
const cleared = existingTokenEntry?.senderTimestamp !== undefined
|
|
813
790
|
? { token: Buffer.alloc(0), senderTimestamp: existingTokenEntry.senderTimestamp }
|
|
814
791
|
: null;
|
|
@@ -827,14 +804,18 @@ export const makeMessagesSocket = (config) => {
|
|
|
827
804
|
content: tcTokenBuffer
|
|
828
805
|
});
|
|
829
806
|
}
|
|
807
|
+
let alreadyHasBizNode = false;
|
|
830
808
|
if (additionalNodes && additionalNodes.length > 0) {
|
|
831
809
|
;
|
|
832
810
|
stanza.content.push(...additionalNodes);
|
|
811
|
+
alreadyHasBizNode = !addBizAttributes && additionalNodes.some(node => node.tag === 'biz');
|
|
812
|
+
}
|
|
813
|
+
if ((!alreadyHasBizNode && shouldIncludeBizBinaryNode(message)) || addBizAttributes) {
|
|
814
|
+
const bizNode = getBizBinaryNode(message);
|
|
815
|
+
stanza.content.push(bizNode);
|
|
833
816
|
}
|
|
834
817
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
835
818
|
await sendNode(stanza);
|
|
836
|
-
// Fire-and-forget: issue our token to the contact AFTER message send.
|
|
837
|
-
// WA Web skips protocol messages and PSA/bot contacts (TcTokenChatAction: isRegularUser)
|
|
838
819
|
const isProtocolMsg = !!normalizeMessageContent(message)?.protocolMessage;
|
|
839
820
|
const isBotOrPSA = destinationJid === PSA_WID || isJidBot(destinationJid) || isJidMetaAI(destinationJid);
|
|
840
821
|
if (is1on1Send &&
|
|
@@ -875,7 +856,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
875
856
|
inFlightTcTokenIssuance.delete(tcTokenJid);
|
|
876
857
|
});
|
|
877
858
|
}
|
|
878
|
-
// Add message to retry cache if enabled
|
|
879
859
|
if (messageRetryManager && !participant) {
|
|
880
860
|
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
881
861
|
}
|
|
@@ -886,6 +866,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
886
866
|
const normalizedMessage = normalizeMessageContent(message);
|
|
887
867
|
if (!normalizedMessage)
|
|
888
868
|
return 'text';
|
|
869
|
+
// Bot Forwarded and Rich Response messages MUST be typed as 'text' on the wire
|
|
870
|
+
if (normalizedMessage.botForwardedMessage || normalizedMessage.richResponseMessage) {
|
|
871
|
+
return 'text';
|
|
872
|
+
}
|
|
889
873
|
if (normalizedMessage.reactionMessage || normalizedMessage.encReactionMessage) {
|
|
890
874
|
return 'reaction';
|
|
891
875
|
}
|
|
@@ -904,49 +888,68 @@ export const makeMessagesSocket = (config) => {
|
|
|
904
888
|
return 'text';
|
|
905
889
|
};
|
|
906
890
|
const getMediaType = (message) => {
|
|
907
|
-
|
|
891
|
+
const innerMsg = message?.botForwardedMessage?.message || message;
|
|
892
|
+
if (innerMsg.imageMessage) {
|
|
908
893
|
return 'image';
|
|
909
894
|
}
|
|
910
|
-
else if (
|
|
911
|
-
return
|
|
895
|
+
else if (innerMsg.videoMessage) {
|
|
896
|
+
return innerMsg.videoMessage.gifPlayback ? 'gif' : 'video';
|
|
897
|
+
}
|
|
898
|
+
else if (innerMsg.ptvMessage) {
|
|
899
|
+
return 'ptv';
|
|
912
900
|
}
|
|
913
|
-
else if (
|
|
914
|
-
return
|
|
901
|
+
else if (innerMsg.audioMessage) {
|
|
902
|
+
return innerMsg.audioMessage.ptt ? 'ptt' : 'audio';
|
|
915
903
|
}
|
|
916
|
-
else if (
|
|
904
|
+
else if (innerMsg.contactMessage) {
|
|
917
905
|
return 'vcard';
|
|
918
906
|
}
|
|
919
|
-
else if (
|
|
907
|
+
else if (innerMsg.documentMessage) {
|
|
920
908
|
return 'document';
|
|
921
909
|
}
|
|
922
|
-
else if (
|
|
910
|
+
else if (innerMsg.contactsArrayMessage) {
|
|
923
911
|
return 'contact_array';
|
|
924
912
|
}
|
|
925
|
-
else if (
|
|
913
|
+
else if (innerMsg.liveLocationMessage) {
|
|
926
914
|
return 'livelocation';
|
|
927
915
|
}
|
|
928
|
-
else if (
|
|
916
|
+
else if (innerMsg.stickerMessage) {
|
|
929
917
|
return 'sticker';
|
|
930
918
|
}
|
|
931
|
-
else if (
|
|
919
|
+
else if (innerMsg.listMessage) {
|
|
932
920
|
return 'list';
|
|
933
921
|
}
|
|
934
|
-
else if (
|
|
922
|
+
else if (innerMsg.listResponseMessage) {
|
|
935
923
|
return 'list_response';
|
|
936
924
|
}
|
|
937
|
-
else if (
|
|
925
|
+
else if (innerMsg.buttonsResponseMessage) {
|
|
938
926
|
return 'buttons_response';
|
|
939
927
|
}
|
|
940
|
-
else if (
|
|
928
|
+
else if (innerMsg.orderMessage) {
|
|
941
929
|
return 'order';
|
|
942
930
|
}
|
|
943
|
-
else if (
|
|
931
|
+
else if (innerMsg.productMessage) {
|
|
944
932
|
return 'product';
|
|
945
933
|
}
|
|
946
|
-
else if (
|
|
934
|
+
else if (innerMsg.interactiveMessage) {
|
|
935
|
+
return 'interactive';
|
|
936
|
+
}
|
|
937
|
+
else if (innerMsg.interactiveResponseMessage) {
|
|
947
938
|
return 'native_flow_response';
|
|
948
939
|
}
|
|
949
|
-
else if (
|
|
940
|
+
else if (innerMsg.commentMessage) {
|
|
941
|
+
return 'comment';
|
|
942
|
+
}
|
|
943
|
+
else if (innerMsg.stickerPackMessage) {
|
|
944
|
+
return 'sticker_pack';
|
|
945
|
+
}
|
|
946
|
+
else if (innerMsg.bcallMessage) {
|
|
947
|
+
return 'bcall';
|
|
948
|
+
}
|
|
949
|
+
else if (innerMsg.lottieStickerMessage) {
|
|
950
|
+
return 'lottie_sticker';
|
|
951
|
+
}
|
|
952
|
+
else if (innerMsg.groupInviteMessage) {
|
|
950
953
|
return 'url';
|
|
951
954
|
}
|
|
952
955
|
return '';
|
|
@@ -999,7 +1002,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
999
1002
|
sendReceipts,
|
|
1000
1003
|
readMessages,
|
|
1001
1004
|
refreshMediaConn,
|
|
1002
|
-
// Function (not getter) so the spread in chats.ts preserves the live closure binding.
|
|
1003
1005
|
getMediaHost: () => mediaHost,
|
|
1004
1006
|
waUploadToServer,
|
|
1005
1007
|
fetchPrivacySettings,
|
|
@@ -1050,8 +1052,279 @@ export const makeMessagesSocket = (config) => {
|
|
|
1050
1052
|
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
1051
1053
|
return message;
|
|
1052
1054
|
},
|
|
1055
|
+
menurich: async (jid, options) => {
|
|
1056
|
+
const responseId = crypto.randomUUID();
|
|
1057
|
+
const botResponseId = crypto.randomUUID();
|
|
1058
|
+
const title = options.title;
|
|
1059
|
+
const sections = [
|
|
1060
|
+
{
|
|
1061
|
+
view_model: {
|
|
1062
|
+
primitive: {
|
|
1063
|
+
__typename: 'FOATextPrimitive',
|
|
1064
|
+
text: title
|
|
1065
|
+
},
|
|
1066
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
];
|
|
1070
|
+
if (options.subtitle) {
|
|
1071
|
+
sections.push({
|
|
1072
|
+
view_model: {
|
|
1073
|
+
primitive: {
|
|
1074
|
+
__typename: 'GenAIMarkdownTextUXPrimitive',
|
|
1075
|
+
text: options.subtitle
|
|
1076
|
+
},
|
|
1077
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
if (options.imageUrl) {
|
|
1082
|
+
sections.push({
|
|
1083
|
+
view_model: {
|
|
1084
|
+
primitive: {
|
|
1085
|
+
__typename: 'GenAIImagePrimitive',
|
|
1086
|
+
preview_image: {
|
|
1087
|
+
__typename: 'GenAIMediaItem',
|
|
1088
|
+
mime_type: 'image/jpeg',
|
|
1089
|
+
url: options.imageUrl
|
|
1090
|
+
},
|
|
1091
|
+
full_image: {
|
|
1092
|
+
__typename: 'GenAIMediaItem',
|
|
1093
|
+
mime_type: 'image/jpeg',
|
|
1094
|
+
url: options.imageUrl
|
|
1095
|
+
}
|
|
1096
|
+
},
|
|
1097
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
if (options.menus && options.menus.length > 0) {
|
|
1102
|
+
let idCounter = 0;
|
|
1103
|
+
const primitives = options.menus.map(menu => {
|
|
1104
|
+
return {
|
|
1105
|
+
__typename: 'GenAI3PExtWidgetPrimitive',
|
|
1106
|
+
header: {
|
|
1107
|
+
__typename: 'GenAI3PExtWidgetStandardHeader',
|
|
1108
|
+
title: menu.title
|
|
1109
|
+
},
|
|
1110
|
+
body: {
|
|
1111
|
+
__typename: 'GenAI3PExtCalendarEventList',
|
|
1112
|
+
sections: [],
|
|
1113
|
+
ctas: menu.buttons.map(btn => {
|
|
1114
|
+
const toolCallId = String(idCounter++).padStart(2, '0');
|
|
1115
|
+
return {
|
|
1116
|
+
__typename: 'GenAI3PExtWidgetCTA',
|
|
1117
|
+
label: btn.label,
|
|
1118
|
+
state: 'PENDING',
|
|
1119
|
+
kind: 'OTHER',
|
|
1120
|
+
tool_call_id: toolCallId,
|
|
1121
|
+
toast: btn.toast ? {
|
|
1122
|
+
__typename: 'GenAI3PExtWidgetToast',
|
|
1123
|
+
label: btn.toast
|
|
1124
|
+
} : undefined
|
|
1125
|
+
};
|
|
1126
|
+
})
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
});
|
|
1130
|
+
sections.push({
|
|
1131
|
+
view_model: {
|
|
1132
|
+
primitives,
|
|
1133
|
+
__typename: 'GenAIHScrollLayoutViewModel'
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
if (options.footerLinks && options.footerLinks.length > 0) {
|
|
1138
|
+
const primitives = options.footerLinks.map(link => {
|
|
1139
|
+
return {
|
|
1140
|
+
__typename: 'GenAIFooterActionPrimitive',
|
|
1141
|
+
cta_text: link.label,
|
|
1142
|
+
cta_type: 'OPEN_URL',
|
|
1143
|
+
cta_url: link.url
|
|
1144
|
+
};
|
|
1145
|
+
});
|
|
1146
|
+
sections.push({
|
|
1147
|
+
view_model: {
|
|
1148
|
+
primitives,
|
|
1149
|
+
__typename: 'GenAIHScrollLayoutViewModel'
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
const unifiedResponse = {
|
|
1154
|
+
response_id: responseId,
|
|
1155
|
+
sections
|
|
1156
|
+
};
|
|
1157
|
+
const signatureRaw = 'TklYRUwuTWVzc2FnZUJ1aWxkZXJWNC43LVZlcmlmaWNhdGlvblNpZ25hdHVyZS5NZXRhZGF0YeN55YRyad2+ZA==';
|
|
1158
|
+
const signature = Buffer.from(Buffer.from(signatureRaw, 'base64').toString('binary').replace('NIXEL', 'UDMODZ'), 'binary').toString('base64');
|
|
1159
|
+
const certificateChainRaw = [
|
|
1160
|
+
'TklYRUwuTWVzc2FnZUJ1aWxkZXJWNC43LUNlcnRpZmljYXRlQ2hhaW4uTWV0YWRhdGEOvtJr968bbpKdZreOTwkk9aPN++XPE60RfuzNLkXXc7LE8BOkJOWRpo2oNXaRJ3uCNJ43HY3A+oetnvHSfcxWqmvvTSrBOI5V1NOD6RMsZ/st1XVPUx83AGps1l5jYBOYzqMNy6un2tToJ2Bt9bXRo29tWLZTu8m7TNY/hISwVpVc5tjSet5U7btPN+dMIx2UvykB1jcbWGsdklheeuz8RXSStNXzeaGvsf1lpZ/ugLE4b2BdmlRNKrY6zLE4qFtRYQoS7axOyQX+4QUyN2m9bfm7urQmn+QRSXJwMO7X5kAJJLbkVGJFt9Pm9VXPwQVrK2aaqiXlpusj+7DfDw00OULmYMmZDTqXM0nUVLxj13z0LhMQoQhhNG8utdUn4uKOFceliTZ/xiP+A54GnX9620641bqw3ctfh9NNXPsTEK8hAUD7FDqUhVntHmoEYYEHq8X1tHHZYP49/f2iezTiE8AUaoZo42/jIWQIKohOGNUib2hEqMkW8NsR8vPihvNuqPc0zKZcl6359YFQdjiiW8kCRD/rsDOr9v1eYLFZKYloFyzFqEgj+jcG/V47elOjShJ5CCPwatXwP6HIloVwtgygFsnOFmCg6Ojoivfoz8Nw1qxFwg5OU2cq/1WbWNELKnaFg4eUWCAIJ/3ZIJsEPkgemZxGhE+hdiNn9dkQYBJs1kx2BxdIkJmQ9vJSKkrMz6lTxZM3IJ9mhmKS6zYdU1ppeAao0/ayte997DQParb/AHLN79g0iW1ad0z8ir5jAl0q3a+UZPTSa4YiSqC2PZ/gfxG5wvL2mKmeKowG0RXjmEp5iNxrni+T/HRLZOoH7y0DQ24nMCPg',
|
|
1161
|
+
'TklYRUwuTWVzc2FnZUJ1aWxkZXJWNC43LUNlcnRpZmljYXRlQ2hhaW4uTWV0YWRhdGHsL0Ccm0ELINFZ2IaBhKaeWnVuh0o6nZLCioCn9xpSADzwIS5VCWO+1eVXT2atJOyf7FYlpB0/JA3Us+aQtekuIkHu/zBXijORZ4ClF4+sF3cSTNg6gY/+6iwLK/zs3bMg+GeJrcI65vXfs95Shxlb2Rd5GRT2/2yBmR6Zkf5QwMJuptUHWtM26WY7/xlkEKGFYDZVqOSylusiOzSALa815zC6dCiHoJNLBEKMlaZZQOk57/+OYoU5zzTaEgLhyvNFHSyAlyLQ3SGFtVHAaJZHSmmSPyJowCOB+92Gkk6SWVMsk6FbU8QJWFtlhzV/W/gZ7WzUlS/AKgN0th9/cup2ToFkW7X9c+rtYavufmuieqFhXgaMD8AGsoN9QC/HzNC9D1nydPfFYEUr9BHVy2nF5gM58Y59r2rT8p5LPARIkUp8g+5DLhyW0tdZFZ1305o4AHCayZnp5rjcU2Xi/c1Qf/djBGakmijlMs4aMzKJYD0c4Q8jdI7sNyd876K2wRD+L6KeD2QB3PtCS4P7BWAl5gh5CJ6ZBrwcaKXZqcSjEwm52MqVCgYZdapAaNYUy/QndttjLOG0wxxwuX1hIhMjPnIKZR1kwnqD5EqlHpilrnojRZvjVGN4zEKmilS8rNstt4HHs/D849W+Q6LRVWiWMs0cT2IugrX+Skxd8En7Gq52UEmuVBrSTpN+UpIu20NsVb9lsvuYh3XO441606tOEY2eKcZJdTtqrOTNqbbTk0zVn1yhbOCvmfctBNDhTwaC5QMi0P9wjU5XI9SBtkdQLizc5oqpoiHeqgb8+aJHVLcbgIJ/KLZKtRWFDfzRNM02Csx4etUUapVd2NA/L0oMs/O5T9sVj9FBJ7q99GWr3PVmxJb36mHZLXC4k1gGN9swE0LtzYsUdT5tUo9ri/hS3W/SM+F1p4Kh4QIgRcG3ciIHGN44bnDh3HDCz0fDnzKYw0bclMxZPctEyJ5gEOPF6OAkjD9dEaRGq/tEPf1k9Aub+v2dEjnfrYWAm4E5Zfhs2Xh0CT0k+SzhgKd0K/46ChJ20G5+blwpIvahvTVS68+aVIX6CwXs4tcVx6FnmVsMOOkIasfaqQLZYbNBkuLoZnQAq4j8yRekrQ=='
|
|
1162
|
+
];
|
|
1163
|
+
const certificateChain = certificateChainRaw.map((cert) => typeof cert === 'string'
|
|
1164
|
+
? Buffer.from(Buffer.from(cert, 'base64').toString('binary').replace('NIXEL', 'UDMODZ'), 'binary').toString('base64')
|
|
1165
|
+
: cert);
|
|
1166
|
+
const message = {
|
|
1167
|
+
messageContextInfo: {
|
|
1168
|
+
deviceListMetadata: {},
|
|
1169
|
+
deviceListMetadataVersion: 2,
|
|
1170
|
+
botMetadata: {
|
|
1171
|
+
messageDisclaimerText: '',
|
|
1172
|
+
botResponseId,
|
|
1173
|
+
verificationMetadata: {
|
|
1174
|
+
proofs: [
|
|
1175
|
+
{
|
|
1176
|
+
version: 1,
|
|
1177
|
+
useCase: 1,
|
|
1178
|
+
signature: typeof signature === 'string' ? Buffer.from(signature, 'base64') : signature,
|
|
1179
|
+
certificateChain: certificateChain.map(cert => typeof cert === 'string' ? Buffer.from(cert, 'base64') : cert)
|
|
1180
|
+
}
|
|
1181
|
+
]
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
1185
|
+
botForwardedMessage: {
|
|
1186
|
+
message: {
|
|
1187
|
+
richResponseMessage: {
|
|
1188
|
+
messageType: 1,
|
|
1189
|
+
submessages: [
|
|
1190
|
+
{
|
|
1191
|
+
messageType: 2,
|
|
1192
|
+
messageText: title
|
|
1193
|
+
}
|
|
1194
|
+
],
|
|
1195
|
+
unifiedResponse: {
|
|
1196
|
+
data: Buffer.from(JSON.stringify(unifiedResponse))
|
|
1197
|
+
},
|
|
1198
|
+
contextInfo: {
|
|
1199
|
+
forwardingScore: 1,
|
|
1200
|
+
isForwarded: true,
|
|
1201
|
+
forwardedAiBotMessageInfo: {
|
|
1202
|
+
botJid: '867051314767696@bot'
|
|
1203
|
+
},
|
|
1204
|
+
forwardOrigin: 4
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
const msgId = generateMessageIDV2(sock.user?.id);
|
|
1211
|
+
await relayMessage(jid, message, { messageId: msgId });
|
|
1212
|
+
return msgId;
|
|
1213
|
+
},
|
|
1214
|
+
sendHtmlGame: async (jid, htmlPayload, options = {}) => {
|
|
1215
|
+
const responseId = options.responseId || crypto.randomUUID();
|
|
1216
|
+
const botResponseId = options.botResponseId || crypto.randomUUID();
|
|
1217
|
+
const title = options.title || 'UDMODZ';
|
|
1218
|
+
const trustedSources = options.trustedSources || ['udmodz.dev'];
|
|
1219
|
+
const botJid = options.botJid || '867051314767696@bot';
|
|
1220
|
+
const signatureRaw = options.signature || 'TklYRUwuTWVzc2FnZUJ1aWxkZXJWNC43LVZlcmlmaWNhdGlvblNpZ25hdHVyZS5NZXRhZGF0YeN55YRyad2+ZA==';
|
|
1221
|
+
const signature = Buffer.from(Buffer.from(signatureRaw, 'base64').toString('binary').replace('NIXEL', 'UDMODZ'), 'binary').toString('base64');
|
|
1222
|
+
const certificateChainRaw = options.certificateChain || [
|
|
1223
|
+
'TklYRUwuTWVzc2FnZUJ1aWxkZXJWNC43LUNlcnRpZmljYXRlQ2hhaW4uTWV0YWRhdGEOvtJr968bbpKdZreOTwkk9aPN++XPE60RfuzNLkXXc7LE8BOkJOWRpo2oNXaRJ3uCNJ43HY3A+oetnvHSfcxWqmvvTSrBOI5V1NOD6RMsZ/st1XVPUx83AGps1l5jYBOYzqMNy6un2tToJ2Bt9bXRo29tWLZTu8m7TNY/hISwVpVc5tjSet5U7btPN+dMIx2UvykB1jcbWGsdklheeuz8RXSStNXzeaGvsf1lpZ/ugLE4b2BdmlRNKrY6zLE4qFtRYQoS7axOyQX+4QUyN2m9bfm7urQmn+QRSXJwMO7X5kAJJLbkVGJFt9Pm9VXPwQVrK2aaqiXlpusj+7DfDw00OULmYMmZDTqXM0nUVLxj13z0LhMQoQhhNG8utdUn4uKOFceliTZ/xiP+A54GnX9620641bqw3ctfh9NNXPsTEK8hAUD7FDqUhVntHmoEYYEHq8X1tHHZYP49/f2iezTiE8AUaoZo42/jIWQIKohOGNUib2hEqMkW8NsR8vPihvNuqPc0zKZcl6359YFQdjiiW8kCRD/rsDOr9v1eYLFZKYloFyzFqEgj+jcG/V47elOjShJ5CCPwatXwP6HIloVwtgygFsnOFmCg6Ojoivfoz8Nw1qxFwg5OU2cq/1WbWNELKnaFg4eUWCAIJ/3ZIJsEPkgemZxGhE+hdiNn9dkQYBJs1kx2BxdIkJmQ9vJSKkrMz6lTxZM3IJ9mhmKS6zYdU1ppeAao0/ayte997DQParb/AHLN79g0iW1ad0z8ir5jAl0q3a+UZPTSa4YiSqC2PZ/gfxG5wvL2mKmeKowG0RXjmEp5iNxrni+T/HRLZOoH7y0DQ24nMCPg',
|
|
1224
|
+
'TklYRUwuTWVzc2FnZUJ1aWxkZXJWNC43LUNlcnRpZmljYXRlQ2hhaW4uTWV0YWRhdGHsL0Ccm0ELINFZ2IaBhKaeWnVuh0o6nZLCioCn9xpSADzwIS5VCWO+1eVXT2atJOyf7FYlpB0/JA3Us+aQtekuIkHu/zBXijORZ4ClF4+sF3cSTNg6gY/+6iwLK/zs3bMg+GeJrcI65vXfs95Shxlb2Rd5GRT2/2yBmR6Zkf5QwMJuptUHWtM26WY7/xlkEKGFYDZVqOSylusiOzSALa815zC6dCiHoJNLBEKMlaZZQOk57/+OYoU5zzTaEgLhyvNFHSyAlyLQ3SGFtVHAaJZHSmmSPyJowCOB+92Gkk6SWVMsk6FbU8QJWFtlhzV/W/gZ7WzUlS/AKgN0th9/cup2ToFkW7X9c+rtYavufmuieqFhXgaMD8AGsoN9QC/HzNC9D1nydPfFYEUr9BHVy2nF5gM58Y59r*+TRf6S4P7BWAl5gh5CJ6ZBrwcaKXZqcSjEwm52MqVCgYZdapAaNYUy/QndttjLOG0wxxwuX1hIhMjPnIKZR1kwnqD5EqlHpilrnojRZvjVGN4zEKmilS8rNstt4HHs/D849W+Q6LRVWiWMs0cT2IugrX+Skxd8En7Gq52UEmuVBrSTpN+UpIu20NsVb9lsvuYh3XO441606tOEY2eKcZJdTtqrOTNqbbTk0zVn1yhbOCvmfctBNDhTwaC5QMi0P9wjU5XI9SBtkdQLizc5oqpoiHeqgb8+aJHVLcbgIJ/KLZKtRWFDfzRNM02Csx4etUUapVd2NA/L0oMs/O5T9sVj9FBJ7q99GWr3PVmxJb36mHZLXC4k1gGN9swE0LtzYsUdT5tUo9ri/hS3W/SM+F1p4Kh4QIgRcG3ciIHGN44bnDh3HDCz0fDnzKYw0bclMxZPctEyJ5gEOPF6OAkjD9dEaRGq/tEPf1k9Aub+v2dEjnfrYWAm4E5Zfhs2Xh0CT0k+SzhgKd0K/46ChJ20G5+blwpIvahvTVS68+aVIX6CwXs4tcVx6FnmVsMOOkIasfaqQLZYbNBkuLoZnQAq4j8yRekrQ=='
|
|
1225
|
+
];
|
|
1226
|
+
const certificateChain = certificateChainRaw.map((cert) => typeof cert === 'string'
|
|
1227
|
+
? Buffer.from(Buffer.from(cert, 'base64').toString('binary').replace('NIXEL', 'UDMODZ'), 'binary').toString('base64')
|
|
1228
|
+
: cert);
|
|
1229
|
+
const sections = [
|
|
1230
|
+
{
|
|
1231
|
+
view_model: {
|
|
1232
|
+
primitive: {
|
|
1233
|
+
__typename: 'FOATextPrimitive',
|
|
1234
|
+
text: title
|
|
1235
|
+
},
|
|
1236
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
];
|
|
1240
|
+
if (options.subtitle) {
|
|
1241
|
+
sections.push({
|
|
1242
|
+
view_model: {
|
|
1243
|
+
primitive: {
|
|
1244
|
+
__typename: 'GenAIMarkdownTextUXPrimitive',
|
|
1245
|
+
text: options.subtitle
|
|
1246
|
+
},
|
|
1247
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
sections.push({
|
|
1252
|
+
view_model: {
|
|
1253
|
+
primitive: {
|
|
1254
|
+
__typename: 'GenAIaeacdsnwHtmlPrimitive',
|
|
1255
|
+
payload: htmlPayload,
|
|
1256
|
+
trusted_sources: trustedSources
|
|
1257
|
+
},
|
|
1258
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
1259
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
const unifiedResponse = {
|
|
1262
|
+
response_id: responseId,
|
|
1263
|
+
sections
|
|
1264
|
+
};
|
|
1265
|
+
const message = {
|
|
1266
|
+
messageContextInfo: {
|
|
1267
|
+
deviceListMetadata: {},
|
|
1268
|
+
deviceListMetadataVersion: 2,
|
|
1269
|
+
botMetadata: {
|
|
1270
|
+
messageDisclaimerText: '',
|
|
1271
|
+
botResponseId,
|
|
1272
|
+
verificationMetadata: {
|
|
1273
|
+
proofs: [
|
|
1274
|
+
{
|
|
1275
|
+
version: 1,
|
|
1276
|
+
useCase: 1,
|
|
1277
|
+
signature: typeof signature === 'string' ? Buffer.from(signature, 'base64') : signature,
|
|
1278
|
+
certificateChain: certificateChain.map(cert => typeof cert === 'string' ? Buffer.from(cert, 'base64') : cert)
|
|
1279
|
+
}
|
|
1280
|
+
]
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
},
|
|
1284
|
+
botForwardedMessage: {
|
|
1285
|
+
message: {
|
|
1286
|
+
richResponseMessage: {
|
|
1287
|
+
messageType: 1,
|
|
1288
|
+
submessages: [
|
|
1289
|
+
{
|
|
1290
|
+
messageType: 2,
|
|
1291
|
+
messageText: title
|
|
1292
|
+
}
|
|
1293
|
+
],
|
|
1294
|
+
unifiedResponse: {
|
|
1295
|
+
data: Buffer.from(JSON.stringify(unifiedResponse))
|
|
1296
|
+
},
|
|
1297
|
+
contextInfo: {
|
|
1298
|
+
forwardingScore: 1,
|
|
1299
|
+
isForwarded: true,
|
|
1300
|
+
forwardedAiBotMessageInfo: {
|
|
1301
|
+
botJid
|
|
1302
|
+
},
|
|
1303
|
+
forwardOrigin: 4
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
const msgId = generateMessageIDV2(sock.user?.id);
|
|
1310
|
+
await relayMessage(jid, message, { messageId: msgId });
|
|
1311
|
+
return msgId;
|
|
1312
|
+
},
|
|
1053
1313
|
sendMessage: async (jid, content, options = {}) => {
|
|
1054
1314
|
const userJid = authState.creds.me.id;
|
|
1315
|
+
if (isJidGroup(jid) && typeof content === 'object' && content) {
|
|
1316
|
+
if (('mentionAll' in content && content.mentionAll) ||
|
|
1317
|
+
(Array.isArray(content.mentions) && content.mentions.includes('@all')) ||
|
|
1318
|
+
options.mentionAll) {
|
|
1319
|
+
try {
|
|
1320
|
+
const metadata = await groupMetadata(jid);
|
|
1321
|
+
content.mentions = metadata.participants.map(p => p.id);
|
|
1322
|
+
}
|
|
1323
|
+
catch (err) {
|
|
1324
|
+
logger.warn({ err, jid }, 'failed to fetch group metadata for mentionAll');
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1055
1328
|
if (typeof content === 'object' &&
|
|
1056
1329
|
'disappearingMessagesInChat' in content &&
|
|
1057
1330
|
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
@@ -1077,7 +1350,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
1077
1350
|
logger,
|
|
1078
1351
|
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1079
1352
|
}),
|
|
1080
|
-
//TODO: CACHE
|
|
1081
1353
|
getProfilePicUrl: sock.profilePictureUrl,
|
|
1082
1354
|
getCallLink: sock.createCallLink,
|
|
1083
1355
|
upload: waUploadToServer,
|
|
@@ -1086,16 +1358,18 @@ export const makeMessagesSocket = (config) => {
|
|
|
1086
1358
|
messageId: generateMessageIDV2(sock.user?.id),
|
|
1087
1359
|
...options
|
|
1088
1360
|
});
|
|
1361
|
+
const isNewsletter = isJidNewsletter(jid);
|
|
1089
1362
|
const isEventMsg = 'event' in content && !!content.event;
|
|
1090
1363
|
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
1091
1364
|
const isEditMsg = 'edit' in content && !!content.edit;
|
|
1092
1365
|
const isPinMsg = 'pin' in content && !!content.pin;
|
|
1093
1366
|
const isPollMessage = 'poll' in content && !!content.poll;
|
|
1094
|
-
const
|
|
1095
|
-
const
|
|
1096
|
-
|
|
1367
|
+
const isQuizMsg = 'poll' in content && !!content.poll.pollType;
|
|
1368
|
+
const isAiMsg = 'ai' in content && !!content.ai;
|
|
1369
|
+
const isNeedBizAttrs = 'secureMetaServiceLabel' in content && !!content.secureMetaServiceLabel;
|
|
1370
|
+
const additionalAttributes = options.additionalAttributes || {};
|
|
1371
|
+
const additionalNodes = options.additionalNodes || [];
|
|
1097
1372
|
if (isDeleteMsg) {
|
|
1098
|
-
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
1099
1373
|
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
1100
1374
|
additionalAttributes.edit = '8';
|
|
1101
1375
|
}
|
|
@@ -1104,16 +1378,20 @@ export const makeMessagesSocket = (config) => {
|
|
|
1104
1378
|
}
|
|
1105
1379
|
}
|
|
1106
1380
|
else if (isEditMsg) {
|
|
1107
|
-
additionalAttributes.edit = '1';
|
|
1381
|
+
additionalAttributes.edit = isNewsletter ? '3' : '1';
|
|
1108
1382
|
}
|
|
1109
1383
|
else if (isPinMsg) {
|
|
1110
1384
|
additionalAttributes.edit = '2';
|
|
1111
1385
|
}
|
|
1112
1386
|
else if (isPollMessage) {
|
|
1387
|
+
if (!isNewsletter && isQuizMsg) {
|
|
1388
|
+
throw new Boom('Quiz are only allowed for newsletter', { statusCode: 400 });
|
|
1389
|
+
}
|
|
1113
1390
|
additionalNodes.push({
|
|
1114
1391
|
tag: 'meta',
|
|
1115
1392
|
attrs: {
|
|
1116
|
-
polltype: 'creation'
|
|
1393
|
+
polltype: isQuizMsg ? 'quiz_creation' : 'creation',
|
|
1394
|
+
contenttype: isPollMessage && isNewsletter ? 'text' : undefined
|
|
1117
1395
|
}
|
|
1118
1396
|
});
|
|
1119
1397
|
}
|
|
@@ -1125,12 +1403,28 @@ export const makeMessagesSocket = (config) => {
|
|
|
1125
1403
|
}
|
|
1126
1404
|
});
|
|
1127
1405
|
}
|
|
1406
|
+
else if (isAiMsg) {
|
|
1407
|
+
if (!(isPnUser(jid) || isLidUser(jid))) {
|
|
1408
|
+
throw new Boom('AI icon on message are only allowed in private chat', { statusCode: 400 });
|
|
1409
|
+
}
|
|
1410
|
+
if ('messageContextInfo' in fullMsg.message && !!fullMsg.message.messageContextInfo) {
|
|
1411
|
+
fullMsg.message.messageContextInfo.supportPayload = BIZ_BOT_SUPPORT_PAYLOAD;
|
|
1412
|
+
}
|
|
1413
|
+
additionalNodes.push({
|
|
1414
|
+
tag: 'bot',
|
|
1415
|
+
attrs: {
|
|
1416
|
+
biz_bot: '1'
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
delete content.ai;
|
|
1420
|
+
}
|
|
1128
1421
|
await relayMessage(jid, fullMsg.message, {
|
|
1129
1422
|
messageId: fullMsg.key.id,
|
|
1130
1423
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1131
1424
|
additionalAttributes,
|
|
1132
1425
|
statusJidList: options.statusJidList,
|
|
1133
|
-
additionalNodes
|
|
1426
|
+
additionalNodes,
|
|
1427
|
+
addBizAttributes: isNeedBizAttrs
|
|
1134
1428
|
});
|
|
1135
1429
|
if (config.emitOwnEvents) {
|
|
1136
1430
|
process.nextTick(async () => {
|
|
@@ -1139,188 +1433,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
1139
1433
|
}
|
|
1140
1434
|
return fullMsg;
|
|
1141
1435
|
}
|
|
1142
|
-
},
|
|
1143
|
-
sendChStatus: async (jid, content, options = {}) => {
|
|
1144
|
-
const userJid = authState.creds.me.id;
|
|
1145
|
-
const statusJid = 'status@broadcast';
|
|
1146
|
-
const fullMsg = await generateWAMessage(statusJid, content, {
|
|
1147
|
-
logger,
|
|
1148
|
-
userJid,
|
|
1149
|
-
getUrlInfo: text => getUrlInfo(text, {
|
|
1150
|
-
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1151
|
-
fetchOpts: {
|
|
1152
|
-
timeout: 3000,
|
|
1153
|
-
...(httpRequestOptions || {})
|
|
1154
|
-
},
|
|
1155
|
-
logger,
|
|
1156
|
-
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1157
|
-
}),
|
|
1158
|
-
getProfilePicUrl: sock.profilePictureUrl,
|
|
1159
|
-
getCallLink: sock.createCallLink,
|
|
1160
|
-
upload: waUploadToServer,
|
|
1161
|
-
mediaCache: config.mediaCache,
|
|
1162
|
-
options: config.options,
|
|
1163
|
-
messageId: generateMessageIDV2(sock.user?.id),
|
|
1164
|
-
...options
|
|
1165
|
-
});
|
|
1166
|
-
await relayMessage(statusJid, fullMsg.message, {
|
|
1167
|
-
messageId: fullMsg.key.id,
|
|
1168
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1169
|
-
statusJidList: [jid]
|
|
1170
|
-
});
|
|
1171
|
-
if (config.emitOwnEvents) {
|
|
1172
|
-
process.nextTick(async () => {
|
|
1173
|
-
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1174
|
-
});
|
|
1175
|
-
}
|
|
1176
|
-
return fullMsg;
|
|
1177
|
-
},
|
|
1178
|
-
sendGroupStatus: (groupJid, content, options = {}) => (sendGroupStatus({
|
|
1179
|
-
waUploadToServer,
|
|
1180
|
-
relayMessage,
|
|
1181
|
-
authState
|
|
1182
|
-
}, groupJid, content, options)),
|
|
1183
|
-
sendChannelStatus: (channelJid, content, options = {}) => (sendChannelStatus({
|
|
1184
|
-
waUploadToServer,
|
|
1185
|
-
relayMessage,
|
|
1186
|
-
authState
|
|
1187
|
-
}, channelJid, content, options)),
|
|
1188
|
-
menurich: async (jid, options) => {
|
|
1189
|
-
const sections = [];
|
|
1190
|
-
// 1. Header (Title)
|
|
1191
|
-
if (options.title) {
|
|
1192
|
-
sections.push({
|
|
1193
|
-
view_model: {
|
|
1194
|
-
primitive: {
|
|
1195
|
-
__typename: "FOATextPrimitive",
|
|
1196
|
-
text: options.title
|
|
1197
|
-
},
|
|
1198
|
-
__typename: "GenAISingleLayoutViewModel"
|
|
1199
|
-
}
|
|
1200
|
-
});
|
|
1201
|
-
}
|
|
1202
|
-
// 2. Subtitle
|
|
1203
|
-
if (options.subtitle) {
|
|
1204
|
-
sections.push({
|
|
1205
|
-
view_model: {
|
|
1206
|
-
primitive: {
|
|
1207
|
-
__typename: "GenAIMarkdownTextUXPrimitive",
|
|
1208
|
-
text: options.subtitle
|
|
1209
|
-
},
|
|
1210
|
-
__typename: "GenAISingleLayoutViewModel"
|
|
1211
|
-
}
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1214
|
-
// 3. Image
|
|
1215
|
-
if (options.imageUrl) {
|
|
1216
|
-
sections.push({
|
|
1217
|
-
view_model: {
|
|
1218
|
-
primitive: {
|
|
1219
|
-
__typename: "GenAIImagePrimitive",
|
|
1220
|
-
preview_image: {
|
|
1221
|
-
__typename: "GenAIMediaItem",
|
|
1222
|
-
mime_type: "image/jpeg",
|
|
1223
|
-
url: options.imageUrl
|
|
1224
|
-
},
|
|
1225
|
-
full_image: {
|
|
1226
|
-
__typename: "GenAIMediaItem",
|
|
1227
|
-
mime_type: "image/jpeg",
|
|
1228
|
-
url: options.imageUrl
|
|
1229
|
-
}
|
|
1230
|
-
},
|
|
1231
|
-
__typename: "GenAISingleLayoutViewModel"
|
|
1232
|
-
}
|
|
1233
|
-
});
|
|
1234
|
-
}
|
|
1235
|
-
// 4. Horizontal Scroll CTAs (Buttons/Menus)
|
|
1236
|
-
if (options.menus && options.menus.length > 0) {
|
|
1237
|
-
const primitives = options.menus.map((menu, mIdx) => {
|
|
1238
|
-
return {
|
|
1239
|
-
__typename: "GenAI3PExtWidgetPrimitive",
|
|
1240
|
-
header: {
|
|
1241
|
-
__typename: "GenAI3PExtWidgetStandardHeader",
|
|
1242
|
-
title: menu.title
|
|
1243
|
-
},
|
|
1244
|
-
body: {
|
|
1245
|
-
__typename: "GenAI3PExtCalendarEventList",
|
|
1246
|
-
sections: [],
|
|
1247
|
-
ctas: menu.buttons.map((btn, bIdx) => ({
|
|
1248
|
-
__typename: "GenAI3PExtWidgetCTA",
|
|
1249
|
-
label: btn.label,
|
|
1250
|
-
state: "PENDING",
|
|
1251
|
-
kind: "OTHER",
|
|
1252
|
-
tool_call_id: `${mIdx}${bIdx}`,
|
|
1253
|
-
toast: btn.toast ? {
|
|
1254
|
-
__typename: "GenAI3PExtWidgetToast",
|
|
1255
|
-
label: btn.toast
|
|
1256
|
-
} : undefined
|
|
1257
|
-
}))
|
|
1258
|
-
}
|
|
1259
|
-
};
|
|
1260
|
-
});
|
|
1261
|
-
sections.push({
|
|
1262
|
-
view_model: {
|
|
1263
|
-
primitives,
|
|
1264
|
-
__typename: "GenAIHScrollLayoutViewModel"
|
|
1265
|
-
}
|
|
1266
|
-
});
|
|
1267
|
-
}
|
|
1268
|
-
// 5. Footer Actions (URLs)
|
|
1269
|
-
if (options.footerLinks && options.footerLinks.length > 0) {
|
|
1270
|
-
const primitives = options.footerLinks.map(link => ({
|
|
1271
|
-
__typename: "GenAIFooterActionPrimitive",
|
|
1272
|
-
cta_text: link.label,
|
|
1273
|
-
cta_type: "OPEN_URL",
|
|
1274
|
-
cta_url: link.url
|
|
1275
|
-
}));
|
|
1276
|
-
sections.push({
|
|
1277
|
-
view_model: {
|
|
1278
|
-
primitives,
|
|
1279
|
-
__typename: "GenAIHScrollLayoutViewModel"
|
|
1280
|
-
}
|
|
1281
|
-
});
|
|
1282
|
-
}
|
|
1283
|
-
const msg = {
|
|
1284
|
-
messageContextInfo: {
|
|
1285
|
-
messageSecret: Buffer.from("v/3VN8Gfr2dbKzgt1GKDEU7ovyYW+nswh4Duwq6KDuU=", "base64")
|
|
1286
|
-
},
|
|
1287
|
-
botForwardedMessage: {
|
|
1288
|
-
message: {
|
|
1289
|
-
richResponseMessage: {
|
|
1290
|
-
messageType: 1,
|
|
1291
|
-
submessages: options.imageUrl ? [
|
|
1292
|
-
{
|
|
1293
|
-
messageType: 1,
|
|
1294
|
-
gridImageMetadata: {
|
|
1295
|
-
gridImageUrl: {
|
|
1296
|
-
imagePreviewUrl: options.imageUrl,
|
|
1297
|
-
},
|
|
1298
|
-
imageUrls: [
|
|
1299
|
-
{
|
|
1300
|
-
imagePreviewUrl: options.imageUrl,
|
|
1301
|
-
imageHighResUrl: options.imageUrl,
|
|
1302
|
-
sourceUrl: options.imageUrl,
|
|
1303
|
-
}
|
|
1304
|
-
],
|
|
1305
|
-
},
|
|
1306
|
-
}
|
|
1307
|
-
] : [],
|
|
1308
|
-
unifiedResponse: {
|
|
1309
|
-
data: Buffer.from(JSON.stringify({
|
|
1310
|
-
response_id: "742a451a-0c33-45ca-a205-42c2b1666bca",
|
|
1311
|
-
sections
|
|
1312
|
-
}))
|
|
1313
|
-
},
|
|
1314
|
-
contextInfo: {
|
|
1315
|
-
forwardingScore: 1,
|
|
1316
|
-
isForwarded: true,
|
|
1317
|
-
forwardOrigin: 4
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
};
|
|
1323
|
-
return relayMessage(jid, msg, {});
|
|
1324
1436
|
}
|
|
1325
1437
|
};
|
|
1326
1438
|
};
|