@badzz88/baileys 8.5.2 → 8.5.4
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 +1256 -75
- package/WAProto/index.d.ts +36042 -19649
- package/WAProto/index.js +181990 -135645
- package/engine-requirements.js +7 -15
- package/lib/Defaults/index.js +22 -17
- 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 +39 -59
- package/lib/Signal/lid-mapping.js +28 -10
- package/lib/Socket/aigroups.js +5 -5
- package/lib/Socket/business.js +3 -11
- package/lib/Socket/chats.js +668 -319
- package/lib/Socket/communities.js +85 -89
- package/lib/Socket/graphql.js +435 -228
- package/lib/Socket/groups.js +132 -211
- package/lib/Socket/index.js +9 -7
- package/lib/Socket/interactive-handler.js +117 -60
- package/lib/Socket/interop.js +56 -175
- package/lib/Socket/managed-account.js +79 -48
- package/lib/Socket/messages-recv.js +898 -340
- package/lib/Socket/messages-send.js +462 -160
- package/lib/Socket/mex.js +40 -53
- package/lib/Socket/newsletter.js +291 -291
- package/lib/Socket/privacy.js +77 -265
- package/lib/Socket/registration.js +164 -157
- package/lib/Socket/socket.js +181 -199
- package/lib/Socket/username.js +144 -227
- package/lib/Store/make-cache-manager-store.js +2 -2
- package/lib/Store/make-in-memory-store.js +25 -141
- package/lib/Types/Auth.js +3 -3
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Newsletter.js +96 -65
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +52 -57
- package/lib/Utils/browser-utils.js +1 -1
- package/lib/Utils/business.js +2 -6
- package/lib/Utils/chat-utils.js +102 -38
- package/lib/Utils/crypto.js +54 -84
- package/lib/Utils/decode-wa-message.js +316 -83
- package/lib/Utils/event-buffer.js +37 -61
- package/lib/Utils/generics.js +157 -103
- package/lib/Utils/group-history.js +3 -12
- package/lib/Utils/history.js +15 -15
- package/lib/Utils/index.js +1 -5
- package/lib/Utils/link-preview.js +3 -8
- package/lib/Utils/lt-hash.js +2 -35
- package/lib/Utils/make-mutex.js +1 -1
- package/lib/Utils/message-inspect.js +393 -0
- package/lib/Utils/message-retry-manager.js +27 -92
- package/lib/Utils/messages-media.js +159 -130
- package/lib/Utils/messages.js +144 -566
- package/lib/Utils/meta-ai-msmsg.js +62 -202
- package/lib/Utils/noise-handler.js +19 -21
- package/lib/Utils/offline-node-processor.js +3 -8
- package/lib/Utils/pre-key-manager.js +13 -23
- package/lib/Utils/process-message.js +197 -106
- package/lib/Utils/reporting-utils.js +2 -2
- package/lib/Utils/signal.js +28 -63
- package/lib/Utils/stanza-ack.js +39 -12
- package/lib/Utils/sync-action-utils.js +4 -7
- package/lib/Utils/tc-token-utils.js +20 -25
- package/lib/Utils/use-multi-file-auth-state.js +30 -14
- package/lib/Utils/validate-connection.js +59 -19
- package/lib/WABinary/decode.js +50 -16
- package/lib/WABinary/encode.js +54 -224
- package/lib/WABinary/generic-utils.js +7 -97
- package/lib/WABinary/jid-utils.js +27 -14
- package/lib/WAM/encode.js +7 -7
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +58 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +13 -5
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -4
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +20 -7
- package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +865 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -2
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +2 -1
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/USyncBackoff.js +26 -0
- package/lib/WAUSync/USyncQuery.js +77 -6
- package/lib/WAUSync/USyncUser.js +16 -8
- package/lib/WAUSync/index.js +1 -0
- package/lib/antiban.js +608 -854
- package/lib/index.js +3 -3
- package/package.json +16 -19
- package/lib/Socket/luxu.js +0 -387
- package/lib/Socket/text-router.js +0 -83
- package/lib/Store/keyed-db.js +0 -108
- package/lib/Types/Mex.js +0 -112
- package/lib/Utils/command-loader.d.ts +0 -31
- package/lib/Utils/command-loader.js +0 -100
- package/lib/Utils/companion-reg-client-utils.js +0 -42
- package/lib/Utils/curve25519-js.js +0 -275
- package/lib/Utils/native-bridge.js +0 -82
- package/lib/Utils/session-pool.d.ts +0 -16
- package/lib/Utils/session-pool.js +0 -94
- package/lib/Utils/sticker.d.ts +0 -17
- package/lib/Utils/sticker.js +0 -145
- package/lib/Utils/view-once-cache.d.ts +0 -9
- package/lib/Utils/view-once-cache.js +0 -79
|
@@ -14,7 +14,7 @@ const {
|
|
|
14
14
|
} = require('../Utils/index.js')
|
|
15
15
|
const { isJidGroup, isPnUser, jidNormalizedUser, STORIES_JID } = require('../WABinary/index.js')
|
|
16
16
|
|
|
17
|
-
class
|
|
17
|
+
class badzz88 {
|
|
18
18
|
constructor(waUploadToServer, relayMessageFn, config, sock) {
|
|
19
19
|
this.relayMessage = relayMessageFn
|
|
20
20
|
this.waUploadToServer = waUploadToServer
|
|
@@ -24,13 +24,12 @@ class InteractiveMessageHandler {
|
|
|
24
24
|
detectType(content) {
|
|
25
25
|
if (content.requestPaymentMessage) return 'PAYMENT'
|
|
26
26
|
if (content.productMessage) return 'PRODUCT'
|
|
27
|
+
if (content.interactiveButtons) return 'INTERACTIVE_BUTTONS'
|
|
27
28
|
if (content.interactiveMessage) return 'INTERACTIVE'
|
|
28
29
|
if (content.albumMessage || content.album) return 'ALBUM'
|
|
29
30
|
if (content.eventMessage) return 'EVENT'
|
|
30
31
|
if (content.pollResultMessage) return 'POLL_RESULT'
|
|
31
32
|
if (content.groupStatusMessage) return 'GROUP_STORY'
|
|
32
|
-
if (content.orderMessage) return 'ORDER'
|
|
33
|
-
if (content.groupLabel) return 'GROUP_LABEL'
|
|
34
33
|
return null
|
|
35
34
|
}
|
|
36
35
|
async handlePayment(content, quoted) {
|
|
@@ -223,6 +222,114 @@ class InteractiveMessageHandler {
|
|
|
223
222
|
}
|
|
224
223
|
return { interactiveMessage }
|
|
225
224
|
}
|
|
225
|
+
async handleInteractiveButtons(content, _jid, _quoted) {
|
|
226
|
+
const {
|
|
227
|
+
text,
|
|
228
|
+
caption,
|
|
229
|
+
title,
|
|
230
|
+
subtitle,
|
|
231
|
+
footer,
|
|
232
|
+
interactiveButtons,
|
|
233
|
+
hasMediaAttachment,
|
|
234
|
+
image,
|
|
235
|
+
video,
|
|
236
|
+
document,
|
|
237
|
+
mimetype,
|
|
238
|
+
jpegThumbnail,
|
|
239
|
+
location,
|
|
240
|
+
product,
|
|
241
|
+
businessOwnerJid
|
|
242
|
+
} = content
|
|
243
|
+
const bodyText = text || caption || ''
|
|
244
|
+
const buttons = interactiveButtons.map(btn => ({
|
|
245
|
+
name: btn.name,
|
|
246
|
+
buttonParamsJson:
|
|
247
|
+
typeof btn.buttonParamsJson === 'string' ? btn.buttonParamsJson : JSON.stringify(btn.buttonParamsJson)
|
|
248
|
+
}))
|
|
249
|
+
let headerContent = {}
|
|
250
|
+
let mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : false
|
|
251
|
+
if (image) {
|
|
252
|
+
const src = typeof image === 'object' && image.url ? { image: { url: image.url } } : { image }
|
|
253
|
+
const uploaded = await prepareWAMessageMedia(src, { upload: this.waUploadToServer })
|
|
254
|
+
headerContent = { ...uploaded }
|
|
255
|
+
mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
|
|
256
|
+
} else if (video) {
|
|
257
|
+
const src = typeof video === 'object' && video.url ? { video: { url: video.url } } : { video }
|
|
258
|
+
const uploaded = await prepareWAMessageMedia(src, { upload: this.waUploadToServer })
|
|
259
|
+
headerContent = { ...uploaded }
|
|
260
|
+
mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
|
|
261
|
+
} else if (document) {
|
|
262
|
+
const docPayload =
|
|
263
|
+
typeof document === 'object' && document.url ? { document: { url: document.url } } : { document }
|
|
264
|
+
if (mimetype) docPayload.mimetype = mimetype
|
|
265
|
+
const uploaded = await prepareWAMessageMedia(docPayload, { upload: this.waUploadToServer })
|
|
266
|
+
if (jpegThumbnail) {
|
|
267
|
+
uploaded.documentMessage.jpegThumbnail =
|
|
268
|
+
typeof jpegThumbnail === 'string' ? Buffer.from(jpegThumbnail, 'base64') : jpegThumbnail
|
|
269
|
+
}
|
|
270
|
+
headerContent = { ...uploaded }
|
|
271
|
+
mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
|
|
272
|
+
} else if (location) {
|
|
273
|
+
headerContent = {
|
|
274
|
+
locationMessage: {
|
|
275
|
+
degreesLatitude: location.degressLatitude || location.degreesLatitude || 0,
|
|
276
|
+
degreesLongitude: location.degressLongitude || location.degreesLongitude || 0,
|
|
277
|
+
name: location.name || ''
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
|
|
281
|
+
} else if (product) {
|
|
282
|
+
let productImage
|
|
283
|
+
if (product.productImage) {
|
|
284
|
+
const imgSrc =
|
|
285
|
+
typeof product.productImage === 'object' && product.productImage.url
|
|
286
|
+
? { image: { url: product.productImage.url } }
|
|
287
|
+
: { image: product.productImage }
|
|
288
|
+
const uploaded = await prepareWAMessageMedia(imgSrc, { upload: this.waUploadToServer })
|
|
289
|
+
productImage = uploaded.imageMessage
|
|
290
|
+
}
|
|
291
|
+
headerContent = {
|
|
292
|
+
productMessage: {
|
|
293
|
+
product: {
|
|
294
|
+
productImage,
|
|
295
|
+
productId: product.productId,
|
|
296
|
+
title: product.title,
|
|
297
|
+
description: product.description,
|
|
298
|
+
currencyCode: product.currencyCode || 'IDR',
|
|
299
|
+
priceAmount1000: product.priceAmount1000,
|
|
300
|
+
retailerId: product.retailerId,
|
|
301
|
+
url: product.url,
|
|
302
|
+
productImageCount: product.productImageCount || 1
|
|
303
|
+
},
|
|
304
|
+
businessOwnerJid: businessOwnerJid || '0@s.whatsapp.net'
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
mediaAttached = typeof hasMediaAttachment === 'boolean' ? hasMediaAttachment : true
|
|
308
|
+
}
|
|
309
|
+
const interactiveMessage = {
|
|
310
|
+
body: { text: bodyText },
|
|
311
|
+
footer: { text: footer || '' },
|
|
312
|
+
header: {
|
|
313
|
+
title: title || '',
|
|
314
|
+
subtitle: subtitle || '',
|
|
315
|
+
hasMediaAttachment: mediaAttached,
|
|
316
|
+
...headerContent
|
|
317
|
+
},
|
|
318
|
+
nativeFlowMessage: { buttons }
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
viewOnceMessage: {
|
|
322
|
+
message: {
|
|
323
|
+
messageContextInfo: {
|
|
324
|
+
deviceListMetadata: {},
|
|
325
|
+
deviceListMetadataVersion: 2,
|
|
326
|
+
messageSecret: crypto.randomBytes(32)
|
|
327
|
+
},
|
|
328
|
+
interactiveMessage
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
226
333
|
async handleAlbum(content, jid, quoted) {
|
|
227
334
|
const array = content.albumMessage || content.album
|
|
228
335
|
const ctxInfo = content.contextInfo || {}
|
|
@@ -237,7 +344,7 @@ class InteractiveMessageHandler {
|
|
|
237
344
|
expectedVideoCount: array.filter(a => 'video' in a).length
|
|
238
345
|
}
|
|
239
346
|
},
|
|
240
|
-
{ userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '')
|
|
347
|
+
{ userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '') }
|
|
241
348
|
)
|
|
242
349
|
await this.relayMessage(jid, album.message, {
|
|
243
350
|
messageId: album.key.id
|
|
@@ -287,18 +394,18 @@ class InteractiveMessageHandler {
|
|
|
287
394
|
joinLink: eventData.joinLink || '',
|
|
288
395
|
startTime:
|
|
289
396
|
typeof eventData.startTime === 'string'
|
|
290
|
-
? parseInt(eventData.startTime)
|
|
397
|
+
? parseInt(eventData.startTime, 10)
|
|
291
398
|
: eventData.startTime || Date.now(),
|
|
292
399
|
endTime:
|
|
293
400
|
typeof eventData.endTime === 'string'
|
|
294
|
-
? parseInt(eventData.endTime)
|
|
401
|
+
? parseInt(eventData.endTime, 10)
|
|
295
402
|
: eventData.endTime || Date.now() + 3600000,
|
|
296
403
|
extraGuestsAllowed: eventData.extraGuestsAllowed !== false
|
|
297
404
|
}
|
|
298
405
|
}
|
|
299
406
|
}
|
|
300
407
|
},
|
|
301
|
-
{ quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '')
|
|
408
|
+
{ quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '') }
|
|
302
409
|
)
|
|
303
410
|
await this.relayMessage(jid, msg.message, {
|
|
304
411
|
messageId: msg.key.id
|
|
@@ -319,7 +426,7 @@ class InteractiveMessageHandler {
|
|
|
319
426
|
}))
|
|
320
427
|
}
|
|
321
428
|
},
|
|
322
|
-
{ quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '')
|
|
429
|
+
{ quoted, userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '') }
|
|
323
430
|
)
|
|
324
431
|
await this.relayMessage(jid, msg.message, {
|
|
325
432
|
messageId: msg.key.id
|
|
@@ -347,55 +454,6 @@ class InteractiveMessageHandler {
|
|
|
347
454
|
messageId: generateMessageID()
|
|
348
455
|
})
|
|
349
456
|
}
|
|
350
|
-
async handleOrderMessage(content, jid, quoted) {
|
|
351
|
-
const orderData = content.orderMessage
|
|
352
|
-
const orderMsg = await generateWAMessageFromContent(jid, {
|
|
353
|
-
orderMessage: {
|
|
354
|
-
orderId: orderData.orderId || 'ORDER' + generateMessageID(),
|
|
355
|
-
thumbnail: orderData.thumbnail || null,
|
|
356
|
-
itemCount: orderData.itemCount || 0,
|
|
357
|
-
status: orderData.status || 'ACCEPTED',
|
|
358
|
-
surface: orderData.surface || 'CATALOG',
|
|
359
|
-
message: orderData.message,
|
|
360
|
-
orderTitle: orderData.orderTitle,
|
|
361
|
-
sellerJid: orderData.sellerJid || jid,
|
|
362
|
-
token: orderData.token || generateMessageID(),
|
|
363
|
-
totalAmount1000: orderData.totalAmount1000 || 0,
|
|
364
|
-
totalCurrencyCode: orderData.totalCurrencyCode || 'IDR',
|
|
365
|
-
messageVersion: 2
|
|
366
|
-
}
|
|
367
|
-
}, { quoted, browser: this.config?.browser })
|
|
368
|
-
await this.relayMessage(jid, orderMsg.message, {
|
|
369
|
-
messageId: orderMsg.key.id
|
|
370
|
-
})
|
|
371
|
-
return orderMsg
|
|
372
|
-
}
|
|
373
|
-
async handleGbLabel(content, jid) {
|
|
374
|
-
const labelData = content.groupLabel
|
|
375
|
-
if (!isJidGroup(jid)) {
|
|
376
|
-
throw new Error('handleGbLabel requires a group jid')
|
|
377
|
-
}
|
|
378
|
-
const msg = await generateWAMessageFromContent(jid, {
|
|
379
|
-
protocolMessage: {
|
|
380
|
-
type: 'GROUP_MEMBER_LABEL_CHANGE',
|
|
381
|
-
memberLabel: {
|
|
382
|
-
label: labelData.labelText.slice(0, 30)
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}, { browser: this.config?.browser })
|
|
386
|
-
return await this.relayMessage(jid, msg.message, {
|
|
387
|
-
additionalNodes: [
|
|
388
|
-
{
|
|
389
|
-
tag: 'meta',
|
|
390
|
-
attrs: {
|
|
391
|
-
tag_reason: 'user_update',
|
|
392
|
-
appdata: 'member_tag'
|
|
393
|
-
},
|
|
394
|
-
content: undefined
|
|
395
|
-
}
|
|
396
|
-
]
|
|
397
|
-
})
|
|
398
|
-
}
|
|
399
457
|
async sendStatusWhatsApp(content, jids = []) {
|
|
400
458
|
const userJid = jidNormalizedUser(this.sock.authState.creds.me.id)
|
|
401
459
|
const allUsers = new Set()
|
|
@@ -499,8 +557,7 @@ class InteractiveMessageHandler {
|
|
|
499
557
|
}
|
|
500
558
|
}
|
|
501
559
|
const statusMsg = await generateWAMessageFromContent(normalizedId, protocolMessage, {
|
|
502
|
-
userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '')
|
|
503
|
-
browser: this.config?.browser
|
|
560
|
+
userJid: jidNormalizedUser(this.sock.authState?.creds?.me?.id || '')
|
|
504
561
|
})
|
|
505
562
|
await this.relayMessage(normalizedId, statusMsg.message, {
|
|
506
563
|
additionalNodes: [
|
|
@@ -519,4 +576,4 @@ class InteractiveMessageHandler {
|
|
|
519
576
|
}
|
|
520
577
|
}
|
|
521
578
|
|
|
522
|
-
module.exports = {
|
|
579
|
+
module.exports = { badzz88 }
|
package/lib/Socket/interop.js
CHANGED
|
@@ -5,47 +5,36 @@ exports.makeInteropSocket = void 0
|
|
|
5
5
|
const { getBinaryNodeChild, getBinaryNodeChildren, S_WHATSAPP_NET } = require('../WABinary')
|
|
6
6
|
const { executeWMexQuery } = require('./mex')
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
const INTEROP_MEX_QUERY_IDS = {
|
|
9
|
-
CREATE_GROUP: '
|
|
10
|
-
LEAVE_GROUP: '
|
|
11
|
-
ADD_PARTICIPANTS: '
|
|
12
|
-
QUERY_GROUP_INFO: '
|
|
13
|
-
PRIVACY_SETTINGS_QUERY: '
|
|
14
|
-
PRIVACY_SETTINGS_UPDATE: '
|
|
15
|
-
PRIVACY_SETTINGS_WITH_CONTACT_LIST: '
|
|
10
|
+
CREATE_GROUP: '25726817620301611',
|
|
11
|
+
LEAVE_GROUP: '25346167795013271',
|
|
12
|
+
ADD_PARTICIPANTS: '25732168276369451',
|
|
13
|
+
QUERY_GROUP_INFO: '32734144032867938',
|
|
14
|
+
PRIVACY_SETTINGS_QUERY: '24849123668112654',
|
|
15
|
+
PRIVACY_SETTINGS_UPDATE: '25421856497452763',
|
|
16
|
+
PRIVACY_SETTINGS_WITH_CONTACT_LIST: '24913399124998598'
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
* Known integrator IDs (assigned by WhatsApp).
|
|
20
|
-
* BirdyChat → identifier_type="email"
|
|
21
|
-
* Haiket → identifier_type="pn"
|
|
22
|
-
*/
|
|
19
|
+
|
|
23
20
|
const INTEGRATOR_BIRDYCHAT = 12
|
|
24
21
|
const INTEGRATOR_HAIKET = 13
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
* TOS trackable results sent by WA on first interop opt-in.
|
|
28
|
-
* 105 = TOS shown, 160 = TOS accepted.
|
|
29
|
-
*/
|
|
23
|
+
|
|
30
24
|
const TOS_TRACKABLE_ID = '20240306'
|
|
31
25
|
const TOS_RESULT_SHOWN = '105'
|
|
32
26
|
const TOS_RESULT_ACCEPTED = '160'
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
|
|
35
29
|
const INTEROP_BATCH_MAX = 256
|
|
36
30
|
|
|
37
31
|
const makeInteropSocket = sock => {
|
|
38
|
-
const { query, generateMessageTag, logger, signalRepository } = sock
|
|
32
|
+
const { query, generateMessageTag, logger, signalRepository, masqueradeAsPrimary } = sock
|
|
39
33
|
|
|
40
34
|
const mexQuery = (variables, queryId, dataPath) =>
|
|
41
35
|
executeWMexQuery(variables, queryId, dataPath, query, generateMessageTag)
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
* Fetch all available interop integrators from the server.
|
|
45
|
-
* Each integrator carries: id, name, status, icon, identifierType,
|
|
46
|
-
* optedIn, features.groupMessaging.
|
|
47
|
-
* status can be "active" | "onboarding" | "removed".
|
|
48
|
-
*/
|
|
37
|
+
|
|
49
38
|
const fetchIntegrators = async () => {
|
|
50
39
|
const result = await query({
|
|
51
40
|
tag: 'iq',
|
|
@@ -62,14 +51,14 @@ const makeInteropSocket = sock => {
|
|
|
62
51
|
return getBinaryNodeChildren(listNode, 'integrator').map(node => {
|
|
63
52
|
const featuresNode = getBinaryNodeChild(node, 'features')
|
|
64
53
|
return {
|
|
65
|
-
id: parseInt(node.attrs.id),
|
|
54
|
+
id: parseInt(node.attrs.id, 10),
|
|
66
55
|
name: node.attrs.name,
|
|
67
|
-
|
|
56
|
+
|
|
68
57
|
status: node.attrs.status,
|
|
69
58
|
icon: node.attrs.icon,
|
|
70
|
-
|
|
59
|
+
|
|
71
60
|
identifierType: node.attrs.identifier_type,
|
|
72
|
-
|
|
61
|
+
|
|
73
62
|
optedIn: node.attrs.opted_in === 'true' || globalOptedIn,
|
|
74
63
|
features: {
|
|
75
64
|
groupMessaging: featuresNode?.attrs?.group_messaging === 'true'
|
|
@@ -78,7 +67,7 @@ const makeInteropSocket = sock => {
|
|
|
78
67
|
})
|
|
79
68
|
}
|
|
80
69
|
|
|
81
|
-
|
|
70
|
+
|
|
82
71
|
const sendTOSTrackable = async (id, result) => {
|
|
83
72
|
await query({
|
|
84
73
|
tag: 'iq',
|
|
@@ -87,20 +76,13 @@ const makeInteropSocket = sock => {
|
|
|
87
76
|
})
|
|
88
77
|
}
|
|
89
78
|
|
|
90
|
-
|
|
91
|
-
* Accept TOS for interop.
|
|
92
|
-
* Sends two trackable items: shown (105) then accepted (160).
|
|
93
|
-
* Must be called before opting in.
|
|
94
|
-
*/
|
|
79
|
+
|
|
95
80
|
const acceptInteropTOS = async () => {
|
|
96
81
|
await sendTOSTrackable(TOS_TRACKABLE_ID, TOS_RESULT_SHOWN)
|
|
97
82
|
await sendTOSTrackable(TOS_TRACKABLE_ID, TOS_RESULT_ACCEPTED)
|
|
98
83
|
}
|
|
99
84
|
|
|
100
|
-
|
|
101
|
-
* Opt in to a list of integrators (by numeric ID).
|
|
102
|
-
* Defaults to both known integrators (BirdyChat + Haiket).
|
|
103
|
-
*/
|
|
85
|
+
|
|
104
86
|
const optInIntegrators = async (integratorIds = [INTEGRATOR_BIRDYCHAT, INTEGRATOR_HAIKET]) => {
|
|
105
87
|
await query({
|
|
106
88
|
tag: 'iq',
|
|
@@ -124,10 +106,7 @@ const makeInteropSocket = sock => {
|
|
|
124
106
|
})
|
|
125
107
|
}
|
|
126
108
|
|
|
127
|
-
|
|
128
|
-
* Opt out of a list of integrators (by numeric ID).
|
|
129
|
-
* Mirror of optInIntegrators — uses <opt_out_integrators>.
|
|
130
|
-
*/
|
|
109
|
+
|
|
131
110
|
const optOutIntegrators = async (integratorIds = [INTEGRATOR_BIRDYCHAT, INTEGRATOR_HAIKET]) => {
|
|
132
111
|
await query({
|
|
133
112
|
tag: 'iq',
|
|
@@ -151,18 +130,7 @@ const makeInteropSocket = sock => {
|
|
|
151
130
|
})
|
|
152
131
|
}
|
|
153
132
|
|
|
154
|
-
|
|
155
|
-
* Resolve one or more interop users by external ID in a single IQ.
|
|
156
|
-
* Each entry: { externalId, integratorId }
|
|
157
|
-
* - BirdyChat (12): externalId = email address
|
|
158
|
-
* - Haiket (13): externalId = phone number string (e.g. "19146088152")
|
|
159
|
-
*
|
|
160
|
-
* Max 256 entries per call (server limit).
|
|
161
|
-
*
|
|
162
|
-
* Returns an array of results:
|
|
163
|
-
* { jid, externalId, normalizedExternalId, integratorId } on success
|
|
164
|
-
* { externalId, integratorId, error: { code, text } } on failure
|
|
165
|
-
*/
|
|
133
|
+
|
|
166
134
|
const resolveInteropUsers = async users => {
|
|
167
135
|
if (!users || users.length === 0) return []
|
|
168
136
|
if (users.length > INTEROP_BATCH_MAX) {
|
|
@@ -192,9 +160,9 @@ const makeInteropSocket = sock => {
|
|
|
192
160
|
if (errorNode) {
|
|
193
161
|
return {
|
|
194
162
|
externalId: userNode.attrs.external_id,
|
|
195
|
-
integratorId: parseInt(userNode.attrs.integrator_id),
|
|
163
|
+
integratorId: parseInt(userNode.attrs.integrator_id, 10),
|
|
196
164
|
error: {
|
|
197
|
-
code: parseInt(errorNode.attrs.code),
|
|
165
|
+
code: parseInt(errorNode.attrs.code, 10),
|
|
198
166
|
text: errorNode.attrs.text
|
|
199
167
|
}
|
|
200
168
|
}
|
|
@@ -203,25 +171,18 @@ const makeInteropSocket = sock => {
|
|
|
203
171
|
jid: userNode.attrs.jid,
|
|
204
172
|
externalId: userNode.attrs.external_id,
|
|
205
173
|
normalizedExternalId: userNode.attrs.normalized_external_id,
|
|
206
|
-
integratorId: parseInt(userNode.attrs.integrator_id)
|
|
174
|
+
integratorId: parseInt(userNode.attrs.integrator_id, 10)
|
|
207
175
|
}
|
|
208
176
|
})
|
|
209
177
|
}
|
|
210
178
|
|
|
211
|
-
|
|
212
|
-
* Convenience wrapper: resolve a single interop user.
|
|
213
|
-
* Returns the result object or null.
|
|
214
|
-
*/
|
|
179
|
+
|
|
215
180
|
const resolveInteropUser = async (externalId, integratorId) => {
|
|
216
181
|
const results = await resolveInteropUsers([{ externalId, integratorId }])
|
|
217
182
|
return results[0] ?? null
|
|
218
183
|
}
|
|
219
184
|
|
|
220
|
-
|
|
221
|
-
* Get reachability settings for interop contacts.
|
|
222
|
-
* Returns the raw <reachability_settings> node content.
|
|
223
|
-
* WA uses this as the interop presence/subscription mechanism.
|
|
224
|
-
*/
|
|
185
|
+
|
|
225
186
|
const getReachabilitySettings = async () => {
|
|
226
187
|
const result = await query({
|
|
227
188
|
tag: 'iq',
|
|
@@ -234,17 +195,13 @@ const makeInteropSocket = sock => {
|
|
|
234
195
|
enabled: settingsNode.attrs?.enabled,
|
|
235
196
|
users: getBinaryNodeChildren(settingsNode, 'user').map(n => ({
|
|
236
197
|
externalId: n.attrs.external_id,
|
|
237
|
-
integratorId: parseInt(n.attrs.integrator_id),
|
|
198
|
+
integratorId: parseInt(n.attrs.integrator_id, 10),
|
|
238
199
|
jid: n.attrs.jid
|
|
239
200
|
}))
|
|
240
201
|
}
|
|
241
202
|
}
|
|
242
203
|
|
|
243
|
-
|
|
244
|
-
* Set reachability settings (subscribe to presence) for interop contacts.
|
|
245
|
-
* users: array of { externalId, integratorId }
|
|
246
|
-
* enabled: "true" | "false"
|
|
247
|
-
*/
|
|
204
|
+
|
|
248
205
|
const setReachabilitySettings = async (users, enabled = 'true') => {
|
|
249
206
|
await query({
|
|
250
207
|
tag: 'iq',
|
|
@@ -265,10 +222,7 @@ const makeInteropSocket = sock => {
|
|
|
265
222
|
})
|
|
266
223
|
}
|
|
267
224
|
|
|
268
|
-
|
|
269
|
-
* Block or unblock an interop user via the w:interop blocklist.
|
|
270
|
-
* Different from regular WA block (xmlns=blocklist).
|
|
271
|
-
*/
|
|
225
|
+
|
|
272
226
|
const updateInteropBlockStatus = async (jid, action) => {
|
|
273
227
|
await query({
|
|
274
228
|
tag: 'iq',
|
|
@@ -286,10 +240,7 @@ const makeInteropSocket = sock => {
|
|
|
286
240
|
const blockInteropUser = jid => updateInteropBlockStatus(jid, 'block')
|
|
287
241
|
const unblockInteropUser = jid => updateInteropBlockStatus(jid, 'unblock')
|
|
288
242
|
|
|
289
|
-
|
|
290
|
-
* Report an interop contact as spam.
|
|
291
|
-
* spam_flow="account_info_block" = block + report (WA Web default).
|
|
292
|
-
*/
|
|
243
|
+
|
|
293
244
|
const reportInteropSpam = async (jid, spamFlow = 'account_info_block') => {
|
|
294
245
|
await query({
|
|
295
246
|
tag: 'iq',
|
|
@@ -298,10 +249,7 @@ const makeInteropSocket = sock => {
|
|
|
298
249
|
})
|
|
299
250
|
}
|
|
300
251
|
|
|
301
|
-
|
|
302
|
-
* Mark an interop JID as trusted_contact in privacy tokens.
|
|
303
|
-
* WA calls this automatically after the first outgoing message.
|
|
304
|
-
*/
|
|
252
|
+
|
|
305
253
|
const trustInteropContact = async jid => {
|
|
306
254
|
const t = Math.floor(Date.now() / 1000).toString()
|
|
307
255
|
await query({
|
|
@@ -317,15 +265,7 @@ const makeInteropSocket = sock => {
|
|
|
317
265
|
})
|
|
318
266
|
}
|
|
319
267
|
|
|
320
|
-
|
|
321
|
-
* Full interop initialization sequence matching WA Web:
|
|
322
|
-
* 1. Fetch available integrators
|
|
323
|
-
* 2. Accept TOS (shown 105 + accepted 160)
|
|
324
|
-
* 3. Opt-in to all active/onboarding integrators
|
|
325
|
-
*
|
|
326
|
-
* Silently tolerates TOS/opt-in errors.
|
|
327
|
-
* Returns the full integrator list.
|
|
328
|
-
*/
|
|
268
|
+
|
|
329
269
|
const initInterop = async () => {
|
|
330
270
|
let integrators
|
|
331
271
|
try {
|
|
@@ -346,30 +286,23 @@ const makeInteropSocket = sock => {
|
|
|
346
286
|
} catch (err) {
|
|
347
287
|
logger.warn({ err }, 'interop: failed to opt-in integrators')
|
|
348
288
|
}
|
|
349
|
-
logger.info({ integrators: toOptIn.map(i => i.name) }, 'interop:
|
|
289
|
+
logger.info({ integrators: toOptIn.map(i => i.name) }, 'interop: opted in')
|
|
290
|
+
logger.warn(
|
|
291
|
+
{ integrators: toOptIn.map(i => i.name) },
|
|
292
|
+
'interop: receiving messages from interop contacts (BirdyChat/Haiket) is NOT YET SUPPORTED. ' +
|
|
293
|
+
'The interop bridge only delivers to device 0 (primary phone) via a single Signal session — ' +
|
|
294
|
+
'no fan-out to companion devices. Opt-in and sending may work, but inbound messages will not arrive.'
|
|
295
|
+
)
|
|
350
296
|
return integrators
|
|
351
297
|
}
|
|
352
298
|
|
|
353
|
-
|
|
354
|
-
* Reset the Signal session with an interop contact and force a fresh pkmsg handshake.
|
|
355
|
-
* Call this when incoming messages from an interop contact are not arriving or
|
|
356
|
-
* failing to decrypt — it clears the stale session so the next sendMessage
|
|
357
|
-
* generates a new pre-key message and re-establishes both directions.
|
|
358
|
-
*/
|
|
299
|
+
|
|
359
300
|
const resetInteropSession = async jid => {
|
|
360
301
|
await signalRepository.deleteSession([jid])
|
|
361
302
|
logger.info({ jid }, '[interop] session reset — next send will use pkmsg')
|
|
362
303
|
}
|
|
363
304
|
|
|
364
|
-
|
|
365
|
-
* Create an interop group via MEX.
|
|
366
|
-
* Confirmed from C80913Xf.java opcode 15:
|
|
367
|
-
* input: { participants: [{ jid }] }
|
|
368
|
-
* dataPath: xwa2_interop_group_create
|
|
369
|
-
*
|
|
370
|
-
* @param {string[]} participants - Interop JIDs to add
|
|
371
|
-
* @returns {{ gid, creationTime, creator, participants }}
|
|
372
|
-
*/
|
|
305
|
+
|
|
373
306
|
const createInteropGroup = async participants => {
|
|
374
307
|
const result = await mexQuery(
|
|
375
308
|
{ input: { participants: participants.map(jid => ({ jid })) } },
|
|
@@ -380,15 +313,7 @@ const makeInteropSocket = sock => {
|
|
|
380
313
|
return result
|
|
381
314
|
}
|
|
382
315
|
|
|
383
|
-
|
|
384
|
-
* Leave one or more interop groups via MEX.
|
|
385
|
-
* Confirmed from C80913Xf.java opcode 28:
|
|
386
|
-
* input: { groups_to_leave: [{ gid }] }
|
|
387
|
-
* dataPath: xwa2_interop_group_leave
|
|
388
|
-
*
|
|
389
|
-
* gid is the raw interop group ID (without @g.us suffix).
|
|
390
|
-
* @param {string|string[]} jids - Interop group JID(s)
|
|
391
|
-
*/
|
|
316
|
+
|
|
392
317
|
const leaveInteropGroup = async jids => {
|
|
393
318
|
const ids = Array.isArray(jids) ? jids : [jids]
|
|
394
319
|
const result = await mexQuery(
|
|
@@ -400,15 +325,7 @@ const makeInteropSocket = sock => {
|
|
|
400
325
|
return result
|
|
401
326
|
}
|
|
402
327
|
|
|
403
|
-
|
|
404
|
-
* Add participants to an existing interop group via MEX.
|
|
405
|
-
* Confirmed from C3Wt.java opcode 9:
|
|
406
|
-
* input: { gid, participants: [{ jid }] }
|
|
407
|
-
* dataPath: xwa2_interop_add_participants_to_group
|
|
408
|
-
*
|
|
409
|
-
* @param {string} groupJid - Interop group JID
|
|
410
|
-
* @param {string[]} participants - Interop JIDs to add
|
|
411
|
-
*/
|
|
328
|
+
|
|
412
329
|
const addParticipantsToInteropGroup = async (groupJid, participants) => {
|
|
413
330
|
const gid = groupJid.split('@')[0]
|
|
414
331
|
return mexQuery(
|
|
@@ -418,35 +335,13 @@ const makeInteropSocket = sock => {
|
|
|
418
335
|
)
|
|
419
336
|
}
|
|
420
337
|
|
|
421
|
-
|
|
422
|
-
* Query info about an interop group via MEX.
|
|
423
|
-
* Confirmed from C3Wt.java opcode 10:
|
|
424
|
-
* group_input: { gid }
|
|
425
|
-
* dataPath: xwa2_interop_group_query_by_id
|
|
426
|
-
*
|
|
427
|
-
* @param {string} groupJid - Interop group JID
|
|
428
|
-
*/
|
|
338
|
+
|
|
429
339
|
const queryInteropGroupInfo = async groupJid => {
|
|
430
340
|
const gid = groupJid.split('@')[0]
|
|
431
|
-
return mexQuery(
|
|
432
|
-
{ group_input: { gid } },
|
|
433
|
-
INTEROP_MEX_QUERY_IDS.QUERY_GROUP_INFO,
|
|
434
|
-
'xwa2_interop_group_query_by_id'
|
|
435
|
-
)
|
|
341
|
+
return mexQuery({ group_input: { gid } }, INTEROP_MEX_QUERY_IDS.QUERY_GROUP_INFO, 'xwa2_interop_group_query_by_id')
|
|
436
342
|
}
|
|
437
343
|
|
|
438
|
-
|
|
439
|
-
* Update an interop privacy setting via MEX.
|
|
440
|
-
* Confirmed from C24385Ak0.java (InteropPrivacySettingsUpdate):
|
|
441
|
-
* feature, setting
|
|
442
|
-
* dataPath: xwa2_interop_privacy_setting_update
|
|
443
|
-
*
|
|
444
|
-
* Known features: "GROUPADD"
|
|
445
|
-
* Known settings: "ALL" | "CONTACTS" | "NONE"
|
|
446
|
-
*
|
|
447
|
-
* @param {string} feature - Privacy feature name
|
|
448
|
-
* @param {string} setting - New value
|
|
449
|
-
*/
|
|
344
|
+
|
|
450
345
|
const updateInteropPrivacySetting = async (feature, setting) => {
|
|
451
346
|
return mexQuery(
|
|
452
347
|
{ feature, setting },
|
|
@@ -455,20 +350,7 @@ const makeInteropSocket = sock => {
|
|
|
455
350
|
)
|
|
456
351
|
}
|
|
457
352
|
|
|
458
|
-
|
|
459
|
-
* Update an interop privacy setting with an explicit contact list via MEX.
|
|
460
|
-
* Confirmed from C24388Ak8.java (InteropPrivacySettingWithContactListUpdate):
|
|
461
|
-
* feature, setting, contacts[], contact_list_type, dhash
|
|
462
|
-
* dataPath: xwa2_interop_privacy_setting_with_contact_list_update
|
|
463
|
-
*
|
|
464
|
-
* Used when setting is "CONTACTS" and you want to specify exact allowed contacts.
|
|
465
|
-
*
|
|
466
|
-
* @param {string} feature - Privacy feature (e.g. "GROUPADD")
|
|
467
|
-
* @param {string} setting - "CONTACTS"
|
|
468
|
-
* @param {string[]} contacts - List of JIDs to allow
|
|
469
|
-
* @param {string} contactListType - Contact list type string
|
|
470
|
-
* @param {string} [dhash] - Hash of the current contact list (or null/"none")
|
|
471
|
-
*/
|
|
353
|
+
|
|
472
354
|
const updateInteropPrivacySettingWithContactList = async (
|
|
473
355
|
feature,
|
|
474
356
|
setting,
|
|
@@ -483,13 +365,11 @@ const makeInteropSocket = sock => {
|
|
|
483
365
|
)
|
|
484
366
|
}
|
|
485
367
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
* the "GROUPADD" feature for the given account.
|
|
492
|
-
*/
|
|
368
|
+
|
|
369
|
+
const queryInteropPrivacySettings = () =>
|
|
370
|
+
mexQuery({}, INTEROP_MEX_QUERY_IDS.PRIVACY_SETTINGS_QUERY, 'xwa2_interop_privacy_settings')
|
|
371
|
+
|
|
372
|
+
|
|
493
373
|
const getInteropGroupAddPrivacy = async (jid, integratorId) => {
|
|
494
374
|
const result = await query({
|
|
495
375
|
tag: 'iq',
|
|
@@ -512,8 +392,8 @@ const makeInteropSocket = sock => {
|
|
|
512
392
|
})
|
|
513
393
|
const privacyNode = getBinaryNodeChild(result, 'privacy')
|
|
514
394
|
const userNode = getBinaryNodeChild(privacyNode, 'user')
|
|
515
|
-
|
|
516
|
-
|
|
395
|
+
|
|
396
|
+
|
|
517
397
|
return userNode?.attrs?.result === 'allowed'
|
|
518
398
|
}
|
|
519
399
|
|
|
@@ -537,6 +417,7 @@ const makeInteropSocket = sock => {
|
|
|
537
417
|
leaveInteropGroup,
|
|
538
418
|
addParticipantsToInteropGroup,
|
|
539
419
|
queryInteropGroupInfo,
|
|
420
|
+
queryInteropPrivacySettings,
|
|
540
421
|
updateInteropPrivacySetting,
|
|
541
422
|
updateInteropPrivacySettingWithContactList,
|
|
542
423
|
getInteropGroupAddPrivacy,
|