@badzz88/baileys 8.5.4 → 8.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/WAProto/WAProto.proto +75 -1256
- package/WAProto/index.d.ts +19729 -36122
- package/WAProto/index.js +132193 -178538
- package/engine-requirements.js +15 -7
- package/lib/Defaults/index.js +14 -22
- package/lib/Signal/Group/group_cipher.js +5 -5
- package/lib/Signal/Group/keyhelper.js +4 -4
- package/lib/Signal/Group/sender-chain-key.js +2 -2
- package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
- package/lib/Signal/Group/sender-key-message.js +3 -3
- package/lib/Signal/Group/sender-key-record.js +1 -1
- package/lib/Signal/Group/sender-message-key.js +5 -5
- package/lib/Signal/libsignal.js +28 -39
- package/lib/Signal/lid-mapping.js +8 -28
- package/lib/Socket/aigroups.js +5 -5
- package/lib/Socket/business.js +11 -3
- package/lib/Socket/chats.js +319 -668
- package/lib/Socket/communities.js +89 -85
- package/lib/Socket/graphql.js +228 -435
- package/lib/Socket/groups.js +211 -132
- package/lib/Socket/index.js +7 -9
- package/lib/Socket/interactive-handler.js +60 -117
- package/lib/Socket/interop.js +175 -56
- package/lib/Socket/luxu.js +387 -0
- package/lib/Socket/managed-account.js +48 -79
- package/lib/Socket/messages-recv.js +340 -898
- package/lib/Socket/messages-send.js +160 -462
- package/lib/Socket/mex.js +53 -40
- package/lib/Socket/newsletter.js +295 -291
- package/lib/Socket/privacy.js +265 -77
- package/lib/Socket/registration.js +157 -164
- package/lib/Socket/socket.js +199 -181
- package/lib/Socket/text-router.js +83 -0
- package/lib/Socket/username.js +227 -144
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +2 -2
- package/lib/Store/make-in-memory-store.js +141 -25
- package/lib/Types/Auth.js +3 -3
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Mex.js +112 -0
- package/lib/Types/Newsletter.js +65 -96
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +57 -52
- package/lib/Utils/browser-utils.js +1 -1
- package/lib/Utils/business.js +6 -2
- package/lib/Utils/chat-utils.js +38 -102
- package/lib/Utils/command-loader.d.ts +31 -0
- package/lib/Utils/command-loader.js +100 -0
- package/lib/Utils/companion-reg-client-utils.js +42 -0
- package/lib/Utils/crypto.js +84 -54
- package/lib/Utils/curve25519-js.js +275 -0
- package/lib/Utils/decode-wa-message.js +83 -316
- package/lib/Utils/event-buffer.js +61 -37
- package/lib/Utils/generics.js +103 -157
- package/lib/Utils/group-history.js +12 -3
- package/lib/Utils/history.js +15 -15
- package/lib/Utils/index.js +5 -1
- package/lib/Utils/link-preview.js +8 -3
- package/lib/Utils/lt-hash.js +35 -2
- package/lib/Utils/make-mutex.js +1 -1
- package/lib/Utils/message-retry-manager.js +92 -27
- package/lib/Utils/messages-media.js +130 -159
- package/lib/Utils/messages.js +566 -144
- package/lib/Utils/meta-ai-msmsg.js +202 -62
- package/lib/Utils/native-bridge.js +82 -0
- package/lib/Utils/noise-handler.js +21 -19
- package/lib/Utils/offline-node-processor.js +8 -3
- package/lib/Utils/pre-key-manager.js +23 -13
- package/lib/Utils/process-message.js +106 -197
- package/lib/Utils/reporting-utils.js +2 -2
- package/lib/Utils/session-pool.d.ts +16 -0
- package/lib/Utils/session-pool.js +94 -0
- package/lib/Utils/signal.js +63 -28
- package/lib/Utils/stanza-ack.js +12 -39
- package/lib/Utils/sticker.d.ts +17 -0
- package/lib/Utils/sticker.js +145 -0
- package/lib/Utils/sync-action-utils.js +7 -4
- package/lib/Utils/tc-token-utils.js +25 -20
- package/lib/Utils/use-multi-file-auth-state.js +14 -30
- package/lib/Utils/validate-connection.js +19 -59
- package/lib/Utils/view-once-cache.d.ts +9 -0
- package/lib/Utils/view-once-cache.js +79 -0
- package/lib/WABinary/decode.js +16 -50
- package/lib/WABinary/encode.js +224 -54
- package/lib/WABinary/generic-utils.js +97 -7
- package/lib/WABinary/jid-utils.js +14 -27
- package/lib/WAM/encode.js +7 -7
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +1 -58
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +1 -7
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +7 -20
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
- package/lib/WAUSync/Protocols/index.js +0 -1
- package/lib/WAUSync/USyncQuery.js +6 -77
- package/lib/WAUSync/USyncUser.js +8 -16
- package/lib/WAUSync/index.js +0 -1
- package/lib/antiban.js +854 -608
- package/lib/index.js +1 -1
- package/package.json +20 -16
|
@@ -59,9 +59,9 @@ const REAL_MSG_STUB_TYPES = new Set([
|
|
|
59
59
|
Types_1.WAMessageStubType.CALL_MISSED_VOICE
|
|
60
60
|
])
|
|
61
61
|
const REAL_MSG_REQ_ME_STUB_TYPES = new Set([Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD])
|
|
62
|
-
|
|
62
|
+
/** Cleans a received message to further processing */
|
|
63
63
|
const cleanMessage = (message, meId, meLid) => {
|
|
64
|
-
|
|
64
|
+
// ensure remoteJid and participant doesn't have device or agent in it
|
|
65
65
|
if ((0, WABinary_1.isHostedPnUser)(message.key.remoteJid) || (0, WABinary_1.isHostedLidUser)(message.key.remoteJid)) {
|
|
66
66
|
message.key.remoteJid = (0, WABinary_1.jidEncode)(
|
|
67
67
|
(0, WABinary_1.jidDecode)(message.key?.remoteJid)?.user,
|
|
@@ -82,7 +82,7 @@ const cleanMessage = (message, meId, meLid) => {
|
|
|
82
82
|
message.key.participant = (0, WABinary_1.jidNormalizedUser)(message.key.participant)
|
|
83
83
|
}
|
|
84
84
|
const content = (0, messages_1.normalizeMessageContent)(message.message)
|
|
85
|
-
|
|
85
|
+
// if the message has a reaction, ensure fromMe & remoteJid are from our perspective
|
|
86
86
|
if (content?.reactionMessage) {
|
|
87
87
|
normaliseKey(content.reactionMessage.key)
|
|
88
88
|
}
|
|
@@ -90,48 +90,47 @@ const cleanMessage = (message, meId, meLid) => {
|
|
|
90
90
|
normaliseKey(content.pollUpdateMessage.pollCreationMessageKey)
|
|
91
91
|
}
|
|
92
92
|
function normaliseKey(msgKey) {
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
// if the reaction is from another user
|
|
94
|
+
// we've to correctly map the key to this user's perspective
|
|
95
95
|
if (!message.key.fromMe) {
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
// if the sender believed the message being reacted to is not from them
|
|
97
|
+
// we've to correct the key to be from them, or some other participant
|
|
98
98
|
msgKey.fromMe = !msgKey.fromMe
|
|
99
99
|
? (0, WABinary_1.areJidsSameUser)(msgKey.participant || msgKey.remoteJid, meId) ||
|
|
100
100
|
(0, WABinary_1.areJidsSameUser)(msgKey.participant || msgKey.remoteJid, meLid)
|
|
101
|
-
:
|
|
102
|
-
|
|
101
|
+
: // if the message being reacted to, was from them
|
|
102
|
+
// fromMe automatically becomes false
|
|
103
103
|
false
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
// set the remoteJid to being the same as the chat the message came from
|
|
105
|
+
// TODO: investigate inconsistencies
|
|
106
106
|
msgKey.remoteJid = message.key.remoteJid
|
|
107
|
-
|
|
107
|
+
// set participant of the message
|
|
108
108
|
msgKey.participant = msgKey.participant || message.key.participant
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
exports.cleanMessage = cleanMessage
|
|
113
|
+
// TODO: target:audit AUDIT THIS FUNCTION AGAIN
|
|
113
114
|
const isRealMessage = message => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (REAL_MSG_STUB_TYPES.has(message.messageStubType) || REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) {
|
|
118
|
-
return true
|
|
119
|
-
}
|
|
120
115
|
const normalizedContent = (0, messages_1.normalizeMessageContent)(message.message)
|
|
121
116
|
const hasSomeContent = !!(0, messages_1.getContentType)(normalizedContent)
|
|
122
117
|
return (
|
|
123
|
-
!!normalizedContent
|
|
118
|
+
(!!normalizedContent ||
|
|
119
|
+
REAL_MSG_STUB_TYPES.has(message.messageStubType) ||
|
|
120
|
+
REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) &&
|
|
124
121
|
hasSomeContent &&
|
|
125
122
|
!normalizedContent?.protocolMessage &&
|
|
126
123
|
!normalizedContent?.reactionMessage &&
|
|
127
|
-
!normalizedContent?.pollUpdateMessage
|
|
128
|
-
!normalizedContent?.secretEncryptedMessage
|
|
124
|
+
!normalizedContent?.pollUpdateMessage
|
|
129
125
|
)
|
|
130
126
|
}
|
|
131
127
|
exports.isRealMessage = isRealMessage
|
|
132
128
|
const shouldIncrementChatUnread = message => !message.key.fromMe && !message.messageStubType
|
|
133
129
|
exports.shouldIncrementChatUnread = shouldIncrementChatUnread
|
|
134
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Get the ID of the chat from the given key.
|
|
132
|
+
* Typically -- that'll be the remoteJid, but for broadcasts, it'll be the participant
|
|
133
|
+
*/
|
|
135
134
|
const getChatId = ({ remoteJid, participant, fromMe }) => {
|
|
136
135
|
if ((0, WABinary_1.isJidBroadcast)(remoteJid) && !(0, WABinary_1.isJidStatusBroadcast)(remoteJid) && !fromMe) {
|
|
137
136
|
return participant
|
|
@@ -139,7 +138,12 @@ const getChatId = ({ remoteJid, participant, fromMe }) => {
|
|
|
139
138
|
return remoteJid
|
|
140
139
|
}
|
|
141
140
|
exports.getChatId = getChatId
|
|
142
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Decrypt a poll vote
|
|
143
|
+
* @param vote encrypted vote
|
|
144
|
+
* @param ctx additional info about the poll required for decryption
|
|
145
|
+
* @returns list of SHA256 options
|
|
146
|
+
*/
|
|
143
147
|
function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pollEncKey, voterJid }) {
|
|
144
148
|
const sign = Buffer.concat([
|
|
145
149
|
toBinary(pollMsgId),
|
|
@@ -157,7 +161,12 @@ function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pol
|
|
|
157
161
|
return Buffer.from(txt)
|
|
158
162
|
}
|
|
159
163
|
}
|
|
160
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Decrypt an event response
|
|
166
|
+
* @param response encrypted event response
|
|
167
|
+
* @param ctx additional info about the event required for decryption
|
|
168
|
+
* @returns event response message
|
|
169
|
+
*/
|
|
161
170
|
function decryptEventResponse({ encPayload, encIv }, { eventCreatorJid, eventMsgId, eventEncKey, responderJid }) {
|
|
162
171
|
const sign = Buffer.concat([
|
|
163
172
|
toBinary(eventMsgId),
|
|
@@ -175,108 +184,6 @@ function decryptEventResponse({ encPayload, encIv }, { eventCreatorJid, eventMsg
|
|
|
175
184
|
return Buffer.from(txt)
|
|
176
185
|
}
|
|
177
186
|
}
|
|
178
|
-
|
|
179
|
-
function decryptMessageEdit({ encPayload, encIv }, { origMsgId, origMsgSenderJid, editorJid, msgEncKey }) {
|
|
180
|
-
const sign = Buffer.concat([
|
|
181
|
-
toBinary(origMsgId),
|
|
182
|
-
toBinary(origMsgSenderJid),
|
|
183
|
-
toBinary(editorJid),
|
|
184
|
-
toBinary('Message Edit'),
|
|
185
|
-
new Uint8Array([1])
|
|
186
|
-
])
|
|
187
|
-
const key0 = (0, crypto_1.hmacSign)(msgEncKey, new Uint8Array(32), 'sha256')
|
|
188
|
-
const decKey = (0, crypto_1.hmacSign)(sign, key0, 'sha256')
|
|
189
|
-
|
|
190
|
-
const decrypted = (0, crypto_1.aesDecryptGCM)(encPayload, decKey, encIv, new Uint8Array(0))
|
|
191
|
-
return index_js_1.proto.Message.decode(decrypted)
|
|
192
|
-
function toBinary(txt) {
|
|
193
|
-
return Buffer.from(txt)
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
exports.decryptMessageEdit = decryptMessageEdit
|
|
197
|
-
|
|
198
|
-
const unwrapSecretEncryptedMessage = async (message, { creds, getMessage, logger }) => {
|
|
199
|
-
const content = (0, messages_1.normalizeMessageContent)(message.message)
|
|
200
|
-
const secretEnc = content?.secretEncryptedMessage
|
|
201
|
-
if (
|
|
202
|
-
!secretEnc?.encPayload ||
|
|
203
|
-
!secretEnc.encIv ||
|
|
204
|
-
secretEnc.secretEncType !== index_js_1.proto.Message.SecretEncryptedMessage.SecretEncType.MESSAGE_EDIT
|
|
205
|
-
) {
|
|
206
|
-
return
|
|
207
|
-
}
|
|
208
|
-
const targetKey = secretEnc.targetMessageKey
|
|
209
|
-
if (!targetKey?.id) {
|
|
210
|
-
return
|
|
211
|
-
}
|
|
212
|
-
try {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const origMsg = await getMessage({
|
|
216
|
-
...targetKey,
|
|
217
|
-
remoteJid: message.key.remoteJid,
|
|
218
|
-
fromMe: message.key.fromMe,
|
|
219
|
-
participant: message.key.participant
|
|
220
|
-
})
|
|
221
|
-
let msgEncKey = origMsg?.messageContextInfo?.messageSecret
|
|
222
|
-
if (typeof msgEncKey === 'string') {
|
|
223
|
-
|
|
224
|
-
msgEncKey = Buffer.from(msgEncKey, 'base64')
|
|
225
|
-
}
|
|
226
|
-
if (!msgEncKey?.length) {
|
|
227
|
-
logger?.warn({ targetKey }, 'message edit: missing messageSecret for decryption')
|
|
228
|
-
return
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(creds.me.id)
|
|
233
|
-
const candidates = [
|
|
234
|
-
...(message.key.fromMe
|
|
235
|
-
? [meIdNormalised, creds.me?.lid]
|
|
236
|
-
: [message.key.participant || message.key.remoteJid, message.key.participantAlt || message.key.remoteJidAlt]),
|
|
237
|
-
targetKey.remoteJid
|
|
238
|
-
]
|
|
239
|
-
.filter(jid => !!jid)
|
|
240
|
-
.map(jid => (0, WABinary_1.jidNormalizedUser)(jid))
|
|
241
|
-
.filter((jid, i, arr) => arr.indexOf(jid) === i)
|
|
242
|
-
let decoded
|
|
243
|
-
let lastError
|
|
244
|
-
for (const authorJid of candidates) {
|
|
245
|
-
try {
|
|
246
|
-
decoded = decryptMessageEdit(secretEnc, {
|
|
247
|
-
origMsgId: targetKey.id,
|
|
248
|
-
origMsgSenderJid: authorJid,
|
|
249
|
-
editorJid: authorJid,
|
|
250
|
-
msgEncKey
|
|
251
|
-
})
|
|
252
|
-
break
|
|
253
|
-
} catch (err) {
|
|
254
|
-
lastError = err
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (!decoded) {
|
|
258
|
-
throw lastError
|
|
259
|
-
}
|
|
260
|
-
if (!decoded.protocolMessage) {
|
|
261
|
-
|
|
262
|
-
decoded = index_js_1.proto.Message.fromObject({
|
|
263
|
-
protocolMessage: {
|
|
264
|
-
key: targetKey,
|
|
265
|
-
type: index_js_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
|
|
266
|
-
editedMessage: decoded
|
|
267
|
-
}
|
|
268
|
-
})
|
|
269
|
-
}
|
|
270
|
-
if (!decoded.messageContextInfo && content?.messageContextInfo) {
|
|
271
|
-
decoded.messageContextInfo = content.messageContextInfo
|
|
272
|
-
}
|
|
273
|
-
message.message = decoded
|
|
274
|
-
logger?.debug({ targetKey }, 'decrypted secretEncryptedMessage edit')
|
|
275
|
-
} catch (err) {
|
|
276
|
-
logger?.warn({ err, targetKey }, 'failed to decrypt secretEncryptedMessage edit')
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
exports.unwrapSecretEncryptedMessage = unwrapSecretEncryptedMessage
|
|
280
187
|
const processMessage = async (
|
|
281
188
|
message,
|
|
282
189
|
{
|
|
@@ -298,7 +205,7 @@ const processMessage = async (
|
|
|
298
205
|
if (isRealMsg) {
|
|
299
206
|
chat.messages = [{ message }]
|
|
300
207
|
chat.conversationTimestamp = (0, generics_1.toNumber)(message.messageTimestamp)
|
|
301
|
-
|
|
208
|
+
// only increment unread count if not CIPHERTEXT and from another person
|
|
302
209
|
if ((0, exports.shouldIncrementChatUnread)(message)) {
|
|
303
210
|
chat.unreadCount = (chat.unreadCount || 0) + 1
|
|
304
211
|
}
|
|
@@ -329,8 +236,8 @@ const processMessage = async (
|
|
|
329
236
|
})
|
|
330
237
|
}
|
|
331
238
|
const content = (0, messages_1.normalizeMessageContent)(message.message)
|
|
332
|
-
|
|
333
|
-
|
|
239
|
+
// unarchive chat if it's a real message, or someone reacted to our message
|
|
240
|
+
// and we've the unarchive chats setting on
|
|
334
241
|
if ((isRealMsg || content?.reactionMessage?.key?.fromMe) && accountSettings?.unarchiveChats) {
|
|
335
242
|
chat.archived = false
|
|
336
243
|
chat.readOnly = false
|
|
@@ -352,7 +259,7 @@ const processMessage = async (
|
|
|
352
259
|
'got history notification'
|
|
353
260
|
)
|
|
354
261
|
if (process) {
|
|
355
|
-
|
|
262
|
+
// TODO: investigate
|
|
356
263
|
if (histNotification.syncType !== index_js_1.proto.HistorySync.HistorySyncType.ON_DEMAND) {
|
|
357
264
|
ev.emit('creds.update', {
|
|
358
265
|
processedHistoryMessages: [
|
|
@@ -418,31 +325,31 @@ const processMessage = async (
|
|
|
418
325
|
case index_js_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
|
|
419
326
|
const response = protocolMsg.peerDataOperationRequestResponseMessage
|
|
420
327
|
if (response) {
|
|
421
|
-
|
|
328
|
+
// TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
|
|
422
329
|
const peerDataOperationResult = response.peerDataOperationResult || []
|
|
423
330
|
for (const result of peerDataOperationResult) {
|
|
424
331
|
const retryResponse = result?.placeholderMessageResendResponse
|
|
425
|
-
|
|
332
|
+
//eslint-disable-next-line max-depth
|
|
426
333
|
if (!retryResponse?.webMessageInfoBytes) {
|
|
427
334
|
continue
|
|
428
335
|
}
|
|
429
|
-
|
|
336
|
+
//eslint-disable-next-line max-depth
|
|
430
337
|
try {
|
|
431
338
|
const webMessageInfo = index_js_1.proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes)
|
|
432
339
|
const msgId = webMessageInfo.key?.id
|
|
433
|
-
|
|
434
|
-
|
|
340
|
+
// Retrieve cached original message data (preserves LID details,
|
|
341
|
+
// timestamps, etc. that the phone may omit in its PDO response)
|
|
435
342
|
const cachedData = msgId ? await placeholderResendCache?.get(msgId) : undefined
|
|
436
|
-
|
|
343
|
+
//eslint-disable-next-line max-depth
|
|
437
344
|
if (msgId) {
|
|
438
345
|
await placeholderResendCache?.del(msgId)
|
|
439
346
|
}
|
|
440
347
|
let finalMsg
|
|
441
|
-
|
|
348
|
+
//eslint-disable-next-line max-depth
|
|
442
349
|
if (cachedData && typeof cachedData === 'object') {
|
|
443
|
-
|
|
350
|
+
// Apply decoded message content onto cached metadata (preserves LID etc.)
|
|
444
351
|
cachedData.message = webMessageInfo.message
|
|
445
|
-
|
|
352
|
+
//eslint-disable-next-line max-depth
|
|
446
353
|
if (webMessageInfo.messageTimestamp) {
|
|
447
354
|
cachedData.messageTimestamp = webMessageInfo.messageTimestamp
|
|
448
355
|
}
|
|
@@ -465,7 +372,7 @@ const processMessage = async (
|
|
|
465
372
|
case index_js_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT:
|
|
466
373
|
ev.emit('messages.update', [
|
|
467
374
|
{
|
|
468
|
-
|
|
375
|
+
// flip the sender / fromMe properties because they're in the perspective of the sender
|
|
469
376
|
key: { ...message.key, id: protocolMsg.key?.id },
|
|
470
377
|
update: {
|
|
471
378
|
message: {
|
|
@@ -482,12 +389,10 @@ const processMessage = async (
|
|
|
482
389
|
break
|
|
483
390
|
case index_js_1.proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE:
|
|
484
391
|
const labelAssociationMsg = protocolMsg.memberLabel
|
|
485
|
-
if (labelAssociationMsg) {
|
|
486
|
-
|
|
487
|
-
|
|
392
|
+
if (labelAssociationMsg?.label) {
|
|
488
393
|
ev.emit('group.member-tag.update', {
|
|
489
394
|
groupId: chat.id,
|
|
490
|
-
label: labelAssociationMsg.label
|
|
395
|
+
label: labelAssociationMsg.label,
|
|
491
396
|
participant: message.key.participant,
|
|
492
397
|
participantAlt: message.key.participantAlt,
|
|
493
398
|
messageTimestamp: Number(message.messageTimestamp)
|
|
@@ -711,12 +616,12 @@ const processMessage = async (
|
|
|
711
616
|
} else if (content?.encEventResponseMessage) {
|
|
712
617
|
const encEventResponse = content.encEventResponseMessage
|
|
713
618
|
const creationMsgKey = encEventResponse.eventCreationMessageKey
|
|
714
|
-
|
|
619
|
+
// we need to fetch the event creation message to get the event enc key
|
|
715
620
|
const eventMsg = await getMessage(creationMsgKey)
|
|
716
621
|
if (eventMsg) {
|
|
717
622
|
try {
|
|
718
623
|
const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(meId)
|
|
719
|
-
|
|
624
|
+
// all jids need to be PN
|
|
720
625
|
const eventCreatorKey = creationMsgKey.participant || creationMsgKey.remoteJid
|
|
721
626
|
const eventCreatorPn = (0, WABinary_1.isLidUser)(eventCreatorKey)
|
|
722
627
|
? await signalRepository.lidMapping.getPNForLID(eventCreatorKey)
|
|
@@ -758,7 +663,7 @@ const processMessage = async (
|
|
|
758
663
|
}
|
|
759
664
|
} else if (message.messageStubType) {
|
|
760
665
|
const jid = message.key?.remoteJid
|
|
761
|
-
|
|
666
|
+
//let actor = whatsappID (message.participant)
|
|
762
667
|
let participants
|
|
763
668
|
const emitParticipantsUpdate = action =>
|
|
764
669
|
ev.emit('group-participants.update', {
|
|
@@ -774,7 +679,7 @@ const processMessage = async (
|
|
|
774
679
|
{
|
|
775
680
|
id: jid,
|
|
776
681
|
...update,
|
|
777
|
-
author: message.key.participant,
|
|
682
|
+
author: message.key.participant ?? undefined,
|
|
778
683
|
authorPn: message.key.participantAlt,
|
|
779
684
|
authorUsername: message.key.participantUsername
|
|
780
685
|
}
|
|
@@ -793,7 +698,7 @@ const processMessage = async (
|
|
|
793
698
|
})
|
|
794
699
|
}
|
|
795
700
|
const participantsIncludesMe = () =>
|
|
796
|
-
participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid.phoneNumber))
|
|
701
|
+
participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid.phoneNumber)) // ADD SUPPORT FOR LID
|
|
797
702
|
switch (message.messageStubType) {
|
|
798
703
|
case Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
|
|
799
704
|
participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
|
|
@@ -803,7 +708,7 @@ const processMessage = async (
|
|
|
803
708
|
case Types_1.WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
|
804
709
|
participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
|
|
805
710
|
emitParticipantsUpdate('remove')
|
|
806
|
-
|
|
711
|
+
// mark the chat read only if you left the group
|
|
807
712
|
if (participantsIncludesMe()) {
|
|
808
713
|
chat.readOnly = true
|
|
809
714
|
}
|
|
@@ -855,7 +760,7 @@ const processMessage = async (
|
|
|
855
760
|
const approvalMode = message.messageStubParameters?.[0]
|
|
856
761
|
emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' })
|
|
857
762
|
break
|
|
858
|
-
case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD:
|
|
763
|
+
case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: // TODO: Add other events
|
|
859
764
|
const participant = JSON.parse(message.messageStubParameters?.[0])
|
|
860
765
|
const action = message.messageStubParameters?.[1]
|
|
861
766
|
const method = message.messageStubParameters?.[2]
|
|
@@ -945,7 +850,7 @@ const processMessage = async (
|
|
|
945
850
|
ev.emit('chats.update', [{ id: jid, psa: { urlParams: message.messageStubParameters } }])
|
|
946
851
|
break
|
|
947
852
|
case Types_1.WAMessageStubType.CHAT_POLL_CREATION_MESSAGE:
|
|
948
|
-
|
|
853
|
+
// poll was created, no special action needed beyond message processing
|
|
949
854
|
break
|
|
950
855
|
case Types_1.WAMessageStubType.BIZ_CHAT_ASSIGNMENT:
|
|
951
856
|
ev.emit('chats.update', [
|
|
@@ -1087,51 +992,55 @@ const processMessage = async (
|
|
|
1087
992
|
emitGroupUpdate({ hidden: true })
|
|
1088
993
|
break
|
|
1089
994
|
}
|
|
1090
|
-
} else if
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
995
|
+
} /* else if(content?.pollUpdateMessage) {
|
|
996
|
+
const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey!
|
|
997
|
+
// we need to fetch the poll creation message to get the poll enc key
|
|
998
|
+
// TODO: make standalone, remove getMessage reference
|
|
999
|
+
// TODO: Remove entirely
|
|
1000
|
+
const pollMsg = await getMessage(creationMsgKey)
|
|
1001
|
+
if(pollMsg) {
|
|
1002
|
+
const meIdNormalised = jidNormalizedUser(meId)
|
|
1003
|
+
const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
|
|
1004
|
+
const voterJid = getKeyAuthor(message.key, meIdNormalised)
|
|
1005
|
+
const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
|
|
1006
|
+
|
|
1007
|
+
try {
|
|
1008
|
+
const voteMsg = decryptPollVote(
|
|
1009
|
+
content.pollUpdateMessage.vote!,
|
|
1010
|
+
{
|
|
1011
|
+
pollEncKey,
|
|
1012
|
+
pollCreatorJid,
|
|
1013
|
+
pollMsgId: creationMsgKey.id!,
|
|
1014
|
+
voterJid,
|
|
1015
|
+
}
|
|
1016
|
+
)
|
|
1017
|
+
ev.emit('messages.update', [
|
|
1018
|
+
{
|
|
1019
|
+
key: creationMsgKey,
|
|
1020
|
+
update: {
|
|
1021
|
+
pollUpdates: [
|
|
1022
|
+
{
|
|
1023
|
+
pollUpdateMessageKey: message.key,
|
|
1024
|
+
vote: voteMsg,
|
|
1025
|
+
senderTimestampMs: (content.pollUpdateMessage.senderTimestampMs! as Long).toNumber(),
|
|
1026
|
+
}
|
|
1027
|
+
]
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
])
|
|
1031
|
+
} catch(err) {
|
|
1032
|
+
logger?.warn(
|
|
1033
|
+
{ err, creationMsgKey },
|
|
1034
|
+
'failed to decrypt poll vote'
|
|
1035
|
+
)
|
|
1036
|
+
}
|
|
1037
|
+
} else {
|
|
1038
|
+
logger?.warn(
|
|
1039
|
+
{ creationMsgKey },
|
|
1040
|
+
'poll creation message not found, cannot decrypt update'
|
|
1041
|
+
)
|
|
1042
|
+
}
|
|
1043
|
+
} */
|
|
1135
1044
|
if (Object.keys(chat).length > 1) {
|
|
1136
1045
|
ev.emit('chats.update', [chat])
|
|
1137
1046
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
Object.defineProperty(exports, '__esModule', { value: true })
|
|
3
3
|
exports.getMessageReportingToken = exports.shouldIncludeReportingToken = void 0
|
|
4
|
-
const
|
|
4
|
+
const Crypto_1 = require('./crypto')
|
|
5
5
|
const crypto_2 = require('./crypto')
|
|
6
6
|
const reportingFields = [
|
|
7
7
|
{ f: 1 },
|
|
@@ -246,7 +246,7 @@ const getMessageReportingToken = async (msgProtobuf, message, key) => {
|
|
|
246
246
|
if (!content || content.length === 0) {
|
|
247
247
|
return null
|
|
248
248
|
}
|
|
249
|
-
const reportingToken = Buffer.from(
|
|
249
|
+
const reportingToken = Buffer.from(Crypto_1.hmacSign(content, reportingSecret)).subarray(0, 16)
|
|
250
250
|
return {
|
|
251
251
|
tag: 'reporting',
|
|
252
252
|
attrs: {},
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SessionPoolOptions {
|
|
2
|
+
makeSocket: (sessionId: string) => Promise<any> | any
|
|
3
|
+
logger?: any
|
|
4
|
+
maxBackoffMs?: number
|
|
5
|
+
onSessionUpdate?: (sessionId: string, sock: any) => void
|
|
6
|
+
onLoggedOut?: (sessionId: string) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SessionPool {
|
|
10
|
+
add: (sessionId: string) => Promise<void>
|
|
11
|
+
remove: (sessionId: string) => void
|
|
12
|
+
get: (sessionId: string) => any
|
|
13
|
+
list: () => string[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createSessionPool(options: SessionPoolOptions): SessionPool
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
Object.defineProperty(exports, '__esModule', { value: true })
|
|
3
|
+
exports.createSessionPool = void 0
|
|
4
|
+
|
|
5
|
+
const DISCONNECT_REASON_LOGGED_OUT = 401
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Manages multiple Baileys socket instances (one per account/session), automatically
|
|
9
|
+
* restarting any session that disconnects -- except when it was logged out -- using
|
|
10
|
+
* exponential backoff with jitter, instead of every project re-implementing its own
|
|
11
|
+
* reconnect loop.
|
|
12
|
+
*
|
|
13
|
+
* @param {{
|
|
14
|
+
* makeSocket: (sessionId: string) => Promise<any> | any,
|
|
15
|
+
* logger?: any,
|
|
16
|
+
* maxBackoffMs?: number,
|
|
17
|
+
* onSessionUpdate?: (sessionId: string, sock: any) => void,
|
|
18
|
+
* onLoggedOut?: (sessionId: string) => void
|
|
19
|
+
* }} options
|
|
20
|
+
* @returns {{
|
|
21
|
+
* add: (sessionId: string) => Promise<void>,
|
|
22
|
+
* remove: (sessionId: string) => void,
|
|
23
|
+
* get: (sessionId: string) => any,
|
|
24
|
+
* list: () => string[]
|
|
25
|
+
* }}
|
|
26
|
+
*/
|
|
27
|
+
const createSessionPool = options => {
|
|
28
|
+
const logger = options.logger
|
|
29
|
+
const maxBackoffMs = options.maxBackoffMs ?? 60000
|
|
30
|
+
const sessions = new Map() // sessionId -> { sock, attempts, stopped }
|
|
31
|
+
|
|
32
|
+
const computeBackoffMs = attempts => {
|
|
33
|
+
const base = Math.min(1000 * 2 ** attempts, maxBackoffMs)
|
|
34
|
+
return base + Math.floor(Math.random() * (base * 0.2))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const start = async sessionId => {
|
|
38
|
+
const entry = sessions.get(sessionId) || { attempts: 0, stopped: false }
|
|
39
|
+
sessions.set(sessionId, entry)
|
|
40
|
+
if (entry.stopped) return
|
|
41
|
+
try {
|
|
42
|
+
const sock = await options.makeSocket(sessionId)
|
|
43
|
+
entry.sock = sock
|
|
44
|
+
options.onSessionUpdate?.(sessionId, sock)
|
|
45
|
+
sock.ev.on('connection.update', update => {
|
|
46
|
+
if (update.connection === 'open') {
|
|
47
|
+
entry.attempts = 0
|
|
48
|
+
}
|
|
49
|
+
if (update.connection === 'close') {
|
|
50
|
+
const statusCode = update.lastDisconnect?.error?.output?.statusCode
|
|
51
|
+
if (statusCode === DISCONNECT_REASON_LOGGED_OUT) {
|
|
52
|
+
logger?.info?.({ sessionId }, 'session logged out, removing from pool')
|
|
53
|
+
sessions.delete(sessionId)
|
|
54
|
+
options.onLoggedOut?.(sessionId)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
if (entry.stopped) return
|
|
58
|
+
entry.attempts += 1
|
|
59
|
+
const backoffMs = computeBackoffMs(entry.attempts)
|
|
60
|
+
logger?.warn?.(
|
|
61
|
+
{ sessionId, attempt: entry.attempts, backoffMs },
|
|
62
|
+
'session disconnected, reconnecting with backoff'
|
|
63
|
+
)
|
|
64
|
+
setTimeout(() => start(sessionId), backoffMs)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
} catch (error) {
|
|
68
|
+
entry.attempts += 1
|
|
69
|
+
const backoffMs = computeBackoffMs(entry.attempts)
|
|
70
|
+
logger?.error?.({ error, sessionId, backoffMs }, 'failed to start session, retrying with backoff')
|
|
71
|
+
if (!entry.stopped) {
|
|
72
|
+
setTimeout(() => start(sessionId), backoffMs)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const add = sessionId => start(sessionId)
|
|
78
|
+
const remove = sessionId => {
|
|
79
|
+
const entry = sessions.get(sessionId)
|
|
80
|
+
if (!entry) return
|
|
81
|
+
entry.stopped = true
|
|
82
|
+
if (entry.sock?.end) {
|
|
83
|
+
try {
|
|
84
|
+
entry.sock.end(undefined)
|
|
85
|
+
} catch {}
|
|
86
|
+
}
|
|
87
|
+
sessions.delete(sessionId)
|
|
88
|
+
}
|
|
89
|
+
const get = sessionId => sessions.get(sessionId)?.sock
|
|
90
|
+
const list = () => [...sessions.keys()]
|
|
91
|
+
|
|
92
|
+
return { add, remove, get, list }
|
|
93
|
+
}
|
|
94
|
+
exports.createSessionPool = createSessionPool
|