@alannxd/baileys 6.0.5 → 6.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +341 -286
- package/WAProto/WAProto.proto +1782 -359
- package/WAProto/index.d.ts +75133 -9893
- package/WAProto/index.js +205861 -60606
- package/lib/Socket/luxu.js +6 -117
- package/lib/Socket/messages-send.js +637 -493
- package/lib/Socket/newsletter.js +229 -156
- package/lib/Utils/browser-utils.js +26 -6
- package/lib/Utils/decode-wa-message.js +33 -0
- package/lib/Utils/generics.js +10 -0
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/message-composer.js +273 -0
- package/lib/Utils/messages.js +361 -24
- package/lib/WABinary/generic-utils.js +8 -1
- package/lib/WABinary/jid-utils.js +2 -0
- package/lib/index.js +1 -2
- package/package.json +5 -4
- package/lib/Defaults/index.d.ts +0 -75
- package/lib/Signal/Group/ciphertext-message.d.ts +0 -10
- package/lib/Signal/Group/group-session-builder.d.ts +0 -15
- package/lib/Signal/Group/group_cipher.d.ts +0 -17
- package/lib/Signal/Group/index.d.ts +0 -12
- package/lib/Signal/Group/keyhelper.d.ts +0 -11
- package/lib/Signal/Group/sender-chain-key.d.ts +0 -14
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -17
- package/lib/Signal/Group/sender-key-message.d.ts +0 -19
- package/lib/Signal/Group/sender-key-name.d.ts +0 -18
- package/lib/Signal/Group/sender-key-record.d.ts +0 -31
- package/lib/Signal/Group/sender-key-state.d.ts +0 -39
- package/lib/Signal/Group/sender-message-key.d.ts +0 -12
- package/lib/Signal/libsignal.d.ts +0 -5
- package/lib/Signal/lid-mapping.d.ts +0 -23
- package/lib/Socket/Client/index.d.ts +0 -3
- package/lib/Socket/Client/types.d.ts +0 -16
- package/lib/Socket/Client/websocket.d.ts +0 -13
- package/lib/Socket/business.d.ts +0 -217
- package/lib/Socket/chats.d.ts +0 -124
- package/lib/Socket/communities.d.ts +0 -273
- package/lib/Socket/groups.d.ts +0 -162
- package/lib/Socket/index.d.ts +0 -260
- package/lib/Socket/luxu.d.ts +0 -22
- package/lib/Socket/messages-recv.d.ts +0 -213
- package/lib/Socket/messages-send.d.ts +0 -199
- package/lib/Socket/mex.d.ts +0 -3
- package/lib/Socket/newsletter.d.ts +0 -170
- package/lib/Socket/socket.d.ts +0 -59
- package/lib/Store/index.d.ts +0 -10
- package/lib/Store/keyed-db.d.ts +0 -22
- package/lib/Store/make-cache-manager-store.d.ts +0 -19
- package/lib/Store/make-in-memory-store.d.ts +0 -39
- package/lib/Store/make-ordered-dictionary.d.ts +0 -14
- package/lib/Store/object-repository.d.ts +0 -11
- package/lib/Types/Auth.d.ts +0 -117
- package/lib/Types/Bussines.d.ts +0 -25
- package/lib/Types/Call.d.ts +0 -15
- package/lib/Types/Chat.d.ts +0 -124
- package/lib/Types/Contact.d.ts +0 -26
- package/lib/Types/Events.d.ts +0 -256
- package/lib/Types/GroupMetadata.d.ts +0 -71
- package/lib/Types/Label.d.ts +0 -47
- package/lib/Types/LabelAssociation.d.ts +0 -30
- package/lib/Types/Message.d.ts +0 -320
- package/lib/Types/Mex.d.ts +0 -141
- package/lib/Types/Product.d.ts +0 -79
- package/lib/Types/Signal.d.ts +0 -87
- package/lib/Types/Socket.d.ts +0 -136
- package/lib/Types/State.d.ts +0 -97
- package/lib/Types/USync.d.ts +0 -26
- package/lib/Types/index.d.ts +0 -65
- package/lib/Utils/auth-utils.d.ts +0 -24
- package/lib/Utils/browser-utils.d.ts +0 -4
- package/lib/Utils/business.d.ts +0 -23
- package/lib/Utils/chat-utils.d.ts +0 -100
- package/lib/Utils/companion-reg-client-utils.d.ts +0 -17
- package/lib/Utils/crypto.d.ts +0 -37
- package/lib/Utils/decode-wa-message.d.ts +0 -66
- package/lib/Utils/event-buffer.d.ts +0 -36
- package/lib/Utils/generics.d.ts +0 -91
- package/lib/Utils/history.d.ts +0 -24
- package/lib/Utils/identity-change-handler.d.ts +0 -44
- package/lib/Utils/index.d.ts +0 -22
- package/lib/Utils/link-preview.d.ts +0 -21
- package/lib/Utils/logger.d.ts +0 -12
- package/lib/Utils/lt-hash.d.ts +0 -8
- package/lib/Utils/make-mutex.d.ts +0 -9
- package/lib/Utils/message-retry-manager.d.ts +0 -115
- package/lib/Utils/messages-media.d.ts +0 -133
- package/lib/Utils/messages.d.ts +0 -91
- package/lib/Utils/noise-handler.d.ts +0 -20
- package/lib/Utils/offline-node-processor.d.ts +0 -17
- package/lib/Utils/pre-key-manager.d.ts +0 -28
- package/lib/Utils/process-message.d.ts +0 -60
- package/lib/Utils/reporting-utils.d.ts +0 -11
- package/lib/Utils/signal.d.ts +0 -47
- package/lib/Utils/stanza-ack.d.ts +0 -11
- package/lib/Utils/sync-action-utils.d.ts +0 -19
- package/lib/Utils/tc-token-utils.d.ts +0 -37
- package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
- package/lib/Utils/validate-connection.d.ts +0 -11
- package/lib/WABinary/constants.d.ts +0 -28
- package/lib/WABinary/decode.d.ts +0 -7
- package/lib/WABinary/encode.d.ts +0 -3
- package/lib/WABinary/generic-utils.d.ts +0 -18
- package/lib/WABinary/index.d.ts +0 -6
- package/lib/WABinary/jid-utils.d.ts +0 -48
- package/lib/WABinary/types.d.ts +0 -19
- package/lib/WAM/BinaryInfo.d.ts +0 -9
- package/lib/WAM/constants.d.ts +0 -40
- package/lib/WAM/encode.d.ts +0 -3
- package/lib/WAM/index.d.ts +0 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -23
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -13
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -13
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -26
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/index.d.ts +0 -6
- package/lib/WAUSync/USyncQuery.d.ts +0 -30
- package/lib/WAUSync/USyncUser.d.ts +0 -17
- package/lib/WAUSync/index.d.ts +0 -4
- package/lib/index.d.ts +0 -13
|
@@ -2,16 +2,17 @@ import NodeCache from '@cacheable/node-cache';
|
|
|
2
2
|
import { Boom } from '@hapi/boom';
|
|
3
3
|
import { proto } from '../../WAProto/index.js';
|
|
4
4
|
import { DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
5
|
-
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/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, parseAndInjectE2ESessions, unixTimestampSeconds, setBotMessageSecret } from '../Utils/index.js';
|
|
6
6
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
7
7
|
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
|
|
8
8
|
import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/reporting-utils.js';
|
|
9
9
|
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, getAdditionalNode, getBinaryNodeFilter } from '../WABinary/index.js';
|
|
10
|
+
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET, getAdditionalNode, getBinaryNodeFilter, getBinaryFilteredBizBot, isInteropUser } from '../WABinary/index.js';
|
|
11
11
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
12
12
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
13
13
|
import imup from './luxu.js';
|
|
14
14
|
import * as Utils_1 from '../Utils/index.js';
|
|
15
|
+
import { randomBytes } from 'crypto';
|
|
15
16
|
export const makeMessagesSocket = (config) => {
|
|
16
17
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount, aiLabel } = config;
|
|
17
18
|
const sock = makeNewsletterSocket(config);
|
|
@@ -427,494 +428,464 @@ export const makeMessagesSocket = (config) => {
|
|
|
427
428
|
}
|
|
428
429
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
429
430
|
};
|
|
430
|
-
const relayMessage = async (
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
431
|
+
const relayMessage = async (
|
|
432
|
+
jid,
|
|
433
|
+
message,
|
|
434
|
+
{
|
|
435
|
+
messageId: msgId,
|
|
436
|
+
participant = false,
|
|
437
|
+
additionalAttributes,
|
|
438
|
+
additionalNodes,
|
|
439
|
+
useUserDevicesCache,
|
|
440
|
+
useCachedGroupMetadata,
|
|
441
|
+
statusJidList
|
|
442
|
+
}
|
|
443
|
+
) => {
|
|
444
|
+
const meId = authState.creds.me.id
|
|
445
|
+
const meLid = authState.creds.me?.lid
|
|
446
|
+
const isRetryResend = Boolean(participant?.jid)
|
|
447
|
+
let shouldIncludeDeviceIdentity = isRetryResend
|
|
448
|
+
const statusJid = 'status@broadcast'
|
|
449
|
+
const { user, server } = jidDecode(jid)
|
|
450
|
+
const isGroup = server === 'g.us'
|
|
451
|
+
const isStatus = jid === statusJid
|
|
452
|
+
const isLid = server === 'lid'
|
|
453
|
+
const isNewsletter = server === 'newsletter'
|
|
454
|
+
const isInterop = isInteropUser(jid)
|
|
455
|
+
const isGroupOrStatus = isGroup || isStatus
|
|
456
|
+
const finalJid = jid
|
|
457
|
+
msgId = msgId || generateMessageIDV2(meId)
|
|
458
|
+
useUserDevicesCache = useUserDevicesCache!== false
|
|
459
|
+
useCachedGroupMetadata = useCachedGroupMetadata!== false &&!isStatus
|
|
460
|
+
const participants = []
|
|
461
|
+
const destinationJid =!isStatus? finalJid : statusJid
|
|
462
|
+
const binaryNodeContent = []
|
|
463
|
+
const devices = []
|
|
464
|
+
let reportingMessage
|
|
465
|
+
const meMsg = {
|
|
466
|
+
deviceSentMessage: { destinationJid, message },
|
|
467
|
+
messageContextInfo: message.messageContextInfo
|
|
468
|
+
}
|
|
469
|
+
const extraAttrs = {}
|
|
470
|
+
const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/
|
|
471
|
+
const messages = normalizeMessageContent(message)
|
|
472
|
+
const buttonType = getButtonType(messages)
|
|
473
|
+
const pollMessage =
|
|
474
|
+
messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
|
|
475
|
+
await authState.keys.transaction(async () => {
|
|
476
|
+
const mediaType = getMediaType(message)
|
|
477
|
+
if (mediaType) extraAttrs.mediatype = mediaType
|
|
478
|
+
if (isNewsletter) {
|
|
479
|
+
const patched = patchMessageBeforeSending? await patchMessageBeforeSending(message, []) : message
|
|
480
|
+
const bytes = encodeNewsletterMessage(patched)
|
|
481
|
+
binaryNodeContent.push({ tag: 'plaintext', attrs: {}, content: bytes })
|
|
482
|
+
const stanza = {
|
|
483
|
+
tag: 'message',
|
|
484
|
+
attrs: {
|
|
485
|
+
to: jid,
|
|
486
|
+
id: msgId,
|
|
487
|
+
type: getMessageType(message),
|
|
488
|
+
...(additionalAttributes || {})
|
|
489
|
+
},
|
|
490
|
+
content: binaryNodeContent
|
|
491
|
+
}
|
|
492
|
+
logger.debug({ msgId }, `sending newsletter message to ${jid}`)
|
|
493
|
+
await sendNode(stanza)
|
|
494
|
+
return
|
|
495
|
+
}
|
|
496
|
+
if (normalizeMessageContent(message)?.pinInChatMessage || normalizeMessageContent(message)?.reactionMessage) {
|
|
497
|
+
extraAttrs['decrypt-fail'] = 'hide'
|
|
498
|
+
}
|
|
499
|
+
if (isGroupOrStatus &&!isRetryResend) {
|
|
500
|
+
const [groupData, senderKeyMap] = await Promise.all([
|
|
501
|
+
(async () => {
|
|
502
|
+
let groupData = useCachedGroupMetadata && cachedGroupMetadata? await cachedGroupMetadata(jid) : undefined
|
|
503
|
+
if (groupData && Array.isArray(groupData?.participants)) {
|
|
504
|
+
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
|
|
505
|
+
} else if (!isStatus) {
|
|
506
|
+
groupData = await groupMetadata(jid)
|
|
507
|
+
}
|
|
508
|
+
return groupData
|
|
509
|
+
})(),
|
|
510
|
+
(async () => {
|
|
511
|
+
if (!participant &&!isStatus) {
|
|
512
|
+
const result = await authState.keys.get('sender-key-memory', [jid])
|
|
513
|
+
return result[jid] || {}
|
|
514
|
+
}
|
|
515
|
+
return {}
|
|
516
|
+
})()
|
|
517
|
+
])
|
|
518
|
+
const participantsList = groupData? groupData.participants.map(p => p.id) : []
|
|
519
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
520
|
+
additionalAttributes = {...additionalAttributes, expiration: groupData.ephemeralDuration.toString() }
|
|
521
|
+
}
|
|
522
|
+
if (isStatus && statusJidList) participantsList.push(...statusJidList)
|
|
523
|
+
const additionalDevices = await getUSyncDevices(participantsList,!!useUserDevicesCache, false)
|
|
524
|
+
devices.push(...additionalDevices)
|
|
525
|
+
if (isGroup) {
|
|
526
|
+
additionalAttributes = {
|
|
527
|
+
...additionalAttributes,
|
|
528
|
+
addressing_mode: groupData?.addressingMode || 'lid'
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (message?.groupStatusMessageV2 &&!message?.messageContextInfo?.messageSecret) {
|
|
532
|
+
message = {
|
|
533
|
+
...message,
|
|
534
|
+
messageContextInfo: {
|
|
535
|
+
...(message.messageContextInfo || {}),
|
|
536
|
+
messageSecret: randomBytes(32)
|
|
537
|
+
},
|
|
538
|
+
groupStatusMessageV2: {
|
|
539
|
+
...message.groupStatusMessageV2,
|
|
540
|
+
message: {
|
|
541
|
+
...(message.groupStatusMessageV2.message || {}),
|
|
542
|
+
messageContextInfo: {
|
|
543
|
+
...(message.groupStatusMessageV2.message?.messageContextInfo || {}),
|
|
544
|
+
messageSecret: message.messageContextInfo?.messageSecret || randomBytes(32)
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// list/buttons/template -> interactiveMessage
|
|
551
|
+
if (message.listMessage) {
|
|
552
|
+
const list = message.listMessage
|
|
553
|
+
message = {
|
|
554
|
+
interactiveMessage: {
|
|
555
|
+
nativeFlowMessage: {
|
|
556
|
+
buttons: [
|
|
557
|
+
{
|
|
558
|
+
name: 'single_select',
|
|
559
|
+
buttonParamsJson: JSON.stringify({
|
|
560
|
+
title: list.buttonText || 'Select',
|
|
561
|
+
sections: (list.sections || []).map(section => ({
|
|
562
|
+
title: section.title || '',
|
|
563
|
+
highlight_label: '',
|
|
564
|
+
rows: (section.rows || []).map(row => ({
|
|
565
|
+
header: '',
|
|
566
|
+
title: row.title || '',
|
|
567
|
+
description: row.description || '',
|
|
568
|
+
id: row.rowId || row.id || ''
|
|
569
|
+
}))
|
|
570
|
+
}))
|
|
571
|
+
})
|
|
572
|
+
}
|
|
573
|
+
],
|
|
574
|
+
messageParamsJson: '',
|
|
575
|
+
messageVersion: 1
|
|
576
|
+
},
|
|
577
|
+
body: { text: list.description || '' },
|
|
578
|
+
footer: list.footerText? { text: list.footerText } : undefined,
|
|
579
|
+
header: list.title? { title: list.title, hasMediaAttachment: false, subtitle: '' } : undefined,
|
|
580
|
+
contextInfo: list.contextInfo
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
} else if (message.buttonsMessage) {
|
|
584
|
+
const bMsg = message.buttonsMessage
|
|
585
|
+
const buttons = (bMsg.buttons || []).map(btn => ({
|
|
586
|
+
name: 'quick_reply',
|
|
587
|
+
buttonParamsJson: JSON.stringify({
|
|
588
|
+
display_text: btn.buttonText?.displayText || btn.buttonText || '',
|
|
589
|
+
id: btn.buttonId || btn.buttonText?.displayText || ''
|
|
590
|
+
})
|
|
591
|
+
}))
|
|
592
|
+
message = {
|
|
593
|
+
interactiveMessage: {
|
|
594
|
+
nativeFlowMessage: { buttons, messageParamsJson: '', messageVersion: 1 },
|
|
595
|
+
body: { text: bMsg.contentText || bMsg.text || '' },
|
|
596
|
+
footer: bMsg.footerText? { text: bMsg.footerText } : undefined,
|
|
597
|
+
header: bMsg.text
|
|
598
|
+
? { title: bMsg.text, hasMediaAttachment: false, subtitle: '' }
|
|
599
|
+
: bMsg.imageMessage || bMsg.videoMessage || bMsg.documentMessage
|
|
600
|
+
? { hasMediaAttachment: true,...(bMsg.imageMessage? { imageMessage: bMsg.imageMessage } : {}),...(bMsg.videoMessage? { videoMessage: bMsg.videoMessage } : {}) }
|
|
601
|
+
: undefined,
|
|
602
|
+
contextInfo: bMsg.contextInfo
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
} else if (message.templateMessage) {
|
|
606
|
+
const tmpl = message.templateMessage.hydratedTemplate || message.templateMessage.fourRowTemplate
|
|
607
|
+
if (tmpl) {
|
|
608
|
+
const buttons = (tmpl.hydratedButtons || [])
|
|
609
|
+
.map(hBtn => {
|
|
610
|
+
if (hBtn.quickReplyButton) {
|
|
611
|
+
return { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: hBtn.quickReplyButton.displayText || '', id: hBtn.quickReplyButton.id || hBtn.quickReplyButton.displayText || '' }) }
|
|
612
|
+
} else if (hBtn.urlButton) {
|
|
613
|
+
return { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: hBtn.urlButton.displayText || '', url: hBtn.urlButton.url || '', merchant_url: hBtn.urlButton.url || '' }) }
|
|
614
|
+
} else if (hBtn.callButton) {
|
|
615
|
+
return { name: 'cta_call', buttonParamsJson: JSON.stringify({ display_text: hBtn.callButton.displayText || '', phone_number: hBtn.callButton.phoneNumber || '' }) }
|
|
616
|
+
}
|
|
617
|
+
return null
|
|
618
|
+
})
|
|
619
|
+
.filter(Boolean)
|
|
620
|
+
message = {
|
|
621
|
+
interactiveMessage: {
|
|
622
|
+
nativeFlowMessage: { buttons, messageParamsJson: '', messageVersion: 1 },
|
|
623
|
+
body: { text: tmpl.hydratedContentText || tmpl.contentText || '' },
|
|
624
|
+
footer: tmpl.hydratedFooterText? { text: tmpl.hydratedFooterText } : undefined,
|
|
625
|
+
header: tmpl.hydratedTitleText
|
|
626
|
+
? { title: tmpl.hydratedTitleText, hasMediaAttachment: false, subtitle: '' }
|
|
627
|
+
: tmpl.imageMessage || tmpl.videoMessage || tmpl.documentMessage
|
|
628
|
+
? { hasMediaAttachment: true,...(tmpl.imageMessage? { imageMessage: tmpl.imageMessage } : {}),...(tmpl.videoMessage? { videoMessage: tmpl.videoMessage } : {}) }
|
|
629
|
+
: undefined,
|
|
630
|
+
contextInfo: tmpl.contextInfo
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const patched = await patchMessageBeforeSending(message)
|
|
637
|
+
if (Array.isArray(patched)) throw new Boom('Per-jid patching is not supported in groups')
|
|
638
|
+
const bytes = encodeWAMessage(patched)
|
|
639
|
+
reportingMessage = patched
|
|
640
|
+
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid'
|
|
641
|
+
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid? meLid : meId
|
|
642
|
+
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
643
|
+
group: destinationJid,
|
|
644
|
+
data: bytes,
|
|
645
|
+
meId: groupSenderIdentity
|
|
646
|
+
})
|
|
647
|
+
const senderKeyRecipients = []
|
|
648
|
+
for (const device of devices) {
|
|
649
|
+
const deviceJid = device.jid
|
|
650
|
+
const hasKey =!!senderKeyMap[deviceJid]
|
|
651
|
+
if (!hasKey ||!!participant &&!isHostedLidUser(deviceJid) &&!isHostedPnUser(deviceJid) && device.device!== 99) {
|
|
652
|
+
senderKeyRecipients.push(deviceJid)
|
|
653
|
+
senderKeyMap[deviceJid] = true
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (senderKeyRecipients.length) {
|
|
657
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key')
|
|
658
|
+
const senderKeyMsg = {
|
|
659
|
+
senderKeyDistributionMessage: {
|
|
660
|
+
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
661
|
+
groupId: destinationJid
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
await assertSessions(senderKeyRecipients)
|
|
665
|
+
const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs)
|
|
666
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity
|
|
667
|
+
participants.push(...result.nodes)
|
|
668
|
+
}
|
|
669
|
+
binaryNodeContent.push({ tag: 'enc', attrs: { v: '2', type: 'skmsg',...extraAttrs }, content: ciphertext })
|
|
670
|
+
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
|
|
671
|
+
} else {
|
|
672
|
+
let ownId = meId
|
|
673
|
+
if (isLid && meLid) {
|
|
674
|
+
ownId = meLid
|
|
675
|
+
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation')
|
|
676
|
+
} else {
|
|
677
|
+
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
|
|
678
|
+
}
|
|
679
|
+
const { user: ownUser } = jidDecode(ownId)
|
|
680
|
+
if (!participant) {
|
|
681
|
+
const patchedForReporting = await patchMessageBeforeSending(message, [jid])
|
|
682
|
+
reportingMessage = Array.isArray(patchedForReporting)
|
|
683
|
+
? patchedForReporting.find(item => item.recipientJid === jid) || patchedForReporting[0]
|
|
684
|
+
: patchedForReporting
|
|
685
|
+
}
|
|
686
|
+
if (!isRetryResend) {
|
|
687
|
+
const targetUserServer = isLid? 'lid' : isInterop? 'interop' : 's.whatsapp.net'
|
|
688
|
+
devices.push({ user, device: 0, jid: jidEncode(user, targetUserServer, 0) })
|
|
689
|
+
if (user!== ownUser &&!isInterop) {
|
|
690
|
+
const ownUserServer = isLid? 'lid' : 's.whatsapp.net'
|
|
691
|
+
const ownUserForAddressing = isLid && meLid? jidDecode(meLid).user : jidDecode(meId).user
|
|
692
|
+
devices.push({ user: ownUserForAddressing, device: 0, jid: jidEncode(ownUserForAddressing, ownUserServer, 0) })
|
|
693
|
+
}
|
|
694
|
+
if (additionalAttributes?.['category']!== 'peer' &&!isInterop) {
|
|
695
|
+
devices.length = 0
|
|
696
|
+
const senderIdentity = isLid && meLid
|
|
697
|
+
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
698
|
+
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined)
|
|
699
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false)
|
|
700
|
+
devices.push(...sessionDevices)
|
|
701
|
+
logger.debug({ deviceCount: devices.length, devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`) }, 'Device enumeration complete with unified addressing')
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
const allRecipients = []
|
|
705
|
+
const meRecipients = []
|
|
706
|
+
const otherRecipients = []
|
|
707
|
+
const { user: mePnUser } = jidDecode(meId)
|
|
708
|
+
const { user: meLidUser } = meLid? jidDecode(meLid) : { user: null }
|
|
709
|
+
for (const { user, jid } of devices) {
|
|
710
|
+
/** participant method by Xzc || Tsm, who's delete the credits = love BBC */
|
|
711
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid)
|
|
647
712
|
if (isExactSenderDevice) {
|
|
648
|
-
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
|
|
649
|
-
continue
|
|
650
|
-
}
|
|
651
|
-
// Check if this is our device (could match either PN or LID user)
|
|
652
|
-
const isMe = user === mePnUser || user === meLidUser;
|
|
653
|
-
if (isMe) {
|
|
654
|
-
meRecipients.push(jid);
|
|
713
|
+
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
|
|
714
|
+
continue
|
|
655
715
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
// For own devices: use DSM if available (1:1 chats only)
|
|
664
|
-
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
665
|
-
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
666
|
-
]);
|
|
667
|
-
participants.push(...meNodes);
|
|
668
|
-
participants.push(...otherNodes);
|
|
669
|
-
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
670
|
-
extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
|
|
671
|
-
}
|
|
672
|
-
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
673
|
-
}
|
|
674
|
-
if (isRetryResend) {
|
|
675
|
-
const isParticipantLid = isLidUser(participant.jid);
|
|
676
|
-
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
|
|
677
|
-
let messageToSend = message;
|
|
678
|
-
if (isGroupOrStatus) {
|
|
679
|
-
let groupSenderIdentity;
|
|
680
|
-
if (meLid && (await signalRepository.hasSenderKey({ group: destinationJid, meId: meLid }))) {
|
|
681
|
-
groupSenderIdentity = meLid;
|
|
682
|
-
}
|
|
683
|
-
else if (await signalRepository.hasSenderKey({ group: destinationJid, meId })) {
|
|
684
|
-
groupSenderIdentity = meId;
|
|
685
|
-
}
|
|
686
|
-
if (groupSenderIdentity) {
|
|
687
|
-
try {
|
|
688
|
-
const skdm = await signalRepository.getSenderKeyDistributionMessage({
|
|
689
|
-
group: destinationJid,
|
|
690
|
-
meId: groupSenderIdentity
|
|
691
|
-
});
|
|
692
|
-
messageToSend = {
|
|
693
|
-
...message,
|
|
694
|
-
senderKeyDistributionMessage: {
|
|
695
|
-
groupId: destinationJid,
|
|
696
|
-
axolotlSenderKeyDistributionMessage: skdm
|
|
697
|
-
}
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
catch (err) {
|
|
701
|
-
logger.warn({ err, jid: destinationJid }, 'failed to build SKDM for retry, sending without it');
|
|
716
|
+
const isMe = user === mePnUser || user === meLidUser
|
|
717
|
+
let ptcp = false
|
|
718
|
+
if (participant) {
|
|
719
|
+
if (!isJidGroup(jid) && !isStatus) {
|
|
720
|
+
if (!(!isMe)) ptcp = true
|
|
721
|
+
} else {
|
|
722
|
+
ptcp = false
|
|
702
723
|
}
|
|
703
724
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
message: messageToSend
|
|
725
|
+
if (!ptcp) {
|
|
726
|
+
if (isMe) {
|
|
727
|
+
meRecipients.push(jid)
|
|
728
|
+
} else {
|
|
729
|
+
otherRecipients.push(jid)
|
|
710
730
|
}
|
|
711
|
-
|
|
712
|
-
: encodeWAMessage(messageToSend);
|
|
713
|
-
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
714
|
-
data: encodedMessageToSend,
|
|
715
|
-
jid: participant.jid
|
|
716
|
-
});
|
|
717
|
-
binaryNodeContent.push({
|
|
718
|
-
tag: 'enc',
|
|
719
|
-
attrs: {
|
|
720
|
-
v: '2',
|
|
721
|
-
type,
|
|
722
|
-
count: participant.count.toString()
|
|
723
|
-
},
|
|
724
|
-
content: encryptedContent
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
if (participants.length) {
|
|
728
|
-
if (additionalAttributes?.['category'] === 'peer') {
|
|
729
|
-
const peerNode = participants[0]?.content?.[0];
|
|
730
|
-
if (peerNode) {
|
|
731
|
-
binaryNodeContent.push(peerNode); // push only enc
|
|
731
|
+
allRecipients.push(jid)
|
|
732
732
|
}
|
|
733
733
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
734
|
+
await assertSessions(allRecipients)
|
|
735
|
+
const [
|
|
736
|
+
{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
|
|
737
|
+
{ nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }
|
|
738
|
+
] = await Promise.all([
|
|
739
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
740
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
741
|
+
])
|
|
742
|
+
participants.push(...meNodes,...otherNodes)
|
|
743
|
+
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
744
|
+
extraAttrs.phash = generateParticipantHashV2([...meRecipients,...otherRecipients])
|
|
745
|
+
}
|
|
746
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
|
747
|
+
}
|
|
748
|
+
if (isRetryResend) {
|
|
749
|
+
const isParticipantLid = jidDecode(participant.jid).server === 'lid'
|
|
750
|
+
const isMe = areJidsSameUser(participant.jid, isParticipantLid? meLid : meId)
|
|
751
|
+
const encodedMessageToSend = isMe
|
|
752
|
+
? encodeWAMessage({ deviceSentMessage: { destinationJid, message } })
|
|
753
|
+
: encodeWAMessage(message)
|
|
754
|
+
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
755
|
+
data: encodedMessageToSend,
|
|
756
|
+
jid: participant.jid
|
|
757
|
+
})
|
|
758
|
+
binaryNodeContent.push({
|
|
759
|
+
tag: 'enc',
|
|
760
|
+
attrs: { v: '2', type, count: (participant.count?? 0).toString() },
|
|
761
|
+
content: encryptedContent
|
|
762
|
+
})
|
|
763
|
+
}
|
|
764
|
+
if (participants.length) {
|
|
765
|
+
if (additionalAttributes?.['category'] === 'peer') {
|
|
766
|
+
const peerNode = participants[0]?.content?.[0]
|
|
767
|
+
if (peerNode) binaryNodeContent.push(peerNode)
|
|
768
|
+
} else if (isInterop) {
|
|
769
|
+
const recipientNode = participants.find(p => isInteropUser(p?.attrs?.jid))
|
|
770
|
+
const encNode = (recipientNode?? participants[0])?.content?.[0]
|
|
771
|
+
if (encNode) binaryNodeContent.push(encNode)
|
|
772
|
+
} else {
|
|
773
|
+
binaryNodeContent.push({ tag: 'participants', attrs: {}, content: participants })
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
const stanza = {
|
|
777
|
+
tag: 'message',
|
|
778
|
+
attrs: { id: msgId, to: destinationJid, type: getMessageType(message),...(additionalAttributes || {}) },
|
|
779
|
+
content: binaryNodeContent
|
|
780
|
+
}
|
|
781
|
+
if (shouldIncludeDeviceIdentity) {
|
|
782
|
+
stanza.content.push({ tag: 'device-identity', attrs: {}, content: encodeSignedDeviceIdentity(authState.creds.account, true) })
|
|
783
|
+
logger.debug({ jid }, 'adding device identity')
|
|
784
|
+
}
|
|
783
785
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
keys: authState.keys,
|
|
888
|
-
getLIDForPN
|
|
889
|
-
});
|
|
890
|
-
const currentData = await authState.keys.get('tctoken', [tcTokenJid]);
|
|
891
|
-
const currentEntry = currentData[tcTokenJid];
|
|
892
|
-
const indexWrite = await buildMergedTcTokenIndexWrite(authState.keys, [tcTokenJid]);
|
|
893
|
-
await authState.keys.set({
|
|
894
|
-
tctoken: {
|
|
895
|
-
[tcTokenJid]: {
|
|
896
|
-
token: Buffer.alloc(0),
|
|
897
|
-
...currentEntry,
|
|
898
|
-
senderTimestamp: issueTimestamp
|
|
899
|
-
},
|
|
900
|
-
...indexWrite
|
|
901
|
-
}
|
|
902
|
-
});
|
|
903
|
-
})
|
|
904
|
-
.catch(err => {
|
|
905
|
-
logger.debug({ jid: destinationJid, err: err?.message }, 'fire-and-forget tctoken issuance failed');
|
|
906
|
-
})
|
|
907
|
-
.finally(() => {
|
|
908
|
-
inFlightTcTokenIssuance.delete(tcTokenJid);
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
// Add message to retry cache if enabled
|
|
912
|
-
if (messageRetryManager && !participant) {
|
|
913
|
-
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
914
|
-
}
|
|
915
|
-
}, meId);
|
|
916
|
-
return msgId;
|
|
917
|
-
};
|
|
786
|
+
if (isGroup && regexGroupOld.test(jid) &&!message.reactionMessage) {
|
|
787
|
+
stanza.content.push({ tag: 'multicast', attrs: {} })
|
|
788
|
+
}
|
|
789
|
+
if (pollMessage || messages.eventMessage) {
|
|
790
|
+
stanza.content.push({
|
|
791
|
+
tag: 'meta',
|
|
792
|
+
attrs: messages.eventMessage
|
|
793
|
+
? { event_type: 'creation' }
|
|
794
|
+
: isNewsletter
|
|
795
|
+
? { polltype: 'creation', contenttype: pollMessage?.pollContentType === 2? 'image' : 'text' }
|
|
796
|
+
: { polltype: 'creation' }
|
|
797
|
+
})
|
|
798
|
+
}
|
|
799
|
+
if (!isNewsletter &&!isRetryResend && reportingMessage?.messageContextInfo?.messageSecret && shouldIncludeReportingToken(reportingMessage)) {
|
|
800
|
+
try {
|
|
801
|
+
const encoded = encodeWAMessage(reportingMessage)
|
|
802
|
+
const reportingKey = { id: msgId, fromMe: true, remoteJid: destinationJid, participant: participant?.jid }
|
|
803
|
+
const reportingNode = await getMessageReportingToken(encoded, reportingMessage, reportingKey)
|
|
804
|
+
if (reportingNode) {
|
|
805
|
+
stanza.content.push(reportingNode)
|
|
806
|
+
logger.trace({ jid }, 'added reporting token to message')
|
|
807
|
+
}
|
|
808
|
+
} catch (error) {
|
|
809
|
+
logger.warn({ jid, trace: error?.stack }, 'failed to attach reporting token')
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
let didPushAdditional = false
|
|
813
|
+
if (!isNewsletter && buttonType) {
|
|
814
|
+
const buttonsNode = getButtonArgs(messages)
|
|
815
|
+
const filteredButtons = getBinaryNodeFilter(additionalNodes? additionalNodes : [])
|
|
816
|
+
if (filteredButtons) {
|
|
817
|
+
stanza.content.push(...additionalNodes)
|
|
818
|
+
didPushAdditional = true
|
|
819
|
+
} else {
|
|
820
|
+
stanza.content.push(buttonsNode)
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
if (!aiLabel && isPnUser(destinationJid)) {
|
|
824
|
+
const alreadyHasBizBot = getBinaryFilteredBizBot(additionalNodes || []) || getBinaryFilteredBizBot(stanza.content)
|
|
825
|
+
if (!alreadyHasBizBot) stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
|
|
826
|
+
} else if (aiLabel &&!isGroup &&!isStatus &&!isNewsletter) {
|
|
827
|
+
const existingBizBot = getBinaryFilteredBizBot(additionalNodes || [])
|
|
828
|
+
if (!existingBizBot) stanza.content.push({ tag: 'bot', attrs: { biz_bot: '1' } })
|
|
829
|
+
}
|
|
830
|
+
const isPeerMessage = additionalAttributes?.['category'] === 'peer'
|
|
831
|
+
const is1on1Send =!isGroup &&!isRetryResend &&!isStatus &&!isNewsletter &&!isPeerMessage
|
|
832
|
+
const tcTokenJid = is1on1Send? await resolveTcTokenJid(destinationJid, getLIDForPN) : destinationJid
|
|
833
|
+
const contactTcTokenData = is1on1Send? await authState.keys.get('tctoken', [tcTokenJid]) : {}
|
|
834
|
+
const existingTokenEntry = contactTcTokenData[tcTokenJid]
|
|
835
|
+
let tcTokenBuffer = existingTokenEntry?.token
|
|
836
|
+
if (tcTokenBuffer?.length && isTcTokenExpired(existingTokenEntry?.timestamp)) {
|
|
837
|
+
logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing')
|
|
838
|
+
tcTokenBuffer = undefined
|
|
839
|
+
const cleared = existingTokenEntry?.senderTimestamp!== undefined? { token: Buffer.alloc(0), senderTimestamp: existingTokenEntry.senderTimestamp } : null
|
|
840
|
+
try {
|
|
841
|
+
await authState.keys.set({ tctoken: { [tcTokenJid]: cleared } })
|
|
842
|
+
} catch (err) {
|
|
843
|
+
logger.debug({ jid: destinationJid, err: err?.message }, 'failed to persist tctoken expiry cleanup')
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
if (tcTokenBuffer?.length && sock.serverProps.privacyTokenOn1to1) {
|
|
847
|
+
stanza.content.push({ tag: 'tctoken', attrs: {}, content: tcTokenBuffer })
|
|
848
|
+
}
|
|
849
|
+
if (additionalNodes && additionalNodes.length > 0 &&!didPushAdditional) {
|
|
850
|
+
stanza.content.push(...additionalNodes)
|
|
851
|
+
}
|
|
852
|
+
logger.debug({ msgId }, `sending message to ${participants.length} devices`)
|
|
853
|
+
await sendNode(stanza)
|
|
854
|
+
if (message.messageContextInfo?.messageSecret) {
|
|
855
|
+
setBotMessageSecret(msgId, message.messageContextInfo.messageSecret, destinationJid)
|
|
856
|
+
}
|
|
857
|
+
const isProtocolMsg =!!normalizeMessageContent(message)?.protocolMessage
|
|
858
|
+
const isBotOrPSA = destinationJid === PSA_WID || isJidBot(destinationJid) || isJidMetaAI(destinationJid)
|
|
859
|
+
if (is1on1Send &&!isProtocolMsg &&!isBotOrPSA && shouldSendNewTcToken(existingTokenEntry?.senderTimestamp) &&!inFlightTcTokenIssuance.has(tcTokenJid)) {
|
|
860
|
+
inFlightTcTokenIssuance.add(tcTokenJid)
|
|
861
|
+
const issueTimestamp = unixTimestampSeconds()
|
|
862
|
+
const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping)
|
|
863
|
+
resolveIssuanceJid(destinationJid, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID)
|
|
864
|
+
.then(issueJid => issuePrivacyTokens([issueJid], issueTimestamp))
|
|
865
|
+
.then(async result => {
|
|
866
|
+
await storeTcTokensFromIqResult({ result, fallbackJid: tcTokenJid, keys: authState.keys, getLIDForPN })
|
|
867
|
+
const currentData = await authState.keys.get('tctoken', [tcTokenJid])
|
|
868
|
+
const currentEntry = currentData[tcTokenJid]
|
|
869
|
+
const indexWrite = await buildMergedTcTokenIndexWrite(authState.keys, [tcTokenJid])
|
|
870
|
+
await authState.keys.set({
|
|
871
|
+
tctoken: {
|
|
872
|
+
[tcTokenJid]: { token: Buffer.alloc(0),...currentEntry, senderTimestamp: issueTimestamp },
|
|
873
|
+
...indexWrite
|
|
874
|
+
}
|
|
875
|
+
})
|
|
876
|
+
})
|
|
877
|
+
.catch(err => logger.debug({ jid: destinationJid, err: err?.message }, 'fire-and-forget tctoken issuance failed'))
|
|
878
|
+
.finally(() => inFlightTcTokenIssuance.delete(tcTokenJid))
|
|
879
|
+
}
|
|
880
|
+
if (messageRetryManager &&!participant) {
|
|
881
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message)
|
|
882
|
+
}
|
|
883
|
+
if (isInterop &&!isRetryResend) {
|
|
884
|
+
await trustInteropContact(destinationJid).catch(err => logger.debug({ err, jid: destinationJid }, 'failed to trust interop contact'))
|
|
885
|
+
}
|
|
886
|
+
}, meId)
|
|
887
|
+
return msgId
|
|
888
|
+
}
|
|
918
889
|
const getMessageType = (message) => {
|
|
919
890
|
const normalizedMessage = normalizeMessageContent(message);
|
|
920
891
|
if (!normalizedMessage)
|
|
@@ -924,8 +895,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
924
895
|
}
|
|
925
896
|
if (normalizedMessage.pollCreationMessage ||
|
|
926
897
|
normalizedMessage.pollCreationMessageV2 ||
|
|
927
|
-
|
|
928
|
-
|
|
898
|
+
normalizedMessage.pollCreationMessageV3 ||
|
|
899
|
+
normalizedMessage.pollCreationMessageV4 ||
|
|
900
|
+
normalizedMessage.pollCreationMessageV5 ||
|
|
901
|
+
normalizedMessage.pollUpdateMessage) {
|
|
929
902
|
return 'poll';
|
|
930
903
|
}
|
|
931
904
|
if (normalizedMessage.eventMessage) {
|
|
@@ -1007,6 +980,9 @@ export const makeMessagesSocket = (config) => {
|
|
|
1007
980
|
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'payment_method') {
|
|
1008
981
|
return 'payment_method'
|
|
1009
982
|
}
|
|
983
|
+
else if (message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name === 'catalog_message') {
|
|
984
|
+
return 'catalog_message'
|
|
985
|
+
}
|
|
1010
986
|
else if (message.interactiveMessage && message.interactiveMessage?.nativeFlowMessage) {
|
|
1011
987
|
return 'interactive'
|
|
1012
988
|
}
|
|
@@ -1014,6 +990,128 @@ export const makeMessagesSocket = (config) => {
|
|
|
1014
990
|
return 'native_flow'
|
|
1015
991
|
}
|
|
1016
992
|
};
|
|
993
|
+
const getButtonArgs = (message) => {
|
|
994
|
+
const nativeFlow = message.interactiveMessage?.nativeFlowMessage
|
|
995
|
+
const firstButtonName = nativeFlow?.buttons?.[0]?.name
|
|
996
|
+
const nativeFlowSpecials = [
|
|
997
|
+
'mpm',
|
|
998
|
+
'cta_catalog',
|
|
999
|
+
'send_location',
|
|
1000
|
+
'call_permission_request',
|
|
1001
|
+
'wa_payment_transaction_details',
|
|
1002
|
+
'automated_greeting_message_view_catalog'
|
|
1003
|
+
]
|
|
1004
|
+
|
|
1005
|
+
if (nativeFlow && (firstButtonName === 'review_and_pay' || firstButtonName === 'payment_info')) {
|
|
1006
|
+
return {
|
|
1007
|
+
tag: 'biz',
|
|
1008
|
+
attrs: {
|
|
1009
|
+
native_flow_name: firstButtonName === 'review_and_pay' ? 'order_details' : firstButtonName
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
} else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
|
|
1013
|
+
// Only works for WhatsApp Original, not WhatsApp Business
|
|
1014
|
+
return {
|
|
1015
|
+
tag: 'biz',
|
|
1016
|
+
attrs: {
|
|
1017
|
+
actual_actors: '2',
|
|
1018
|
+
host_storage: '2',
|
|
1019
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1020
|
+
},
|
|
1021
|
+
content: [
|
|
1022
|
+
{
|
|
1023
|
+
tag: 'interactive',
|
|
1024
|
+
attrs: {
|
|
1025
|
+
type: 'native_flow',
|
|
1026
|
+
v: '1'
|
|
1027
|
+
},
|
|
1028
|
+
content: [
|
|
1029
|
+
{
|
|
1030
|
+
tag: 'native_flow',
|
|
1031
|
+
attrs: {
|
|
1032
|
+
v: '2',
|
|
1033
|
+
name: firstButtonName
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
]
|
|
1037
|
+
},
|
|
1038
|
+
{
|
|
1039
|
+
tag: 'quality_control',
|
|
1040
|
+
attrs: {
|
|
1041
|
+
source_type: 'third_party'
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
]
|
|
1045
|
+
}
|
|
1046
|
+
} else if (nativeFlow || message.buttonsMessage) {
|
|
1047
|
+
// It works for whatsapp original and whatsapp business
|
|
1048
|
+
return {
|
|
1049
|
+
tag: 'biz',
|
|
1050
|
+
attrs: {
|
|
1051
|
+
actual_actors: '2',
|
|
1052
|
+
host_storage: '2',
|
|
1053
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1054
|
+
},
|
|
1055
|
+
content: [
|
|
1056
|
+
{
|
|
1057
|
+
tag: 'interactive',
|
|
1058
|
+
attrs: {
|
|
1059
|
+
type: 'native_flow',
|
|
1060
|
+
v: '1'
|
|
1061
|
+
},
|
|
1062
|
+
content: [
|
|
1063
|
+
{
|
|
1064
|
+
tag: 'native_flow',
|
|
1065
|
+
attrs: {
|
|
1066
|
+
v: '9',
|
|
1067
|
+
name: 'mixed'
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
]
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
tag: 'quality_control',
|
|
1074
|
+
attrs: {
|
|
1075
|
+
source_type: 'third_party'
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
]
|
|
1079
|
+
}
|
|
1080
|
+
} else if (message.listMessage) {
|
|
1081
|
+
return {
|
|
1082
|
+
tag: 'biz',
|
|
1083
|
+
attrs: {
|
|
1084
|
+
actual_actors: '2',
|
|
1085
|
+
host_storage: '2',
|
|
1086
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1087
|
+
},
|
|
1088
|
+
content: [
|
|
1089
|
+
{
|
|
1090
|
+
tag: 'list',
|
|
1091
|
+
attrs: {
|
|
1092
|
+
v: '2',
|
|
1093
|
+
type: 'product_list'
|
|
1094
|
+
}
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
tag: 'quality_control',
|
|
1098
|
+
attrs: {
|
|
1099
|
+
source_type: 'third_party'
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
]
|
|
1103
|
+
}
|
|
1104
|
+
} else {
|
|
1105
|
+
return {
|
|
1106
|
+
tag: 'biz',
|
|
1107
|
+
attrs: {
|
|
1108
|
+
actual_actors: '2',
|
|
1109
|
+
host_storage: '2',
|
|
1110
|
+
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1017
1115
|
const issuePrivacyTokens = async (jids, timestamp) => {
|
|
1018
1116
|
const t = (timestamp ?? unixTimestampSeconds()).toString();
|
|
1019
1117
|
const result = await query({
|
|
@@ -1113,10 +1211,61 @@ export const makeMessagesSocket = (config) => {
|
|
|
1113
1211
|
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
1114
1212
|
return message;
|
|
1115
1213
|
},
|
|
1214
|
+
sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
|
|
1215
|
+
const { message, messageId } = Utils_1.generateTableContent(title, headers, rows, quoted, options)
|
|
1216
|
+
await relayMessage(jid, message, { messageId })
|
|
1217
|
+
return { message, messageId }
|
|
1218
|
+
},
|
|
1219
|
+
sendList: async (jid, title, items, quoted, options = {}) => {
|
|
1220
|
+
const { message, messageId } = Utils_1.generateListContent(title, items, quoted, options)
|
|
1221
|
+
await relayMessage(jid, message, { messageId })
|
|
1222
|
+
return { message, messageId }
|
|
1223
|
+
},
|
|
1224
|
+
sendCodeBlock: async (jid, code, quoted, options = {}) => {
|
|
1225
|
+
const { message, messageId } = Utils_1.generateCodeBlockContent(code, quoted, options)
|
|
1226
|
+
await relayMessage(jid, message, { messageId })
|
|
1227
|
+
return { message, messageId }
|
|
1228
|
+
},
|
|
1229
|
+
sendLatex: async (jid, quoted, options) => {
|
|
1230
|
+
const { message, messageId } = Utils_1.generateLatexContent(quoted, options)
|
|
1231
|
+
await relayMessage(jid, message, { messageId })
|
|
1232
|
+
return { message, messageId }
|
|
1233
|
+
},
|
|
1234
|
+
sendLatexImage: async (jid, quoted, options, renderLatexToPng, uploadFn) => {
|
|
1235
|
+
const { message, messageId } = await Utils_1.generateLatexImageContent(
|
|
1236
|
+
quoted,
|
|
1237
|
+
options,
|
|
1238
|
+
uploadFn,
|
|
1239
|
+
renderLatexToPng
|
|
1240
|
+
)
|
|
1241
|
+
await relayMessage(jid, message, { messageId })
|
|
1242
|
+
return { message, messageId }
|
|
1243
|
+
},
|
|
1244
|
+
sendLatexInlineImage: async (jid, quoted, options, renderLatexToPng, uploadFn) => {
|
|
1245
|
+
const { message, messageId } = await Utils_1.generateLatexInlineImageContent(
|
|
1246
|
+
quoted,
|
|
1247
|
+
options,
|
|
1248
|
+
uploadFn,
|
|
1249
|
+
renderLatexToPng
|
|
1250
|
+
)
|
|
1251
|
+
await relayMessage(jid, message, { messageId })
|
|
1252
|
+
return { message, messageId }
|
|
1253
|
+
},
|
|
1254
|
+
captureUnifiedResponse: Utils_1.captureUnifiedResponse,
|
|
1255
|
+
sendUnifiedResponse: async (jid, quoted, captured) => {
|
|
1256
|
+
const { message, messageId } = Utils_1.generateUnifiedResponseContent(quoted, captured)
|
|
1257
|
+
await relayMessage(jid, message, { messageId })
|
|
1258
|
+
return { message, messageId }
|
|
1259
|
+
},
|
|
1260
|
+
sendRichMessage: async (jid, submessages, quoted, options = {}) => {
|
|
1261
|
+
const { message, messageId } = Utils_1.generateRichMessageContent(submessages, quoted, options)
|
|
1262
|
+
await relayMessage(jid, message, { messageId })
|
|
1263
|
+
return { message, messageId }
|
|
1264
|
+
},
|
|
1116
1265
|
sendMessage: async (jid, content, options = {}) => {
|
|
1117
1266
|
const userJid = authState.creds.me.id;
|
|
1118
1267
|
const luki = new imup(Utils_1, waUploadToServer, relayMessage)
|
|
1119
|
-
const { quoted } = options;
|
|
1268
|
+
const { quoted, participant = false } = options;
|
|
1120
1269
|
const messageType = luki.detectType(content);
|
|
1121
1270
|
if (typeof content === 'object' &&
|
|
1122
1271
|
'disappearingMessagesInChat' in content &&
|
|
@@ -1144,13 +1293,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1144
1293
|
return await relayMessage(jid, productMsg.message, {
|
|
1145
1294
|
messageId: productMsg.key.id,
|
|
1146
1295
|
});
|
|
1147
|
-
|
|
1148
|
-
case 'INTERACTIVE':
|
|
1149
|
-
const interactiveContent = await luki.handleInteractive(content, jid, quoted);
|
|
1150
|
-
const interactiveMsg = await Utils_1.generateWAMessageFromContent(jid, interactiveContent, { quoted });
|
|
1151
|
-
return await relayMessage(jid, interactiveMsg.message, {
|
|
1152
|
-
messageId: interactiveMsg.key.id
|
|
1153
|
-
});
|
|
1296
|
+
|
|
1154
1297
|
case 'ALBUM':
|
|
1155
1298
|
return await luki.handleAlbum(content, jid, quoted)
|
|
1156
1299
|
case 'EVENT':
|
|
@@ -1230,7 +1373,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
1230
1373
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1231
1374
|
additionalAttributes,
|
|
1232
1375
|
statusJidList: options.statusJidList,
|
|
1233
|
-
additionalNodes: aiLabel ? additionalNodes : options.additionalNodes
|
|
1376
|
+
additionalNodes: aiLabel ? additionalNodes : options.additionalNodes,
|
|
1377
|
+
participant
|
|
1234
1378
|
});
|
|
1235
1379
|
if (config.emitOwnEvents) {
|
|
1236
1380
|
process.nextTick(async () => {
|