@fhynella/baileys 2.0.5 → 2.1.7
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/connection.js +51 -0
- package/lib/Defaults/constants.js +62 -0
- package/lib/Defaults/history.js +17 -0
- package/lib/Defaults/index.js +36 -142
- package/lib/Defaults/media.js +48 -0
- package/lib/Defaults/prefix.js +18 -0
- package/lib/Signal/Group/group-session-builder.js +10 -42
- package/lib/Signal/Group/group_cipher.js +9 -6
- package/lib/Signal/Group/index.js +39 -53
- package/lib/Signal/Group/keyhelper.js +8 -41
- package/lib/Signal/Group/sender-chain-key.js +4 -4
- package/lib/Signal/Group/sender-key-distribution-message.js +5 -5
- package/lib/Signal/Group/sender-key-message.js +12 -8
- package/lib/Signal/Group/sender-key-record.js +7 -7
- package/lib/Signal/Group/sender-key-state.js +4 -4
- package/lib/Signal/Group/sender-message-key.js +2 -2
- package/lib/Signal/libsignal.js +45 -69
- package/lib/Signal/lid-mapping.js +15 -11
- package/lib/Socket/Client/types.js +2 -2
- package/lib/Socket/Client/websocket.js +16 -14
- package/lib/Socket/business.js +41 -32
- package/lib/Socket/chats.js +123 -98
- package/lib/Socket/community.js +50 -40
- package/lib/Socket/groups.js +59 -47
- package/lib/Socket/index.js +4 -4
- package/lib/Socket/messages-recv.js +219 -172
- package/lib/Socket/messages-send.js +187 -211
- package/lib/Socket/newsletter.js +61 -47
- package/lib/Socket/socket.js +133 -90
- package/lib/Socket/usync.js +6 -6
- package/lib/Store/index.js +27 -11
- package/lib/Store/make-cache-manager-store.js +14 -15
- package/lib/Store/make-in-memory-store.js +28 -24
- package/lib/Types/LabelAssociation.js +2 -2
- package/lib/Types/Message.js +6 -6
- package/lib/Types/MexUpdates.js +5 -5
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +28 -12
- package/lib/Utils/auth-utils.js +28 -26
- package/lib/Utils/baileys-event-stream.js +68 -69
- package/lib/Utils/business.js +63 -53
- package/lib/Utils/chat-utils.js +81 -71
- package/lib/Utils/crypto.js +25 -45
- package/lib/Utils/decode-wa-message.js +319 -311
- package/lib/Utils/event-buffer.js +21 -22
- package/lib/Utils/generics.js +52 -75
- package/lib/Utils/history.js +21 -21
- package/lib/Utils/index.js +27 -13
- package/lib/Utils/link-preview.js +7 -30
- package/lib/Utils/logger.js +5 -5
- package/lib/Utils/lt-hash.js +3 -3
- package/lib/Utils/message-retry-manager.js +4 -4
- package/lib/Utils/messages-media.js +104 -109
- package/lib/Utils/messages.js +203 -171
- package/lib/Utils/noise-handler.js +28 -19
- package/lib/Utils/process-message.js +111 -96
- package/lib/Utils/signal.js +36 -25
- package/lib/Utils/use-multi-file-auth-state.js +18 -22
- package/lib/Utils/validate-connection.js +52 -45
- package/lib/WABinary/decode.js +6 -32
- package/lib/WABinary/encode.js +3 -29
- package/lib/WABinary/generic-utils.js +4 -4
- package/lib/WABinary/index.js +27 -11
- package/lib/WAM/encode.js +16 -8
- package/lib/WAM/index.js +27 -11
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +20 -16
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +7 -4
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -2
- package/lib/WAUSync/Protocols/index.js +27 -11
- package/lib/WAUSync/USyncQuery.js +17 -10
- package/lib/WAUSync/index.js +27 -11
- package/lib/index.js +60 -31
- package/package.json +15 -6
- package/WAProto/AICommon/AICommon.d.ts +0 -11702
- package/WAProto/Adv/Adv.d.ts +0 -643
- package/WAProto/BotMetadata/BotMetadata.d.ts +0 -5654
- package/WAProto/Cert/Cert.d.ts +0 -613
- package/WAProto/ChatLockSettings/ChatLockSettings.d.ts +0 -476
- package/WAProto/CompanionReg/CompanionReg.d.ts +0 -1361
- package/WAProto/DeviceCapabilities/DeviceCapabilities.d.ts +0 -577
- package/WAProto/E2E/E2E.d.ts +0 -41724
- package/WAProto/Ephemeral/Ephemeral.d.ts +0 -114
- package/WAProto/HistorySync/HistorySync.d.ts +0 -51700
- package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.d.ts +0 -229
- package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.d.ts +0 -583
- package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.d.ts +0 -42897
- package/WAProto/MmsRetry/MmsRetry.d.ts +0 -243
- package/WAProto/Protocol/Protocol.d.ts +0 -270
- package/WAProto/Reporting/Reporting.d.ts +0 -371
- package/WAProto/ServerSync/ServerSync.d.ts +0 -1285
- package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.d.ts +0 -1868
- package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.d.ts +0 -767
- package/WAProto/StatusAttributions/StatusAttributions.d.ts +0 -1027
- package/WAProto/SyncAction/SyncAction.d.ts +0 -11193
- package/WAProto/UserPassword/UserPassword.d.ts +0 -363
- package/WAProto/VnameCert/VnameCert.d.ts +0 -821
- package/WAProto/Wa6/Wa6.d.ts +0 -2128
- package/WAProto/Web/Web.d.ts +0 -46383
- package/WAProto/index.d.ts +0 -55
- package/lib/Defaults/index.d.ts +0 -77
- package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
- package/lib/Signal/Group/group-session-builder.d.ts +0 -17
- package/lib/Signal/Group/group_cipher.d.ts +0 -19
- package/lib/Signal/Group/index.d.ts +0 -11
- package/lib/Signal/Group/keyhelper.d.ts +0 -16
- 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 -19
- package/lib/Signal/Group/sender-key-record.d.ts +0 -32
- package/lib/Signal/Group/sender-key-state.d.ts +0 -44
- package/lib/Signal/Group/sender-message-key.d.ts +0 -11
- package/lib/Signal/libsignal.d.ts +0 -8
- package/lib/Signal/lid-mapping.d.ts +0 -28
- package/lib/Socket/.nomedia +0 -0
- package/lib/Socket/Client/index.d.ts +0 -2
- 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 -187
- package/lib/Socket/chats.d.ts +0 -97
- package/lib/Socket/community.d.ts +0 -129
- package/lib/Socket/groups.d.ts +0 -129
- package/lib/Socket/index.d.ts +0 -197
- package/lib/Socket/messages-recv.d.ts +0 -180
- package/lib/Socket/messages-send.d.ts +0 -169
- package/lib/Socket/messages-send.d.ts.bak +0 -165
- package/lib/Socket/messages-send.js.bak +0 -1812
- package/lib/Socket/newsletter.d.ts +0 -145
- package/lib/Socket/socket.d.ts +0 -45
- package/lib/Socket/usync.d.ts +0 -37
- package/lib/Store/index.d.ts +0 -4
- package/lib/Store/make-cache-manager-store.d.ts +0 -14
- package/lib/Store/make-in-memory-store.d.ts +0 -123
- package/lib/Store/make-ordered-dictionary.d.ts +0 -12
- package/lib/Store/object-repository.d.ts +0 -10
- package/lib/Types/Auth.d.ts +0 -121
- package/lib/Types/Bussiness.d.ts +0 -28
- package/lib/Types/Call.d.ts +0 -14
- package/lib/Types/Chat.d.ts +0 -143
- package/lib/Types/Contact.d.ts +0 -23
- package/lib/Types/Events.d.ts +0 -226
- package/lib/Types/GroupMetadata.d.ts +0 -66
- package/lib/Types/Label.d.ts +0 -48
- package/lib/Types/LabelAssociation.d.ts +0 -35
- package/lib/Types/Message.d.ts +0 -484
- package/lib/Types/MexUpdates.d.ts +0 -9
- package/lib/Types/Newsletter.d.ts +0 -109
- package/lib/Types/Product.d.ts +0 -92
- package/lib/Types/Signal.d.ts +0 -98
- package/lib/Types/Socket.d.ts +0 -141
- package/lib/Types/State.d.ts +0 -41
- package/lib/Types/USync.d.ts +0 -26
- package/lib/Types/index.d.ts +0 -80
- package/lib/Utils/auth-utils.d.ts +0 -21
- package/lib/Utils/baileys-event-stream.d.ts +0 -18
- package/lib/Utils/business.d.ts +0 -29
- package/lib/Utils/chat-utils.d.ts +0 -82
- package/lib/Utils/crypto.d.ts +0 -56
- package/lib/Utils/decode-wa-message.d.ts +0 -53
- package/lib/Utils/event-buffer.d.ts +0 -39
- package/lib/Utils/generics.d.ts +0 -117
- package/lib/Utils/history.d.ts +0 -23
- package/lib/Utils/index.d.ts +0 -20
- package/lib/Utils/link-preview.d.ts +0 -23
- package/lib/Utils/logger.d.ts +0 -13
- package/lib/Utils/lt-hash.d.ts +0 -14
- package/lib/Utils/make-mutex.d.ts +0 -9
- package/lib/Utils/message-retry-manager.d.ts +0 -88
- package/lib/Utils/messages-media.d.ts +0 -135
- package/lib/Utils/messages.d.ts +0 -105
- package/lib/Utils/noise-handler.d.ts +0 -20
- package/lib/Utils/process-message.d.ts +0 -49
- package/lib/Utils/signal.d.ts +0 -42
- package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
- package/lib/Utils/use-mongo-file-auth-state.js +0 -84
- package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
- package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
- package/lib/Utils/use-single-file-auth-state.js +0 -80
- package/lib/Utils/validate-connection.d.ts +0 -13
- package/lib/WABinary/constants.d.ts +0 -30
- package/lib/WABinary/decode.d.ts +0 -9
- package/lib/WABinary/encode.d.ts +0 -3
- package/lib/WABinary/generic-utils.d.ts +0 -28
- package/lib/WABinary/index.d.ts +0 -5
- package/lib/WABinary/jid-utils.d.ts +0 -58
- package/lib/WABinary/types.d.ts +0 -22
- package/lib/WAM/BinaryInfo.d.ts +0 -16
- package/lib/WAM/constants.d.ts +0 -47
- package/lib/WAM/encode.d.ts +0 -3
- package/lib/WAM/index.d.ts +0 -3
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +0 -28
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -26
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -14
- package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -14
- package/lib/WAUSync/Protocols/index.d.ts +0 -6
- package/lib/WAUSync/USyncQuery.d.ts +0 -31
- package/lib/WAUSync/USyncUser.d.ts +0 -12
- package/lib/WAUSync/index.d.ts +0 -3
- package/lib/index.d.ts +0 -13
|
@@ -1,1812 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod }
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true })
|
|
8
|
-
|
|
9
|
-
const node_cache_1 = __importDefault(require("@cacheable/node-cache"))
|
|
10
|
-
const boom_1 = require("@hapi/boom")
|
|
11
|
-
const crypto_1 = require("crypto")
|
|
12
|
-
const WAProto_1 = require("../../WAProto")
|
|
13
|
-
const Defaults_1 = require("../Defaults")
|
|
14
|
-
const Utils_1 = require("../Utils")
|
|
15
|
-
const Types_1 = require("../Types")
|
|
16
|
-
const WABinary_1 = require("../WABinary")
|
|
17
|
-
const WAUSync_1 = require("../WAUSync")
|
|
18
|
-
const newsletter_1 = require("./newsletter")
|
|
19
|
-
const link_preview_1 = require("../Utils/link-preview")
|
|
20
|
-
const make_keyed_mutex_1 = require("../Utils/make-mutex")
|
|
21
|
-
|
|
22
|
-
const makeMessagesSocket = (config) => {
|
|
23
|
-
const { logger, maxMsgRetryCount, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache } = config
|
|
24
|
-
const suki = newsletter_1.makeNewsletterSocket(config)
|
|
25
|
-
const { ev, authState, processingMutex, signalRepository, upsertMessage, createCallLink, query, fetchPrivacySettings, sendNode, groupQuery, groupMetadata, groupToggleEphemeral, newsletterWMexQuery, executeUSyncQuery } = suki
|
|
26
|
-
|
|
27
|
-
const userDevicesCache = config.userDevicesCache || new node_cache_1.default({
|
|
28
|
-
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
29
|
-
useClones: false
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
// Initialize message retry manager if enabled
|
|
33
|
-
const messageRetryManager = enableRecentMessageCache ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount) : null
|
|
34
|
-
|
|
35
|
-
// Prevent race conditions in Signal session encryption by user
|
|
36
|
-
const encryptionMutex = make_keyed_mutex_1.makeKeyedMutex()
|
|
37
|
-
|
|
38
|
-
let mediaConn
|
|
39
|
-
|
|
40
|
-
const refreshMediaConn = async (forceGet = false) => {
|
|
41
|
-
const media = await mediaConn
|
|
42
|
-
|
|
43
|
-
if (!media || forceGet || (new Date().getTime() - media.fetchDate.getTime()) > media.ttl * 1000) {
|
|
44
|
-
mediaConn = (async () => {
|
|
45
|
-
|
|
46
|
-
const result = await query({
|
|
47
|
-
tag: 'iq',
|
|
48
|
-
attrs: {
|
|
49
|
-
type: 'set',
|
|
50
|
-
xmlns: 'w:m',
|
|
51
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
52
|
-
},
|
|
53
|
-
content: [{ tag: 'media_conn', attrs: {} }]
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
const mediaConnNode = WABinary_1.getBinaryNodeChild(result, 'media_conn')
|
|
57
|
-
|
|
58
|
-
const node = {
|
|
59
|
-
hosts: WABinary_1.getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
60
|
-
hostname: attrs.hostname,
|
|
61
|
-
maxContentLengthBytes: +attrs.maxContentLengthBytes,
|
|
62
|
-
})),
|
|
63
|
-
auth: mediaConnNode.attrs.auth,
|
|
64
|
-
ttl: +mediaConnNode.attrs.ttl,
|
|
65
|
-
fetchDate: new Date()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
logger.debug('fetched media conn')
|
|
69
|
-
|
|
70
|
-
return node
|
|
71
|
-
})()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return mediaConn
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* generic send receipt function
|
|
79
|
-
* used for receipts of phone call, read, delivery etc.
|
|
80
|
-
* */
|
|
81
|
-
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
82
|
-
const node = {
|
|
83
|
-
tag: 'receipt',
|
|
84
|
-
attrs: {
|
|
85
|
-
id: messageIds[0],
|
|
86
|
-
},
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const isReadReceipt = type === 'read' || type === 'read-self'
|
|
90
|
-
|
|
91
|
-
if (isReadReceipt) {
|
|
92
|
-
node.attrs.t = Utils_1.unixTimestampSeconds().toString()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (type === 'sender' && WABinary_1.isJidUser(jid)) {
|
|
96
|
-
node.attrs.recipient = jid
|
|
97
|
-
node.attrs.to = participant
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
else {
|
|
101
|
-
node.attrs.to = jid
|
|
102
|
-
if (participant) {
|
|
103
|
-
node.attrs.participant = participant
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (type) {
|
|
108
|
-
node.attrs.type = WABinary_1.isJidNewsletter(jid) ? 'read-self' : type
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const remainingMessageIds = messageIds.slice(1)
|
|
112
|
-
|
|
113
|
-
if (remainingMessageIds.length) {
|
|
114
|
-
node.content = [
|
|
115
|
-
{
|
|
116
|
-
tag: 'list',
|
|
117
|
-
attrs: {},
|
|
118
|
-
content: remainingMessageIds.map(id => ({
|
|
119
|
-
tag: 'item',
|
|
120
|
-
attrs: { id }
|
|
121
|
-
}))
|
|
122
|
-
}
|
|
123
|
-
]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages')
|
|
127
|
-
|
|
128
|
-
await sendNode(node)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Correctly bulk send receipts to multiple chats, participants */
|
|
132
|
-
const sendReceipts = async (keys, type) => {
|
|
133
|
-
const recps = Utils_1.aggregateMessageKeysNotFromMe(keys)
|
|
134
|
-
|
|
135
|
-
for (const { jid, participant, messageIds } of recps) {
|
|
136
|
-
await sendReceipt(jid, participant, messageIds, type)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Bulk read messages. Keys can be from different chats & participants */
|
|
141
|
-
const readMessages = async (keys) => {
|
|
142
|
-
const privacySettings = await fetchPrivacySettings()
|
|
143
|
-
|
|
144
|
-
// based on privacy settings, we have to change the read type
|
|
145
|
-
const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self'
|
|
146
|
-
|
|
147
|
-
await sendReceipts(keys, readType)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Deduplicate JIDs when both LID and PN versions exist for same user
|
|
152
|
-
* Prefers LID over PN to maintain single encryption layer
|
|
153
|
-
*/
|
|
154
|
-
const deduplicateLidPnJids = (jids) => {
|
|
155
|
-
const lidUsers = new Set()
|
|
156
|
-
const filteredJids = []
|
|
157
|
-
|
|
158
|
-
// Collect all LID users
|
|
159
|
-
for (const jid of jids) {
|
|
160
|
-
if (WABinary_1.isLidUser(jid)) {
|
|
161
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
162
|
-
if (user)
|
|
163
|
-
lidUsers.add(user)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Filter out PN versions when LID exists
|
|
168
|
-
for (const jid of jids) {
|
|
169
|
-
if (WABinary_1.isJidUser(jid)) {
|
|
170
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
171
|
-
if (user && lidUsers.has(user)) {
|
|
172
|
-
logger.debug({ jid }, 'Skipping PN - LID version exists')
|
|
173
|
-
continue
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
filteredJids.push(jid)
|
|
177
|
-
}
|
|
178
|
-
return filteredJids
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/** Fetch image for groups, user, and newsletter **/
|
|
182
|
-
const profilePictureUrl = async (jid) => {
|
|
183
|
-
if (WABinary_1.isJidNewsletter(jid)) {
|
|
184
|
-
|
|
185
|
-
let node = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
|
|
186
|
-
input: {
|
|
187
|
-
key: jid,
|
|
188
|
-
type: 'JID',
|
|
189
|
-
view_role: 'GUEST'
|
|
190
|
-
},
|
|
191
|
-
fetch_viewer_metadata: true,
|
|
192
|
-
fetch_full_image: true,
|
|
193
|
-
fetch_creation_time: true
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
let result = WABinary_1.getBinaryNodeChild(node, 'result')?.content?.toString()
|
|
197
|
-
|
|
198
|
-
let metadata = JSON.parse(result).data[Types_1.XWAPaths.NEWSLETTER]
|
|
199
|
-
|
|
200
|
-
return Utils_1.getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
else {
|
|
205
|
-
const result = await query({
|
|
206
|
-
tag: 'iq',
|
|
207
|
-
attrs: {
|
|
208
|
-
target: WABinary_1.jidNormalizedUser(jid),
|
|
209
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
210
|
-
type: 'get',
|
|
211
|
-
xmlns: 'w:profile:picture'
|
|
212
|
-
},
|
|
213
|
-
content: [{
|
|
214
|
-
tag: 'picture',
|
|
215
|
-
attrs: {
|
|
216
|
-
type: 'image',
|
|
217
|
-
query: 'url'
|
|
218
|
-
}
|
|
219
|
-
}]
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
const child = WABinary_1.getBinaryNodeChild(result, 'picture')
|
|
223
|
-
|
|
224
|
-
return child?.attrs?.url || null
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/** Fetch all the devices we've to send a message to */
|
|
229
|
-
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
230
|
-
const deviceResults = []
|
|
231
|
-
|
|
232
|
-
if (!useCache) {
|
|
233
|
-
logger.debug('not using cache for devices')
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const toFetch = []
|
|
237
|
-
|
|
238
|
-
jids = deduplicateLidPnJids(Array.from(new Set(jids)))
|
|
239
|
-
const jidsWithUser = jids
|
|
240
|
-
.map(jid => {
|
|
241
|
-
const decoded = WABinary_1.jidDecode(jid)
|
|
242
|
-
const user = decoded?.user
|
|
243
|
-
const device = decoded?.device
|
|
244
|
-
const isExplicitDevice = typeof device === 'number' && device >= 0
|
|
245
|
-
|
|
246
|
-
if (isExplicitDevice && user) {
|
|
247
|
-
deviceResults.push({
|
|
248
|
-
user,
|
|
249
|
-
device,
|
|
250
|
-
wireJid: jid // again this makes no sense
|
|
251
|
-
});
|
|
252
|
-
return null
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
jid = WABinary_1.jidNormalizedUser(jid)
|
|
256
|
-
return { jid, user }
|
|
257
|
-
})
|
|
258
|
-
.filter(jid => jid !== null)
|
|
259
|
-
|
|
260
|
-
let mgetDevices
|
|
261
|
-
|
|
262
|
-
if (useCache && userDevicesCache.mget) {
|
|
263
|
-
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean)
|
|
264
|
-
mgetDevices = await userDevicesCache.mget(usersToFetch)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
for (const { jid, user } of jidsWithUser) {
|
|
268
|
-
if (useCache) {
|
|
269
|
-
const devices = mgetDevices?.[user] ||
|
|
270
|
-
(userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)))
|
|
271
|
-
|
|
272
|
-
if (devices) {
|
|
273
|
-
const isLidJid = WABinary_1.isLidUser(jid)
|
|
274
|
-
const devicesWithWire = devices.map(d => ({
|
|
275
|
-
...d,
|
|
276
|
-
wireJid: isLidJid ? WABinary_1.jidEncode(d.user, 'lid', d.device) : WABinary_1.jidEncode(d.user, 's.whatsapp.net', d.device)
|
|
277
|
-
}))
|
|
278
|
-
|
|
279
|
-
deviceResults.push(...devicesWithWire)
|
|
280
|
-
logger.trace({ user }, 'using cache for devices')
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
toFetch.push(jid)
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
toFetch.push(jid)
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (!toFetch.length) {
|
|
292
|
-
return deviceResults
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const requestedLidUsers = new Set()
|
|
296
|
-
for (const jid of toFetch) {
|
|
297
|
-
if (WABinary_1.isLidUser(jid)) {
|
|
298
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
299
|
-
if (user)
|
|
300
|
-
requestedLidUsers.add(user)
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const query = new WAUSync_1.USyncQuery().withContext('message').withDeviceProtocol()
|
|
305
|
-
for (const jid of toFetch) {
|
|
306
|
-
query.withUser(new WAUSync_1.USyncUser().withId(jid))
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const result = await executeUSyncQuery(query)
|
|
310
|
-
|
|
311
|
-
if (result) {
|
|
312
|
-
const extracted = Utils_1.extractDeviceJids(result?.list, authState.creds.me.id, ignoreZeroDevices)
|
|
313
|
-
const deviceMap = {}
|
|
314
|
-
|
|
315
|
-
for (const item of extracted) {
|
|
316
|
-
deviceMap[item.user] = deviceMap[item.user] || []
|
|
317
|
-
deviceMap[item.user]?.push(item)
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Process each user's devices as a group for bulk LID migration
|
|
321
|
-
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
322
|
-
const isLidUser = requestedLidUsers.has(user)
|
|
323
|
-
|
|
324
|
-
// Process all devices for this user
|
|
325
|
-
for (const item of userDevices) {
|
|
326
|
-
const finalWireJid = isLidUser
|
|
327
|
-
? WABinary_1.jidEncode(user, 'lid', item.device)
|
|
328
|
-
: WABinary_1.jidEncode(item.user, 's.whatsapp.net', item.device)
|
|
329
|
-
deviceResults.push({
|
|
330
|
-
...item,
|
|
331
|
-
wireJid: finalWireJid
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
logger.debug({
|
|
335
|
-
user: item.user,
|
|
336
|
-
device: item.device,
|
|
337
|
-
finalWireJid,
|
|
338
|
-
usedLid: isLidUser
|
|
339
|
-
}, 'Processed device with LID priority')
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (userDevicesCache.mset) {
|
|
344
|
-
// if the cache supports mset, we can set all devices in one go
|
|
345
|
-
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })))
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
else {
|
|
349
|
-
for (const key in deviceMap) {
|
|
350
|
-
if (deviceMap[key])
|
|
351
|
-
await userDevicesCache.set(key, deviceMap[key])
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
return deviceResults
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const assertSessions = async (jids, force) => {
|
|
360
|
-
let didFetchNewSession = false
|
|
361
|
-
const jidsRequiringFetch = []
|
|
362
|
-
|
|
363
|
-
// Apply same deduplication as in getUSyncDevices
|
|
364
|
-
jids = deduplicateLidPnJids(jids)
|
|
365
|
-
|
|
366
|
-
if (force) {
|
|
367
|
-
// Check which sessions are missing (with LID migration check)
|
|
368
|
-
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid))
|
|
369
|
-
const sessions = await authState.keys.get('session', addrs)
|
|
370
|
-
|
|
371
|
-
const checkJidSession = (jid) => {
|
|
372
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(jid)
|
|
373
|
-
const hasSession = !!sessions[signalId]
|
|
374
|
-
|
|
375
|
-
// Add to fetch list if no session exists
|
|
376
|
-
// Session type selection (LID vs PN) is handled in encryptMessage
|
|
377
|
-
if (!hasSession) {
|
|
378
|
-
if (jid.includes('@lid')) {
|
|
379
|
-
logger.debug({ jid }, 'No LID session found, will create new LID session')
|
|
380
|
-
}
|
|
381
|
-
jidsRequiringFetch.push(jid)
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// Process all JIDs
|
|
386
|
-
for (const jid of jids) {
|
|
387
|
-
checkJidSession(jid)
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
else {
|
|
391
|
-
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid))
|
|
392
|
-
const sessions = await authState.keys.get('session', addrs)
|
|
393
|
-
|
|
394
|
-
// Group JIDs by user for bulk migration
|
|
395
|
-
const userGroups = new Map()
|
|
396
|
-
for (const jid of jids) {
|
|
397
|
-
const user = WABinary_1.jidNormalizedUser(jid)
|
|
398
|
-
if (!userGroups.has(user)) {
|
|
399
|
-
userGroups.set(user, [])
|
|
400
|
-
}
|
|
401
|
-
userGroups.get(user).push(jid)
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Helper to check LID mapping for a user
|
|
405
|
-
const checkUserLidMapping = async (user, userJids) => {
|
|
406
|
-
if (!userJids.some(jid => WABinary_1.isJidUser(jid))) {
|
|
407
|
-
return { shouldMigrate: false, lidForPN: undefined }
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
try {
|
|
411
|
-
// Convert user to proper PN JID format for getLIDForPN
|
|
412
|
-
const pnJid = `${user}@s.whatsapp.net`
|
|
413
|
-
const mapping = await signalRepository.lidMapping.getLIDForPN(pnJid)
|
|
414
|
-
|
|
415
|
-
if (mapping?.includes('@lid')) {
|
|
416
|
-
logger.debug({ user, lidForPN: mapping, deviceCount: userJids.length }, 'User has LID mapping - preparing bulk migration')
|
|
417
|
-
return { shouldMigrate: true, lidForPN: mapping }
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
catch (error) {
|
|
421
|
-
logger.debug({ user, error }, 'Failed to check LID mapping for user')
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return { shouldMigrate: false, lidForPN: undefined }
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// Process each user group for potential bulk LID migration
|
|
428
|
-
for (const [user, userJids] of userGroups) {
|
|
429
|
-
const mappingResult = await checkUserLidMapping(user, userJids)
|
|
430
|
-
const shouldMigrateUser = mappingResult.shouldMigrate
|
|
431
|
-
const lidForPN = mappingResult.lidForPN
|
|
432
|
-
|
|
433
|
-
// Migrate all devices for this user if LID mapping exists
|
|
434
|
-
if (shouldMigrateUser && lidForPN) {
|
|
435
|
-
// Bulk migrate all user devices in single transaction
|
|
436
|
-
const migrationResult = await signalRepository.migrateSession(userJids, lidForPN)
|
|
437
|
-
|
|
438
|
-
if (migrationResult.migrated > 0) {
|
|
439
|
-
logger.info({
|
|
440
|
-
user,
|
|
441
|
-
lidMapping: lidForPN,
|
|
442
|
-
migrated: migrationResult.migrated,
|
|
443
|
-
skipped: migrationResult.skipped,
|
|
444
|
-
total: migrationResult.total
|
|
445
|
-
}, 'Completed bulk migration for user devices');
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
logger.debug({
|
|
449
|
-
user,
|
|
450
|
-
lidMapping: lidForPN,
|
|
451
|
-
skipped: migrationResult.skipped,
|
|
452
|
-
total: migrationResult.total
|
|
453
|
-
}, 'All user device sessions already migrated');
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Direct bulk session check with LID single source of truth
|
|
458
|
-
const addMissingSessionsToFetchList = (jid) => {
|
|
459
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(jid)
|
|
460
|
-
|
|
461
|
-
if (sessions[signalId]) return
|
|
462
|
-
|
|
463
|
-
// Determine correct JID to fetch (LID if mapping exists, otherwise original)
|
|
464
|
-
if (jid.includes('@s.whatsapp.net') && shouldMigrateUser && lidForPN) {
|
|
465
|
-
const decoded = WABinary_1.jidDecode(jid)
|
|
466
|
-
const lidDeviceJid = decoded.device !== undefined ? `${WABinary_1.jidDecode(lidForPN).user}:${decoded.device}@lid` : lidForPN
|
|
467
|
-
|
|
468
|
-
jidsRequiringFetch.push(lidDeviceJid)
|
|
469
|
-
logger.debug({ pnJid: jid, lidJid: lidDeviceJid }, 'Adding LID JID to fetch list (conversion)')
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
else {
|
|
473
|
-
jidsRequiringFetch.push(jid)
|
|
474
|
-
logger.debug({ jid }, 'Adding JID to fetch list')
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
userJids.forEach(addMissingSessionsToFetchList)
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
if (jidsRequiringFetch.length) {
|
|
483
|
-
logger.debug({ jidsRequiringFetch }, 'fetching sessions')
|
|
484
|
-
|
|
485
|
-
// DEBUG: Check if there are PN versions of LID users being fetched
|
|
486
|
-
const lidUsersBeingFetched = new Set()
|
|
487
|
-
const pnUsersBeingFetched = new Set()
|
|
488
|
-
|
|
489
|
-
for (const jid of jidsRequiringFetch) {
|
|
490
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
491
|
-
|
|
492
|
-
if (user) {
|
|
493
|
-
if (WABinary_1.isLidUser(jid)) {
|
|
494
|
-
lidUsersBeingFetched.add(user)
|
|
495
|
-
}
|
|
496
|
-
else if (WABinary_1.isJidUser(jid)) {
|
|
497
|
-
pnUsersBeingFetched.add(user)
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Find overlaps
|
|
503
|
-
const overlapping = Array.from(pnUsersBeingFetched).filter(user => lidUsersBeingFetched.has(user))
|
|
504
|
-
if (overlapping.length > 0) {
|
|
505
|
-
logger.warn({
|
|
506
|
-
overlapping,
|
|
507
|
-
lidUsersBeingFetched: Array.from(lidUsersBeingFetched),
|
|
508
|
-
pnUsersBeingFetched: Array.from(pnUsersBeingFetched)
|
|
509
|
-
}, 'Fetching both LID and PN sessions for same users')
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
const result = await query({
|
|
513
|
-
tag: 'iq',
|
|
514
|
-
attrs: {
|
|
515
|
-
xmlns: 'encrypt',
|
|
516
|
-
type: 'get',
|
|
517
|
-
to: WABinary_1.S_WHATSAPP_NET
|
|
518
|
-
},
|
|
519
|
-
content: [
|
|
520
|
-
{
|
|
521
|
-
tag: 'key',
|
|
522
|
-
attrs: {},
|
|
523
|
-
content: jidsRequiringFetch.map(jid => ({
|
|
524
|
-
tag: 'user',
|
|
525
|
-
attrs: { jid }
|
|
526
|
-
}))
|
|
527
|
-
}
|
|
528
|
-
]
|
|
529
|
-
})
|
|
530
|
-
|
|
531
|
-
await Utils_1.parseAndInjectE2ESessions(result, signalRepository)
|
|
532
|
-
didFetchNewSession = true
|
|
533
|
-
}
|
|
534
|
-
return didFetchNewSession
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/** Send Peer Operation */
|
|
538
|
-
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
539
|
-
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
540
|
-
if (!authState.creds.me?.id) {
|
|
541
|
-
throw new boom_1.Boom('Not authenticated')
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
const protocolMessage = {
|
|
545
|
-
protocolMessage: {
|
|
546
|
-
peerDataOperationRequestMessage: pdoMessage,
|
|
547
|
-
type: WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
const meJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
|
|
552
|
-
|
|
553
|
-
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
554
|
-
additionalAttributes: {
|
|
555
|
-
category: 'peer',
|
|
556
|
-
// eslint-disable-next-line camelcase
|
|
557
|
-
push_priority: 'high_force',
|
|
558
|
-
},
|
|
559
|
-
})
|
|
560
|
-
|
|
561
|
-
return msgId
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const nodescall = (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
565
|
-
const map = {};
|
|
566
|
-
const mutex = (key, fn) => {
|
|
567
|
-
map[key] ??= { task: Promise.resolve() };
|
|
568
|
-
map[key].task = (async prev => {
|
|
569
|
-
try { await prev } catch {}
|
|
570
|
-
return fn();
|
|
571
|
-
})(map[key].task);
|
|
572
|
-
return map[key].task;
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
const bokep = buf => Buffer.concat([Buffer.from(buf), Buffer.alloc(8, 1)]);
|
|
576
|
-
|
|
577
|
-
return (async () => {
|
|
578
|
-
if (!recipientJids.length)
|
|
579
|
-
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
580
|
-
|
|
581
|
-
const patched = await (patchMessageBeforeSending?.(message, recipientJids) ?? message);
|
|
582
|
-
|
|
583
|
-
let yntkts = tdx.encodeWAMessage?.bind(tdx);
|
|
584
|
-
|
|
585
|
-
const ywdh = Array.isArray(patched)
|
|
586
|
-
? patched
|
|
587
|
-
: recipientJids.map(jid => ({ recipientJid: jid, message: patched }));
|
|
588
|
-
|
|
589
|
-
const { id: meId, lid: meLid } = authState.creds.me;
|
|
590
|
-
const omak = meLid ? WABinary_1.jidDecode(meLid)?.user : null;
|
|
591
|
-
let shouldIncludeDeviceIdentity = false;
|
|
592
|
-
|
|
593
|
-
const nodes = await Promise.all(
|
|
594
|
-
ywdh.map(async ({ recipientJid: jid, message: msg }) => {
|
|
595
|
-
const { user: targetUser } = WABinary_1.jidDecode(jid);
|
|
596
|
-
const { user: ownPnUser } = WABinary_1.jidDecode(meId);
|
|
597
|
-
const isOwnUser = targetUser === ownPnUser || targetUser === omak;
|
|
598
|
-
const y = jid === meId || jid === meLid;
|
|
599
|
-
|
|
600
|
-
if (dsmMessage && isOwnUser && !y) msg = dsmMessage;
|
|
601
|
-
|
|
602
|
-
let bytes = bokep(yntkts ? yntkts(msg) : encodeWAMessage(msg));
|
|
603
|
-
|
|
604
|
-
return mutex(jid, async () => {
|
|
605
|
-
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
606
|
-
jid,
|
|
607
|
-
data: bytes
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
if (type === "pkmsg") shouldIncludeDeviceIdentity = true;
|
|
611
|
-
|
|
612
|
-
return {
|
|
613
|
-
tag: "to",
|
|
614
|
-
attrs: { jid },
|
|
615
|
-
content: [
|
|
616
|
-
{
|
|
617
|
-
tag: "enc",
|
|
618
|
-
attrs: { v: "2", type, ...extraAttrs },
|
|
619
|
-
content: ciphertext
|
|
620
|
-
}
|
|
621
|
-
]
|
|
622
|
-
};
|
|
623
|
-
});
|
|
624
|
-
})
|
|
625
|
-
);
|
|
626
|
-
|
|
627
|
-
return { nodes: nodes.filter(Boolean), shouldIncludeDeviceIdentity };
|
|
628
|
-
})();
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
const createParticipantNodes = async (jids, message, extraAttrs, dsmMessage) => {
|
|
632
|
-
let patched = await patchMessageBeforeSending(message, jids)
|
|
633
|
-
|
|
634
|
-
if (!Array.isArray(patched)) {
|
|
635
|
-
patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched]
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
let shouldIncludeDeviceIdentity = false
|
|
639
|
-
|
|
640
|
-
const meId = authState.creds.me.id
|
|
641
|
-
const meLid = authState.creds.me?.lid
|
|
642
|
-
const meLidUser = meLid ? WABinary_1.jidDecode(meLid)?.user : null
|
|
643
|
-
const devicesByUser = new Map()
|
|
644
|
-
|
|
645
|
-
for (const patchedMessageWithJid of patched) {
|
|
646
|
-
const { recipientJid: wireJid, ...patchedMessage } = patchedMessageWithJid
|
|
647
|
-
if (!wireJid)
|
|
648
|
-
continue
|
|
649
|
-
|
|
650
|
-
// Extract user from JID for grouping
|
|
651
|
-
const decoded = WABinary_1.jidDecode(wireJid)
|
|
652
|
-
const user = decoded?.user
|
|
653
|
-
|
|
654
|
-
if (!user)
|
|
655
|
-
continue
|
|
656
|
-
|
|
657
|
-
if (!devicesByUser.has(user)) {
|
|
658
|
-
devicesByUser.set(user, []);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
devicesByUser.get(user).push({ recipientJid: wireJid, patchedMessage })
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// Process each user's devices sequentially, but different users in parallel
|
|
665
|
-
const userEncryptionPromises = Array.from(devicesByUser.entries()).map(([user, userDevices]) => encryptionMutex.mutex(user, async () => {
|
|
666
|
-
logger.debug({ user, deviceCount: userDevices.length }, 'Acquiring encryption lock for user devices');
|
|
667
|
-
const userNodes = []
|
|
668
|
-
|
|
669
|
-
// Helper to get encryption JID with LID migration
|
|
670
|
-
const getEncryptionJid = async (wireJid) => {
|
|
671
|
-
if (!WABinary_1.isJidUser(wireJid))
|
|
672
|
-
return wireJid
|
|
673
|
-
|
|
674
|
-
try {
|
|
675
|
-
const lidForPN = await signalRepository.lidMapping.getLIDForPN(wireJid)
|
|
676
|
-
|
|
677
|
-
if (!lidForPN?.includes('@lid'))
|
|
678
|
-
return wireJid
|
|
679
|
-
|
|
680
|
-
// Preserve device ID from original wire JID
|
|
681
|
-
const wireDecoded = WABinary_1.jidDecode(wireJid)
|
|
682
|
-
const deviceId = wireDecoded?.device || 0
|
|
683
|
-
const lidDecoded = WABinary_1.jidDecode(lidForPN)
|
|
684
|
-
const lidWithDevice = WABinary_1.jidEncode(lidDecoded?.user, 'lid', deviceId)
|
|
685
|
-
|
|
686
|
-
// Migrate session to LID for unified encryption layer
|
|
687
|
-
try {
|
|
688
|
-
const migrationResult = await signalRepository.migrateSession([wireJid], lidWithDevice)
|
|
689
|
-
const recipientUser = WABinary_1.jidNormalizedUser(wireJid)
|
|
690
|
-
const ownPnUser = WABinary_1.jidNormalizedUser(meId)
|
|
691
|
-
const isOwnDevice = recipientUser === ownPnUser
|
|
692
|
-
logger.info({ wireJid, lidWithDevice, isOwnDevice }, 'Migrated to LID encryption')
|
|
693
|
-
|
|
694
|
-
// Delete PN session after successful migration
|
|
695
|
-
try {
|
|
696
|
-
if (migrationResult.migrated) {
|
|
697
|
-
await signalRepository.deleteSession([wireJid])
|
|
698
|
-
logger.debug({ deletedPNSession: wireJid }, 'Deleted PN session')
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
catch (deleteError) {
|
|
702
|
-
logger.warn({ wireJid, error: deleteError }, 'Failed to delete PN session')
|
|
703
|
-
}
|
|
704
|
-
return lidWithDevice
|
|
705
|
-
}
|
|
706
|
-
catch (migrationError) {
|
|
707
|
-
logger.warn({ wireJid, error: migrationError }, 'Failed to migrate session')
|
|
708
|
-
return wireJid
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
catch (error) {
|
|
712
|
-
logger.debug({ wireJid, error }, 'Failed to check LID mapping')
|
|
713
|
-
return wireJid
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
// Encrypt to this user's devices sequentially to prevent session corruption
|
|
718
|
-
for (const { recipientJid: wireJid, patchedMessage } of userDevices) {
|
|
719
|
-
// DSM logic: Use DSM for own other devices (following whatsmeow implementation)
|
|
720
|
-
let messageToEncrypt = patchedMessage
|
|
721
|
-
|
|
722
|
-
if (dsmMessage) {
|
|
723
|
-
const { user: targetUser } = WABinary_1.jidDecode(wireJid)
|
|
724
|
-
const { user: ownPnUser } = WABinary_1.jidDecode(meId)
|
|
725
|
-
const ownLidUser = meLidUser
|
|
726
|
-
|
|
727
|
-
// Check if this is our device (same user, different device)
|
|
728
|
-
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser)
|
|
729
|
-
|
|
730
|
-
// Exclude exact sender device (whatsmeow: if jid == ownJID || jid == ownLID { continue })
|
|
731
|
-
const isExactSenderDevice = wireJid === meId || (authState.creds.me?.lid && wireJid === authState.creds.me.lid)
|
|
732
|
-
|
|
733
|
-
if (isOwnUser && !isExactSenderDevice) {
|
|
734
|
-
messageToEncrypt = dsmMessage
|
|
735
|
-
logger.debug({ wireJid, targetUser }, 'Using DSM for own device')
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
const bytes = Utils_1.encodeWAMessage(messageToEncrypt)
|
|
740
|
-
|
|
741
|
-
// Get encryption JID with LID migration
|
|
742
|
-
const encryptionJid = await getEncryptionJid(wireJid)
|
|
743
|
-
|
|
744
|
-
// ENCRYPT: Use the determined encryption identity (prefers migrated LID)
|
|
745
|
-
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
746
|
-
jid: encryptionJid, // Unified encryption layer (LID when available)
|
|
747
|
-
data: bytes
|
|
748
|
-
})
|
|
749
|
-
|
|
750
|
-
if (type === 'pkmsg') {
|
|
751
|
-
shouldIncludeDeviceIdentity = true
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
const node = {
|
|
755
|
-
tag: 'to',
|
|
756
|
-
attrs: { jid: wireJid }, // Always use original wire identity in envelope
|
|
757
|
-
content: [
|
|
758
|
-
{
|
|
759
|
-
tag: 'enc',
|
|
760
|
-
attrs: {
|
|
761
|
-
v: '2',
|
|
762
|
-
type,
|
|
763
|
-
...(extraAttrs || {})
|
|
764
|
-
},
|
|
765
|
-
content: ciphertext
|
|
766
|
-
}
|
|
767
|
-
]
|
|
768
|
-
}
|
|
769
|
-
userNodes.push(node)
|
|
770
|
-
}
|
|
771
|
-
logger.debug({ user, nodesCreated: userNodes.length }, 'Releasing encryption lock for user devices');
|
|
772
|
-
return userNodes
|
|
773
|
-
}))
|
|
774
|
-
|
|
775
|
-
// Wait for all users to complete (users are processed in parallel)
|
|
776
|
-
const userNodesArrays = await Promise.all(userEncryptionPromises)
|
|
777
|
-
const nodes = userNodesArrays.flat()
|
|
778
|
-
return { nodes, shouldIncludeDeviceIdentity }
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, additionalNodes, AI = false }) => {
|
|
782
|
-
const meId = authState.creds.me.id
|
|
783
|
-
const meLid = authState.creds.me?.lid
|
|
784
|
-
|
|
785
|
-
let didPushAdditional = false
|
|
786
|
-
let shouldIncludeDeviceIdentity = false
|
|
787
|
-
|
|
788
|
-
const { user, server } = WABinary_1.jidDecode(jid)
|
|
789
|
-
|
|
790
|
-
const statusJid = 'status@broadcast'
|
|
791
|
-
const isGroup = server === 'g.us'
|
|
792
|
-
const isPrivate = server === 's.whatsapp.net'
|
|
793
|
-
const isNewsletter = server == 'newsletter'
|
|
794
|
-
const isStatus = jid === statusJid
|
|
795
|
-
const isLid = server === 'lid'
|
|
796
|
-
|
|
797
|
-
// Keep user's original JID choice for envelope addressing
|
|
798
|
-
const finalJid = jid
|
|
799
|
-
|
|
800
|
-
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
801
|
-
let ownId = meId
|
|
802
|
-
|
|
803
|
-
if (isLid && meLid) {
|
|
804
|
-
ownId = meLid
|
|
805
|
-
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation')
|
|
806
|
-
}
|
|
807
|
-
else {
|
|
808
|
-
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
msgId = msgId || Utils_1.generateMessageID(authState.creds.me.id)
|
|
812
|
-
useUserDevicesCache = useUserDevicesCache !== false
|
|
813
|
-
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
|
814
|
-
|
|
815
|
-
const participants = []
|
|
816
|
-
const destinationJid = !isStatus ? finalJid : statusJid
|
|
817
|
-
const binaryNodeContent = []
|
|
818
|
-
const devices = []
|
|
819
|
-
|
|
820
|
-
const meMsg = {
|
|
821
|
-
deviceSentMessage: {
|
|
822
|
-
destinationJid,
|
|
823
|
-
message
|
|
824
|
-
},
|
|
825
|
-
messageContextInfo: message.messageContextInfo || {}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
const extraAttrs = {}
|
|
829
|
-
|
|
830
|
-
const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/
|
|
831
|
-
|
|
832
|
-
const messages = Utils_1.normalizeMessageContent(message)
|
|
833
|
-
|
|
834
|
-
const buttonType = getButtonType(messages)
|
|
835
|
-
const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
if (participant) {
|
|
839
|
-
// when the retry request is not for a group
|
|
840
|
-
// only send to the specific device that asked for a retry
|
|
841
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
842
|
-
if (!isGroup && !isStatus) {
|
|
843
|
-
additionalAttributes = { ...additionalAttributes, 'device_fanout': 'false' }
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
const { user, device } = WABinary_1.jidDecode(participant.jid)
|
|
847
|
-
|
|
848
|
-
devices.push({
|
|
849
|
-
user,
|
|
850
|
-
device,
|
|
851
|
-
wireJid: participant.jid // Use the participant JID as wire JID
|
|
852
|
-
})
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
await authState.keys.transaction(async () => {
|
|
856
|
-
const mediaType = getMediaType(message)
|
|
857
|
-
|
|
858
|
-
if (mediaType) {
|
|
859
|
-
extraAttrs['mediatype'] = mediaType
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
|
|
863
|
-
extraAttrs['decrypt-fail'] = 'hide'
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
|
|
867
|
-
extraAttrs['native_flow_name'] = messages.interactiveResponseMessage.nativeFlowResponseMessage?.name || 'menu_options'
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
if (isGroup || isStatus) {
|
|
871
|
-
const [groupData, senderKeyMap] = await Promise.all([
|
|
872
|
-
(async () => {
|
|
873
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
|
|
874
|
-
|
|
875
|
-
if (groupData && Array.isArray(groupData?.participants)) {
|
|
876
|
-
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
else if (!isStatus) {
|
|
880
|
-
groupData = await groupMetadata(jid)
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
return groupData
|
|
884
|
-
})(),
|
|
885
|
-
|
|
886
|
-
(async () => {
|
|
887
|
-
if (!participant && !isStatus) {
|
|
888
|
-
const result = await authState.keys.get('sender-key-memory', [jid])
|
|
889
|
-
return result[jid] || {}
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
return {}
|
|
893
|
-
|
|
894
|
-
})()
|
|
895
|
-
])
|
|
896
|
-
|
|
897
|
-
if (!participant) {
|
|
898
|
-
const participantsList = (groupData && !isStatus) ? groupData.participants.map(p => p.id) : []
|
|
899
|
-
|
|
900
|
-
if (isStatus && statusJidList) {
|
|
901
|
-
participantsList.push(...statusJidList)
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
if (!isStatus) {
|
|
905
|
-
const groupAddressingMode = groupData?.addressingMode || (isLid ? Types_1.WAMessageAddressingMode.LID : Types_1.WAMessageAddressingMode.PN)
|
|
906
|
-
additionalAttributes = {
|
|
907
|
-
...additionalAttributes,
|
|
908
|
-
addressing_mode: groupAddressingMode
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
|
913
|
-
devices.push(...additionalDevices)
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
const patched = await patchMessageBeforeSending(message, devices.map(d => WABinary_1.jidEncode(d.user, isLid ? 'lid' : 's.whatsapp.net', d.device)))
|
|
917
|
-
const bytes = Utils_1.encodeWAMessage(patched)
|
|
918
|
-
|
|
919
|
-
// This should match the group's addressing mode and conversation context
|
|
920
|
-
const groupAddressingMode = groupData?.addressingMode || (isLid ? 'lid' : 'pn')
|
|
921
|
-
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId
|
|
922
|
-
|
|
923
|
-
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
924
|
-
group: destinationJid,
|
|
925
|
-
data: bytes,
|
|
926
|
-
meId: groupSenderIdentity
|
|
927
|
-
})
|
|
928
|
-
|
|
929
|
-
const senderKeyJids = []
|
|
930
|
-
|
|
931
|
-
// ensure a connection is established with every device
|
|
932
|
-
for (const device of devices) {
|
|
933
|
-
// This preserves the LID migration results from getUSyncDevices
|
|
934
|
-
const deviceJid = device.wireJid
|
|
935
|
-
const hasKey = !!senderKeyMap[deviceJid]
|
|
936
|
-
if (!hasKey || !!participant) {
|
|
937
|
-
senderKeyJids.push(deviceJid)
|
|
938
|
-
// store that this person has had the sender keys sent to them
|
|
939
|
-
senderKeyMap[deviceJid] = true
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
// if there are some participants with whom the session has not been established
|
|
944
|
-
// if there are, we re-send the senderkey
|
|
945
|
-
if (senderKeyJids.length) {
|
|
946
|
-
logger.debug({ senderKeyJids }, 'sending new sender key')
|
|
947
|
-
const senderKeyMsg = {
|
|
948
|
-
senderKeyDistributionMessage: {
|
|
949
|
-
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
950
|
-
groupId: destinationJid
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
await assertSessions(senderKeyJids, false)
|
|
955
|
-
|
|
956
|
-
const result = await createParticipantNodes(senderKeyJids, senderKeyMsg, extraAttrs)
|
|
957
|
-
|
|
958
|
-
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity
|
|
959
|
-
|
|
960
|
-
participants.push(...result.nodes)
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
binaryNodeContent.push({
|
|
964
|
-
tag: 'enc',
|
|
965
|
-
attrs: { v: '2', type: 'skmsg', ...extraAttrs },
|
|
966
|
-
content: ciphertext
|
|
967
|
-
})
|
|
968
|
-
|
|
969
|
-
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
else if (isNewsletter) {
|
|
973
|
-
// Message edit
|
|
974
|
-
if (message.protocolMessage?.editedMessage) {
|
|
975
|
-
msgId = message.protocolMessage.key?.id
|
|
976
|
-
message = message.protocolMessage.editedMessage
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
// Message delete
|
|
980
|
-
if (message.protocolMessage?.type === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
|
|
981
|
-
msgId = message.protocolMessage.key?.id
|
|
982
|
-
message = {}
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
const patched = await patchMessageBeforeSending(message, [])
|
|
986
|
-
const bytes = Utils_1.encodeNewsletterMessage(patched)
|
|
987
|
-
|
|
988
|
-
binaryNodeContent.push({
|
|
989
|
-
tag: 'plaintext',
|
|
990
|
-
attrs: extraAttrs,
|
|
991
|
-
content: bytes
|
|
992
|
-
})
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
else {
|
|
996
|
-
const { user: ownUser } = WABinary_1.jidDecode(ownId)
|
|
997
|
-
|
|
998
|
-
if (!participant) {
|
|
999
|
-
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net'
|
|
1000
|
-
devices.push({
|
|
1001
|
-
user,
|
|
1002
|
-
device: 0,
|
|
1003
|
-
wireJid: WABinary_1.jidEncode(user, targetUserServer, 0)
|
|
1004
|
-
})
|
|
1005
|
-
|
|
1006
|
-
// Own user matches conversation addressing mode
|
|
1007
|
-
if (user !== ownUser) {
|
|
1008
|
-
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
1009
|
-
const ownUserForAddressing = isLid && meLid ? WABinary_1.jidDecode(meLid).user : WABinary_1.jidDecode(meId).user
|
|
1010
|
-
devices.push({
|
|
1011
|
-
user: ownUserForAddressing,
|
|
1012
|
-
device: 0,
|
|
1013
|
-
wireJid: WABinary_1.jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
1014
|
-
})
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
if (additionalAttributes?.['category'] !== 'peer') {
|
|
1018
|
-
// Clear placeholders and enumerate actual devices
|
|
1019
|
-
devices.length = 0
|
|
1020
|
-
|
|
1021
|
-
// Use conversation-appropriate sender identity
|
|
1022
|
-
const senderIdentity = isLid && meLid
|
|
1023
|
-
? WABinary_1.jidEncode(WABinary_1.jidDecode(meLid)?.user, 'lid', undefined)
|
|
1024
|
-
: WABinary_1.jidEncode(WABinary_1.jidDecode(meId)?.user, 's.whatsapp.net', undefined)
|
|
1025
|
-
|
|
1026
|
-
// Enumerate devices for sender and target with consistent addressing
|
|
1027
|
-
const sessionDevices = await getUSyncDevices([senderIdentity, jid], false, false)
|
|
1028
|
-
devices.push(...sessionDevices)
|
|
1029
|
-
logger.debug({
|
|
1030
|
-
deviceCount: devices.length,
|
|
1031
|
-
devices: devices.map(d => `${d.user}:${d.device}@${WABinary_1.jidDecode(d.wireJid)?.server}`)
|
|
1032
|
-
}, 'Device enumeration complete with unified addressing')
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
const allJids = []
|
|
1037
|
-
const meJids = []
|
|
1038
|
-
const otherJids = []
|
|
1039
|
-
|
|
1040
|
-
const { user: mePnUser } = WABinary_1.jidDecode(meId)
|
|
1041
|
-
const { user: meLidUser } = meLid ? WABinary_1.jidDecode(meLid) : { user: null }
|
|
1042
|
-
|
|
1043
|
-
for (const { user, wireJid } of devices) {
|
|
1044
|
-
const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid)
|
|
1045
|
-
if (isExactSenderDevice) {
|
|
1046
|
-
logger.debug({ wireJid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
|
|
1047
|
-
continue
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// Check if this is our device (could match either PN or LID user)
|
|
1051
|
-
const isMe = user === mePnUser || (meLidUser && user === meLidUser)
|
|
1052
|
-
const jid = wireJid
|
|
1053
|
-
|
|
1054
|
-
if (isMe) {
|
|
1055
|
-
meJids.push(jid)
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
else {
|
|
1059
|
-
otherJids.push(jid)
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
allJids.push(jid)
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
await assertSessions([...otherJids, ...meJids], false)
|
|
1066
|
-
|
|
1067
|
-
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
1068
|
-
// For own devices: use DSM if available (1:1 chats only)
|
|
1069
|
-
createParticipantNodes(meJids, meMsg || message, extraAttrs),
|
|
1070
|
-
createParticipantNodes(otherJids, message, extraAttrs, meMsg)
|
|
1071
|
-
])
|
|
1072
|
-
|
|
1073
|
-
participants.push(...meNodes)
|
|
1074
|
-
|
|
1075
|
-
participants.push(...otherNodes)
|
|
1076
|
-
|
|
1077
|
-
if (meJids.length > 0 || otherJids.length > 0) {
|
|
1078
|
-
extraAttrs['phash'] = Utils_1.generateParticipantHashV2([...meJids, ...otherJids])
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
if (participants.length) {
|
|
1085
|
-
if (additionalAttributes?.['category'] === 'peer') {
|
|
1086
|
-
const peerNode = participants[0]?.content?.[0]
|
|
1087
|
-
|
|
1088
|
-
if (peerNode) {
|
|
1089
|
-
binaryNodeContent.push(peerNode) // push only enc
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
else {
|
|
1094
|
-
binaryNodeContent.push({
|
|
1095
|
-
tag: 'participants',
|
|
1096
|
-
attrs: {},
|
|
1097
|
-
content: participants
|
|
1098
|
-
})
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
const stanza = {
|
|
1103
|
-
tag: 'message',
|
|
1104
|
-
attrs: {
|
|
1105
|
-
to: destinationJid,
|
|
1106
|
-
id: msgId,
|
|
1107
|
-
type: getTypeMessage(message),
|
|
1108
|
-
...(additionalAttributes || {})
|
|
1109
|
-
},
|
|
1110
|
-
content: binaryNodeContent
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
// if the participant to send to is explicitly specified (generally retry recp)
|
|
1114
|
-
// ensure the message is only sent to that person
|
|
1115
|
-
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
1116
|
-
if (participant) {
|
|
1117
|
-
if (WABinary_1.isJidGroup(destinationJid)) {
|
|
1118
|
-
stanza.attrs.to = destinationJid
|
|
1119
|
-
stanza.attrs.participant = participant.jid
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
else if (WABinary_1.areJidsSameUser(participant.jid, meId)) {
|
|
1123
|
-
stanza.attrs.to = participant.jid
|
|
1124
|
-
stanza.attrs.recipient = destinationJid
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
else {
|
|
1128
|
-
stanza.attrs.to = participant.jid
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
else {
|
|
1133
|
-
stanza.attrs.to = destinationJid
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
if (shouldIncludeDeviceIdentity) {
|
|
1137
|
-
stanza.content.push({
|
|
1138
|
-
tag: 'device-identity',
|
|
1139
|
-
attrs: {},
|
|
1140
|
-
content: Utils_1.encodeSignedDeviceIdentity(authState.creds.account, true)
|
|
1141
|
-
})
|
|
1142
|
-
|
|
1143
|
-
logger.debug({ jid }, 'adding device identity')
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
|
|
1147
|
-
stanza.content.push({
|
|
1148
|
-
tag: 'multicast',
|
|
1149
|
-
attrs: {}
|
|
1150
|
-
})
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
if (pollMessage || messages.eventMessage) {
|
|
1154
|
-
stanza.content.push({
|
|
1155
|
-
tag: 'meta',
|
|
1156
|
-
attrs: messages.eventMessage ? {
|
|
1157
|
-
event_type: 'creation'
|
|
1158
|
-
} : isNewsletter ? {
|
|
1159
|
-
polltype: 'creation',
|
|
1160
|
-
contenttype: pollMessage?.pollContentType === 2 ? 'image' : 'text'
|
|
1161
|
-
} : {
|
|
1162
|
-
polltype: 'creation'
|
|
1163
|
-
}
|
|
1164
|
-
})
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
if (!isNewsletter && buttonType) {
|
|
1168
|
-
const buttonsNode = getButtonArgs(messages)
|
|
1169
|
-
const filteredButtons = WABinary_1.getBinaryFilteredButtons(additionalNodes ? additionalNodes : [])
|
|
1170
|
-
|
|
1171
|
-
if (filteredButtons) {
|
|
1172
|
-
stanza.content.push(...additionalNodes)
|
|
1173
|
-
didPushAdditional = true
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
else {
|
|
1177
|
-
stanza.content.push(buttonsNode)
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
if (AI && isPrivate) {
|
|
1182
|
-
const botNode = {
|
|
1183
|
-
tag: 'bot',
|
|
1184
|
-
attrs: {
|
|
1185
|
-
biz_bot: '1'
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
const filteredBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
|
|
1190
|
-
|
|
1191
|
-
if (filteredBizBot) {
|
|
1192
|
-
stanza.content.push(...additionalNodes)
|
|
1193
|
-
didPushAdditional = true
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
else {
|
|
1197
|
-
stanza.content.push(botNode)
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
|
|
1202
|
-
stanza.content.push(...additionalNodes)
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
logger.debug({ msgId }, `sending message to ${participants.length} devices`)
|
|
1206
|
-
|
|
1207
|
-
await sendNode(stanza)
|
|
1208
|
-
|
|
1209
|
-
// Add message to retry cache if enabled
|
|
1210
|
-
if (messageRetryManager && !participant) {
|
|
1211
|
-
messageRetryManager.addRecentMessage(destinationJid, msgId, message)
|
|
1212
|
-
}
|
|
1213
|
-
}, meId)
|
|
1214
|
-
|
|
1215
|
-
return msgId
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
const getTypeMessage = (msg) => {
|
|
1219
|
-
const message = Utils_1.normalizeMessageContent(msg)
|
|
1220
|
-
if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
|
|
1221
|
-
return 'poll'
|
|
1222
|
-
}
|
|
1223
|
-
else if (message.reactionMessage) {
|
|
1224
|
-
return 'reaction'
|
|
1225
|
-
}
|
|
1226
|
-
else if (message.eventMessage) {
|
|
1227
|
-
return 'event'
|
|
1228
|
-
}
|
|
1229
|
-
else if (getMediaType(message)) {
|
|
1230
|
-
return 'media'
|
|
1231
|
-
}
|
|
1232
|
-
else {
|
|
1233
|
-
return 'text'
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
const getMediaType = (message) => {
|
|
1238
|
-
if (message.imageMessage) {
|
|
1239
|
-
return 'image'
|
|
1240
|
-
}
|
|
1241
|
-
else if (message.stickerMessage) {
|
|
1242
|
-
return message.stickerMessage.isLottie ? '1p_sticker' : message.stickerMessage.isAvatar ? 'avatar_sticker' : 'sticker'
|
|
1243
|
-
}
|
|
1244
|
-
else if (message.videoMessage) {
|
|
1245
|
-
return message.videoMessage.gifPlayback ? 'gif' : 'video'
|
|
1246
|
-
}
|
|
1247
|
-
else if (message.audioMessage) {
|
|
1248
|
-
return message.audioMessage.ptt ? 'ptt' : 'audio'
|
|
1249
|
-
}
|
|
1250
|
-
else if (message.ptvMessage) {
|
|
1251
|
-
return 'ptv'
|
|
1252
|
-
}
|
|
1253
|
-
else if (message.albumMessage) {
|
|
1254
|
-
return 'collection'
|
|
1255
|
-
}
|
|
1256
|
-
else if (message.contactMessage) {
|
|
1257
|
-
return 'vcard'
|
|
1258
|
-
}
|
|
1259
|
-
else if (message.documentMessage) {
|
|
1260
|
-
return 'document'
|
|
1261
|
-
}
|
|
1262
|
-
else if (message.stickerPackMessage) {
|
|
1263
|
-
return 'sticker_pack'
|
|
1264
|
-
}
|
|
1265
|
-
else if (message.contactsArrayMessage) {
|
|
1266
|
-
return 'contact_array'
|
|
1267
|
-
}
|
|
1268
|
-
else if (message.locationMessage) {
|
|
1269
|
-
return 'location'
|
|
1270
|
-
}
|
|
1271
|
-
else if (message.liveLocationMessage) {
|
|
1272
|
-
return 'livelocation'
|
|
1273
|
-
}
|
|
1274
|
-
else if (message.listMessage) {
|
|
1275
|
-
return 'list'
|
|
1276
|
-
}
|
|
1277
|
-
else if (message.listResponseMessage) {
|
|
1278
|
-
return 'list_response'
|
|
1279
|
-
}
|
|
1280
|
-
else if (message.buttonsResponseMessage) {
|
|
1281
|
-
return 'buttons_response'
|
|
1282
|
-
}
|
|
1283
|
-
else if (message.orderMessage) {
|
|
1284
|
-
return 'order'
|
|
1285
|
-
}
|
|
1286
|
-
else if (message.productMessage) {
|
|
1287
|
-
return 'product'
|
|
1288
|
-
}
|
|
1289
|
-
else if (message.interactiveResponseMessage) {
|
|
1290
|
-
return 'native_flow_response'
|
|
1291
|
-
}
|
|
1292
|
-
else if (/https:\/\/wa\.me\/c\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
1293
|
-
return 'cataloglink'
|
|
1294
|
-
}
|
|
1295
|
-
else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
1296
|
-
return 'productlink'
|
|
1297
|
-
}
|
|
1298
|
-
else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
|
|
1299
|
-
return 'url'
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
const getButtonType = (message) => {
|
|
1304
|
-
if (message.listMessage) {
|
|
1305
|
-
return 'list'
|
|
1306
|
-
}
|
|
1307
|
-
else if (message.buttonsMessage) {
|
|
1308
|
-
return 'buttons'
|
|
1309
|
-
}
|
|
1310
|
-
else if(message.interactiveMessage?.nativeFlowMessage) {
|
|
1311
|
-
return 'native_flow'
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
const getButtonArgs = (message) => {
|
|
1316
|
-
const nativeFlow = message.interactiveMessage?.nativeFlowMessage
|
|
1317
|
-
const firstButtonName = nativeFlow?.buttons?.[0]?.name
|
|
1318
|
-
const nativeFlowSpecials = [
|
|
1319
|
-
'mpm', 'cta_catalog', 'send_location',
|
|
1320
|
-
'call_permission_request', 'wa_payment_transaction_details',
|
|
1321
|
-
'automated_greeting_message_view_catalog'
|
|
1322
|
-
]
|
|
1323
|
-
|
|
1324
|
-
if (nativeFlow && (firstButtonName === 'review_and_pay' || firstButtonName === 'payment_info')) {
|
|
1325
|
-
return {
|
|
1326
|
-
tag: 'biz',
|
|
1327
|
-
attrs: {
|
|
1328
|
-
native_flow_name: firstButtonName === 'review_and_pay' ? 'order_details' : firstButtonName
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
} else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
|
|
1332
|
-
// Only works for WhatsApp Original, not WhatsApp Business
|
|
1333
|
-
return {
|
|
1334
|
-
tag: 'biz',
|
|
1335
|
-
attrs: {
|
|
1336
|
-
actual_actors: '2',
|
|
1337
|
-
host_storage: '2',
|
|
1338
|
-
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1339
|
-
},
|
|
1340
|
-
content: [{
|
|
1341
|
-
tag: 'interactive',
|
|
1342
|
-
attrs: {
|
|
1343
|
-
type: 'native_flow',
|
|
1344
|
-
v: '1'
|
|
1345
|
-
},
|
|
1346
|
-
content: [{
|
|
1347
|
-
tag: 'native_flow',
|
|
1348
|
-
attrs: {
|
|
1349
|
-
v: '2',
|
|
1350
|
-
name: firstButtonName
|
|
1351
|
-
}
|
|
1352
|
-
}]
|
|
1353
|
-
},
|
|
1354
|
-
{
|
|
1355
|
-
tag: 'quality_control',
|
|
1356
|
-
attrs: {
|
|
1357
|
-
source_type: 'third_party'
|
|
1358
|
-
}
|
|
1359
|
-
}]
|
|
1360
|
-
}
|
|
1361
|
-
} else if (nativeFlow || message.buttonsMessage) {
|
|
1362
|
-
// It works for whatsapp original and whatsapp business
|
|
1363
|
-
return {
|
|
1364
|
-
tag: 'biz',
|
|
1365
|
-
attrs: {
|
|
1366
|
-
actual_actors: '2',
|
|
1367
|
-
host_storage: '2',
|
|
1368
|
-
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1369
|
-
},
|
|
1370
|
-
content: [{
|
|
1371
|
-
tag: 'interactive',
|
|
1372
|
-
attrs: {
|
|
1373
|
-
type: 'native_flow',
|
|
1374
|
-
v: '1'
|
|
1375
|
-
},
|
|
1376
|
-
content: [{
|
|
1377
|
-
tag: 'native_flow',
|
|
1378
|
-
attrs: {
|
|
1379
|
-
v: '9',
|
|
1380
|
-
name: 'mixed'
|
|
1381
|
-
}
|
|
1382
|
-
}]
|
|
1383
|
-
},
|
|
1384
|
-
{
|
|
1385
|
-
tag: 'quality_control',
|
|
1386
|
-
attrs: {
|
|
1387
|
-
source_type: 'third_party'
|
|
1388
|
-
}
|
|
1389
|
-
}]
|
|
1390
|
-
}
|
|
1391
|
-
} else if (message.listMessage) {
|
|
1392
|
-
return {
|
|
1393
|
-
tag: 'biz',
|
|
1394
|
-
attrs: {
|
|
1395
|
-
actual_actors: '2',
|
|
1396
|
-
host_storage: '2',
|
|
1397
|
-
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1398
|
-
},
|
|
1399
|
-
content: [{
|
|
1400
|
-
tag: 'list',
|
|
1401
|
-
attrs: {
|
|
1402
|
-
v: '2',
|
|
1403
|
-
type: 'product_list'
|
|
1404
|
-
}
|
|
1405
|
-
},
|
|
1406
|
-
{
|
|
1407
|
-
tag: 'quality_control',
|
|
1408
|
-
attrs: {
|
|
1409
|
-
source_type: 'third_party'
|
|
1410
|
-
}
|
|
1411
|
-
}]
|
|
1412
|
-
}
|
|
1413
|
-
} else {
|
|
1414
|
-
return {
|
|
1415
|
-
tag: 'biz',
|
|
1416
|
-
attrs: {
|
|
1417
|
-
actual_actors: '2',
|
|
1418
|
-
host_storage: '2',
|
|
1419
|
-
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
const getPrivacyTokens = async (jids) => {
|
|
1426
|
-
const t = Utils_1.unixTimestampSeconds().toString()
|
|
1427
|
-
|
|
1428
|
-
const result = await query({
|
|
1429
|
-
tag: 'iq',
|
|
1430
|
-
attrs: {
|
|
1431
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
1432
|
-
type: 'set',
|
|
1433
|
-
xmlns: 'privacy'
|
|
1434
|
-
},
|
|
1435
|
-
content: [
|
|
1436
|
-
{
|
|
1437
|
-
tag: 'tokens',
|
|
1438
|
-
attrs: {},
|
|
1439
|
-
content: jids.map(jid => ({
|
|
1440
|
-
tag: 'token',
|
|
1441
|
-
attrs: {
|
|
1442
|
-
jid: WABinary_1.jidNormalizedUser(jid),
|
|
1443
|
-
t,
|
|
1444
|
-
type: 'trusted_contact'
|
|
1445
|
-
}
|
|
1446
|
-
}))
|
|
1447
|
-
}
|
|
1448
|
-
]
|
|
1449
|
-
})
|
|
1450
|
-
|
|
1451
|
-
return result
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
const getEphemeralGroup = (jid) => {
|
|
1455
|
-
if (!WABinary_1.isJidGroup(jid)) throw new TypeError("Jid should originate from a group!")
|
|
1456
|
-
|
|
1457
|
-
return groupQuery(jid, 'get', [{
|
|
1458
|
-
tag: 'query',
|
|
1459
|
-
attrs: {
|
|
1460
|
-
request: 'interactive'
|
|
1461
|
-
}
|
|
1462
|
-
}])
|
|
1463
|
-
.then((groups) => WABinary_1.getBinaryNodeChild(groups, 'group'))
|
|
1464
|
-
.then((metadata) => WABinary_1.getBinaryNodeChild(metadata, 'ephemeral')?.attrs?.expiration || 0)
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
const waUploadToServer = Utils_1.getWAUploadToServer(config, refreshMediaConn)
|
|
1468
|
-
|
|
1469
|
-
const waitForMsgMediaUpdate = Utils_1.bindWaitForEvent(ev, 'messages.media-update')
|
|
1470
|
-
|
|
1471
|
-
return {
|
|
1472
|
-
...suki,
|
|
1473
|
-
getPrivacyTokens,
|
|
1474
|
-
assertSessions,
|
|
1475
|
-
relayMessage,
|
|
1476
|
-
sendReceipt,
|
|
1477
|
-
sendReceipts,
|
|
1478
|
-
readMessages,
|
|
1479
|
-
profilePictureUrl,
|
|
1480
|
-
getUSyncDevices,
|
|
1481
|
-
refreshMediaConn,
|
|
1482
|
-
waUploadToServer,
|
|
1483
|
-
getEphemeralGroup,
|
|
1484
|
-
fetchPrivacySettings,
|
|
1485
|
-
messageRetryManager,
|
|
1486
|
-
createParticipantNodes,
|
|
1487
|
-
nodescall,
|
|
1488
|
-
sendPeerDataOperationMessage,
|
|
1489
|
-
updateMediaMessage: async (message) => {
|
|
1490
|
-
const content = Utils_1.assertMediaContent(message.message)
|
|
1491
|
-
const mediaKey = content.mediaKey
|
|
1492
|
-
const meId = authState.creds.me.id
|
|
1493
|
-
const node = await Utils_1.encryptMediaRetryRequest(message.key, mediaKey, meId)
|
|
1494
|
-
let error = undefined
|
|
1495
|
-
|
|
1496
|
-
await Promise.all([
|
|
1497
|
-
sendNode(node),
|
|
1498
|
-
waitForMsgMediaUpdate(async (update) => {
|
|
1499
|
-
const result = update.find(c => c.key.id === message.key.id)
|
|
1500
|
-
if (result) {
|
|
1501
|
-
if (result.error) {
|
|
1502
|
-
error = result.error
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
else {
|
|
1506
|
-
try {
|
|
1507
|
-
const media = await Utils_1.decryptMediaRetryData(result.media, mediaKey, result.key.id)
|
|
1508
|
-
|
|
1509
|
-
if (media.result !== WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS) {
|
|
1510
|
-
const resultStr = WAProto_1.proto.MediaRetryNotification.ResultType[media.result]
|
|
1511
|
-
|
|
1512
|
-
throw new boom_1.Boom(`Media re-upload failed by device (${resultStr})`, { data: media, statusCode: Utils_1.getStatusCodeForMediaRetry(media.result) || 404 })
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
content.directPath = media.directPath
|
|
1516
|
-
|
|
1517
|
-
content.url = Utils_1.getUrlFromDirectPath(content.directPath)
|
|
1518
|
-
|
|
1519
|
-
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful')
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
catch (err) {
|
|
1523
|
-
error = err
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
return true
|
|
1528
|
-
}
|
|
1529
|
-
})
|
|
1530
|
-
])
|
|
1531
|
-
|
|
1532
|
-
if (error) {
|
|
1533
|
-
throw error
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
ev.emit('messages.update', [
|
|
1537
|
-
{ key: message.key, update: { message: message.message } }
|
|
1538
|
-
])
|
|
1539
|
-
|
|
1540
|
-
return message
|
|
1541
|
-
},
|
|
1542
|
-
sendStatusMentions: async (content, jids = []) => {
|
|
1543
|
-
const userJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
|
|
1544
|
-
let allUsers = new Set()
|
|
1545
|
-
allUsers.add(userJid)
|
|
1546
|
-
|
|
1547
|
-
for (const id of jids) {
|
|
1548
|
-
const isGroup = WABinary_1.isJidGroup(id)
|
|
1549
|
-
const isPrivate = WABinary_1.isJidUser(id)
|
|
1550
|
-
|
|
1551
|
-
if (isGroup) {
|
|
1552
|
-
try {
|
|
1553
|
-
const metadata = await cachedGroupMetadata(id) || await groupMetadata(id)
|
|
1554
|
-
const participants = metadata.participants.map(p => WABinary_1.jidNormalizedUser(p.id))
|
|
1555
|
-
participants.forEach(jid => allUsers.add(jid))
|
|
1556
|
-
} catch (error) {
|
|
1557
|
-
logger.error(`Error getting metadata for group ${id}: ${error}`)
|
|
1558
|
-
}
|
|
1559
|
-
} else if (isPrivate) {
|
|
1560
|
-
allUsers.add(WABinary_1.jidNormalizedUser(id))
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
|
-
const uniqueUsers = Array.from(allUsers)
|
|
1565
|
-
const getRandomHexColor = () => "#" + Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")
|
|
1566
|
-
|
|
1567
|
-
const isMedia = content.image || content.video || content.audio
|
|
1568
|
-
const isAudio = !!content.audio
|
|
1569
|
-
|
|
1570
|
-
const messageContent = { ...content }
|
|
1571
|
-
|
|
1572
|
-
if (isMedia && !isAudio) {
|
|
1573
|
-
if (messageContent.text) {
|
|
1574
|
-
messageContent.caption = messageContent.text
|
|
1575
|
-
|
|
1576
|
-
delete messageContent.text
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
delete messageContent.ptt
|
|
1580
|
-
delete messageContent.font
|
|
1581
|
-
delete messageContent.backgroundColor
|
|
1582
|
-
delete messageContent.textColor
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
if (isAudio) {
|
|
1586
|
-
delete messageContent.text
|
|
1587
|
-
delete messageContent.caption
|
|
1588
|
-
delete messageContent.font
|
|
1589
|
-
delete messageContent.textColor
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
const font = !isMedia ? (content.font || Math.floor(Math.random() * 9)) : undefined
|
|
1593
|
-
const textColor = !isMedia ? (content.textColor || getRandomHexColor()) : undefined
|
|
1594
|
-
const backgroundColor = (!isMedia || isAudio) ? (content.backgroundColor || getRandomHexColor()) : undefined
|
|
1595
|
-
const ptt = isAudio ? (typeof content.ptt === 'boolean' ? content.ptt : true) : undefined
|
|
1596
|
-
|
|
1597
|
-
let msg
|
|
1598
|
-
let mediaHandle
|
|
1599
|
-
try {
|
|
1600
|
-
msg = await Utils_1.generateWAMessage(WABinary_1.STORIES_JID, messageContent, {
|
|
1601
|
-
logger,
|
|
1602
|
-
userJid,
|
|
1603
|
-
getUrlInfo: text => link_preview_1.getUrlInfo(text, {
|
|
1604
|
-
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1605
|
-
fetchOpts: { timeout: 3000, ...axiosOptions || {} },
|
|
1606
|
-
logger,
|
|
1607
|
-
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1608
|
-
}),
|
|
1609
|
-
upload: async (encFilePath, opts) => {
|
|
1610
|
-
const up = await waUploadToServer(encFilePath, { ...opts })
|
|
1611
|
-
mediaHandle = up.handle
|
|
1612
|
-
return up
|
|
1613
|
-
},
|
|
1614
|
-
mediaCache: config.mediaCache,
|
|
1615
|
-
options: config.options,
|
|
1616
|
-
font,
|
|
1617
|
-
textColor,
|
|
1618
|
-
backgroundColor,
|
|
1619
|
-
ptt
|
|
1620
|
-
})
|
|
1621
|
-
} catch (error) {
|
|
1622
|
-
logger.error(`Error generating message: ${error}`)
|
|
1623
|
-
throw error
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
await relayMessage(WABinary_1.STORIES_JID, msg.message, {
|
|
1627
|
-
messageId: msg.key.id,
|
|
1628
|
-
statusJidList: uniqueUsers,
|
|
1629
|
-
additionalNodes: [
|
|
1630
|
-
{
|
|
1631
|
-
tag: 'meta',
|
|
1632
|
-
attrs: {},
|
|
1633
|
-
content: [
|
|
1634
|
-
{
|
|
1635
|
-
tag: 'mentioned_users',
|
|
1636
|
-
attrs: {},
|
|
1637
|
-
content: jids.map(jid => ({
|
|
1638
|
-
tag: 'to',
|
|
1639
|
-
attrs: { jid: WABinary_1.jidNormalizedUser(jid) }
|
|
1640
|
-
}))
|
|
1641
|
-
}]
|
|
1642
|
-
}]
|
|
1643
|
-
})
|
|
1644
|
-
|
|
1645
|
-
for (const id of jids) {
|
|
1646
|
-
try {
|
|
1647
|
-
const normalizedId = WABinary_1.jidNormalizedUser(id)
|
|
1648
|
-
const isPrivate = WABinary_1.isJidUser(normalizedId)
|
|
1649
|
-
const type = isPrivate ? 'statusMentionMessage' : 'groupStatusMentionMessage'
|
|
1650
|
-
|
|
1651
|
-
const protocolMessage = {
|
|
1652
|
-
[type]: {
|
|
1653
|
-
message: {
|
|
1654
|
-
protocolMessage: {
|
|
1655
|
-
key: msg.key,
|
|
1656
|
-
type: 25
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
},
|
|
1660
|
-
messageContextInfo: {
|
|
1661
|
-
messageSecret: crypto_1.randomBytes(32)
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
|
|
1665
|
-
const statusMsg = await Utils_1.generateWAMessageFromContent(normalizedId,
|
|
1666
|
-
protocolMessage,
|
|
1667
|
-
{}
|
|
1668
|
-
)
|
|
1669
|
-
|
|
1670
|
-
await relayMessage(
|
|
1671
|
-
normalizedId,
|
|
1672
|
-
statusMsg.message,
|
|
1673
|
-
{
|
|
1674
|
-
additionalNodes: [{
|
|
1675
|
-
tag: 'meta',
|
|
1676
|
-
attrs: isPrivate ?
|
|
1677
|
-
{ is_status_mention: 'true' } :
|
|
1678
|
-
{ is_group_status_mention: 'true' }
|
|
1679
|
-
}]
|
|
1680
|
-
}
|
|
1681
|
-
)
|
|
1682
|
-
|
|
1683
|
-
await Utils_1.delay(2000)
|
|
1684
|
-
} catch (error) {
|
|
1685
|
-
logger.error(`Error sending to ${id}: ${error}`)
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
return msg
|
|
1690
|
-
},
|
|
1691
|
-
sendMessage: async (jid, content, options = {}) => {
|
|
1692
|
-
const userJid = authState.creds.me.id
|
|
1693
|
-
const additionalAttributes = {}
|
|
1694
|
-
|
|
1695
|
-
if (!options.ephemeralExpiration) {
|
|
1696
|
-
if (WABinary_1.isJidGroup(jid)) {
|
|
1697
|
-
const expiration = await getEphemeralGroup(jid)
|
|
1698
|
-
options.ephemeralExpiration = expiration
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
if (typeof content === 'object' &&
|
|
1703
|
-
'disappearingMessagesInChat' in content &&
|
|
1704
|
-
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
1705
|
-
WABinary_1.isJidGroup(jid)) {
|
|
1706
|
-
|
|
1707
|
-
const { disappearingMessagesInChat } = content
|
|
1708
|
-
|
|
1709
|
-
const value = typeof disappearingMessagesInChat === 'boolean' ?
|
|
1710
|
-
(disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
|
|
1711
|
-
disappearingMessagesInChat
|
|
1712
|
-
|
|
1713
|
-
await groupToggleEphemeral(jid, value)
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
else if (typeof content === 'object' && 'album' in content && content.album) {
|
|
1717
|
-
const albumMsg = await Utils_1.prepareAlbumMessageContent(jid, content.album, {
|
|
1718
|
-
suki: {
|
|
1719
|
-
relayMessage,
|
|
1720
|
-
waUploadToServer
|
|
1721
|
-
},
|
|
1722
|
-
userJid: userJid,
|
|
1723
|
-
...options
|
|
1724
|
-
})
|
|
1725
|
-
|
|
1726
|
-
for (const media of albumMsg) {
|
|
1727
|
-
await Utils_1.delay(options.delay || 500)
|
|
1728
|
-
await relayMessage(jid, media.message, { messageId: media.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
return albumMsg
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
else {
|
|
1735
|
-
let mediaHandle
|
|
1736
|
-
|
|
1737
|
-
const fullMsg = await Utils_1.generateWAMessage(jid, content, {
|
|
1738
|
-
logger,
|
|
1739
|
-
userJid,
|
|
1740
|
-
getUrlInfo: text => link_preview_1.getUrlInfo(text, {
|
|
1741
|
-
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1742
|
-
fetchOpts: {
|
|
1743
|
-
timeout: 3000,
|
|
1744
|
-
...axiosOptions || {}
|
|
1745
|
-
},
|
|
1746
|
-
logger,
|
|
1747
|
-
uploadImage: generateHighQualityLinkPreview
|
|
1748
|
-
? waUploadToServer
|
|
1749
|
-
: undefined
|
|
1750
|
-
}),
|
|
1751
|
-
getProfilePicUrl: profilePictureUrl,
|
|
1752
|
-
getCallLink: createCallLink,
|
|
1753
|
-
upload: async (encFilePath, opts) => {
|
|
1754
|
-
const up = await waUploadToServer(encFilePath, { ...opts, newsletter: WABinary_1.isJidNewsletter(jid) })
|
|
1755
|
-
mediaHandle = up.handle
|
|
1756
|
-
return up
|
|
1757
|
-
},
|
|
1758
|
-
mediaCache: config.mediaCache,
|
|
1759
|
-
options: config.options,
|
|
1760
|
-
messageId: Utils_1.generateMessageID(userJid),
|
|
1761
|
-
...options,
|
|
1762
|
-
})
|
|
1763
|
-
|
|
1764
|
-
const isPin = 'pin' in content && !!content.pin
|
|
1765
|
-
const isEdit = 'edit' in content && !!content.edit
|
|
1766
|
-
const isDelete = 'delete' in content && !!content.delete
|
|
1767
|
-
const isKeep = 'keep' in content && !!content.keep && content.keep?.type === 2
|
|
1768
|
-
|
|
1769
|
-
if (isDelete || isKeep) {
|
|
1770
|
-
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
1771
|
-
if (WABinary_1.isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe || WABinary_1.isJidNewsletter(jid)) {
|
|
1772
|
-
additionalAttributes.edit = '8'
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
|
-
else {
|
|
1776
|
-
additionalAttributes.edit = '7'
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
else if (isEdit) {
|
|
1781
|
-
additionalAttributes.edit = WABinary_1.isJidNewsletter(jid) ? '3' : '1'
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
else if (isPin) {
|
|
1785
|
-
additionalAttributes.edit = '2'
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
if (mediaHandle) {
|
|
1789
|
-
additionalAttributes['media_id'] = mediaHandle
|
|
1790
|
-
}
|
|
1791
|
-
|
|
1792
|
-
if ('cachedGroupMetadata' in options) {
|
|
1793
|
-
console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.')
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
|
|
1797
|
-
|
|
1798
|
-
if (config.emitOwnEvents) {
|
|
1799
|
-
process.nextTick(() => {
|
|
1800
|
-
processingMutex.mutex(() => (upsertMessage(fullMsg, 'append')))
|
|
1801
|
-
})
|
|
1802
|
-
}
|
|
1803
|
-
|
|
1804
|
-
return fullMsg
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
|
|
1810
|
-
module.exports = {
|
|
1811
|
-
makeMessagesSocket
|
|
1812
|
-
}
|