@badzz88/baileys 8.5.7 → 8.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +337 -1055
- package/WAProto/WAProto.proto +284 -264
- package/WAProto/index.js +5 -5
- package/engine-requirements.js +7 -15
- package/lib/Defaults/index.js +130 -187
- package/lib/Signal/Group/ciphertext-message.js +11 -14
- package/lib/Signal/Group/group-session-builder.js +29 -91
- package/lib/Signal/Group/group_cipher.js +81 -88
- package/lib/Signal/Group/index.js +12 -136
- package/lib/Signal/Group/keyhelper.js +15 -70
- package/lib/Signal/Group/sender-chain-key.js +25 -31
- package/lib/Signal/Group/sender-key-distribution-message.js +62 -65
- package/lib/Signal/Group/sender-key-message.js +65 -68
- package/lib/Signal/Group/sender-key-name.js +41 -43
- package/lib/Signal/Group/sender-key-record.js +40 -43
- package/lib/Signal/Group/sender-key-state.js +83 -96
- package/lib/Signal/Group/sender-message-key.js +25 -29
- package/lib/Signal/libsignal.js +425 -453
- package/lib/Signal/lid-mapping.js +276 -259
- package/lib/Socket/Client/index.js +3 -30
- package/lib/Socket/Client/types.js +10 -12
- package/lib/Socket/Client/websocket.js +53 -61
- package/lib/Socket/business.js +379 -422
- package/lib/Socket/chats.js +1193 -1816
- package/lib/Socket/communities.js +431 -549
- package/lib/Socket/graphql.js +672 -612
- package/lib/Socket/groups.js +374 -764
- package/lib/Socket/index.js +17 -38
- package/lib/Socket/interop.js +417 -503
- package/lib/Socket/messages-recv.js +1915 -2441
- package/lib/Socket/messages-send.js +1213 -1630
- package/lib/Socket/mex.js +9 -15
- package/lib/Socket/newsletter.js +746 -808
- package/lib/Socket/privacy.js +310 -441
- package/lib/Socket/socket.js +1025 -1022
- package/lib/Socket/username.js +8 -15
- package/lib/Store/index.js +10 -36
- package/lib/Store/make-cache-manager-store.js +80 -85
- package/lib/Store/make-in-memory-store.js +231 -591
- package/lib/Store/make-ordered-dictionary.js +72 -78
- package/lib/Store/object-repository.js +28 -25
- package/lib/Types/Auth.js +2 -38
- package/lib/Types/Bussines.js +2 -2
- package/lib/Types/Call.js +2 -2
- package/lib/Types/Chat.js +8 -4
- package/lib/Types/Contact.js +2 -2
- package/lib/Types/Events.js +2 -2
- package/lib/Types/GroupMetadata.js +2 -2
- package/lib/Types/Label.js +24 -26
- package/lib/Types/LabelAssociation.js +6 -8
- package/lib/Types/Message.js +11 -95
- package/lib/Types/Mex.js +111 -112
- package/lib/Types/Product.js +2 -2
- package/lib/Types/Signal.js +2 -2
- package/lib/Types/Socket.js +3 -2
- package/lib/Types/State.js +56 -70
- package/lib/Types/USync.js +2 -2
- package/lib/Types/index.js +26 -55
- package/lib/Utils/auth-utils.js +288 -292
- package/lib/Utils/browser-utils.js +47 -113
- package/lib/Utils/business.js +224 -240
- package/lib/Utils/chat-utils.js +869 -1205
- package/lib/Utils/companion-reg-client-utils.js +34 -41
- package/lib/Utils/crypto.js +107 -144
- package/lib/Utils/decode-wa-message.js +308 -518
- package/lib/Utils/event-buffer.js +611 -596
- package/lib/Utils/generics.js +355 -515
- package/lib/Utils/history.js +134 -244
- package/lib/Utils/identity-change-handler.js +49 -51
- package/lib/Utils/index.js +23 -57
- package/lib/Utils/link-preview.js +77 -135
- package/lib/Utils/logger.js +3 -9
- package/lib/Utils/lt-hash.js +6 -37
- package/lib/Utils/make-mutex.js +33 -36
- package/lib/Utils/message-composer.js +233 -439
- package/lib/Utils/message-retry-manager.js +260 -265
- package/lib/Utils/messages-media.js +829 -855
- package/lib/Utils/messages.js +961 -2528
- package/lib/Utils/noise-handler.js +200 -195
- package/lib/Utils/offline-node-processor.js +33 -35
- package/lib/Utils/pre-key-manager.js +102 -103
- package/lib/Utils/process-message.js +560 -978
- package/lib/Utils/reporting-utils.js +253 -257
- package/lib/Utils/signal.js +195 -218
- package/lib/Utils/stanza-ack.js +29 -31
- package/lib/Utils/sticker.js +109 -144
- package/lib/Utils/sync-action-utils.js +45 -50
- package/lib/Utils/tc-token-utils.js +139 -137
- package/lib/Utils/use-multi-file-auth-state.js +109 -109
- package/lib/Utils/validate-connection.js +202 -218
- package/lib/WABinary/constants.js +1299 -1302
- package/lib/WABinary/decode.js +262 -343
- package/lib/WABinary/encode.js +4 -12
- package/lib/WABinary/generic-utils.js +187 -223
- package/lib/WABinary/index.js +6 -33
- package/lib/WABinary/jid-utils.js +88 -351
- package/lib/WABinary/types.js +2 -2
- package/lib/WAM/BinaryInfo.js +9 -12
- package/lib/WAM/constants.js +22853 -39486
- package/lib/WAM/encode.js +140 -132
- package/lib/WAM/index.js +4 -31
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +21 -23
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +9 -9
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -7
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +10 -10
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +7 -7
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +11 -12
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +4 -5
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +7 -7
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +7 -8
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -7
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +8 -8
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +7 -7
- package/lib/WAUSync/Protocols/index.js +12 -39
- package/lib/WAUSync/USyncQuery.js +67 -49
- package/lib/WAUSync/USyncUser.js +11 -5
- package/lib/WAUSync/index.js +3 -31
- package/lib/index.js +15 -48
- package/package.json +129 -99
- package/LICENSE +0 -21
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Socket/aigroups.js +0 -240
- package/lib/Socket/interactive-handler.js +0 -522
- package/lib/Socket/managed-account.js +0 -183
- package/lib/Socket/registration.js +0 -427
- package/lib/Socket/text-router.js +0 -83
- package/lib/Types/Newsletter.js +0 -121
- package/lib/Utils/command-loader.d.ts +0 -31
- package/lib/Utils/command-loader.js +0 -100
- package/lib/Utils/consumer-application.js +0 -107
- package/lib/Utils/curve25519-js.js +0 -275
- package/lib/Utils/group-history.js +0 -60
- package/lib/Utils/jid-display-normalization.js +0 -218
- package/lib/Utils/meta-ai-msmsg.js +0 -262
- 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/view-once-cache.d.ts +0 -9
- package/lib/Utils/view-once-cache.js +0 -79
- package/lib/Utils/voip-rekey.js +0 -22
- package/lib/antiban.js +0 -4637
package/lib/Socket/interop.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.makeInteropSocket = void 0
|
|
4
|
-
|
|
5
|
-
const { getBinaryNodeChild, getBinaryNodeChildren, S_WHATSAPP_NET } = require('../WABinary')
|
|
6
|
-
const { executeWMexQuery } = require('./mex')
|
|
1
|
+
import { getBinaryNodeChild, getBinaryNodeChildren, S_WHATSAPP_NET } from '../WABinary/index.js'
|
|
2
|
+
import { executeWMexQuery } from './mex.js'
|
|
7
3
|
|
|
4
|
+
/**
|
|
5
|
+
* w:mex query IDs for interop group and privacy operations.
|
|
6
|
+
*
|
|
7
|
+
* Source: whatsapp-android-mex_client_persist_ids.json (WA 2.26.26.4 APK assets)
|
|
8
|
+
*/
|
|
8
9
|
const INTEROP_MEX_QUERY_IDS = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
CREATE_GROUP: '25726817620301611', // GroupsCreateInteropGroup
|
|
11
|
+
LEAVE_GROUP: '25346167795013271', // LeaveInteropGroup
|
|
12
|
+
ADD_PARTICIPANTS: '25732168276369451', // AddParticipantsToInteropGroup
|
|
13
|
+
QUERY_GROUP_INFO: '32734144032867938', // QueryInteropGroupInfo
|
|
14
|
+
PRIVACY_SETTINGS_QUERY: '24849123668112654', // InteropPrivacySettingsQuery
|
|
15
|
+
PRIVACY_SETTINGS_UPDATE: '25421856497452763', // InteropPrivacySettingsUpdate
|
|
16
|
+
PRIVACY_SETTINGS_WITH_CONTACT_LIST: '24913399124998598' // InteropPrivacySettingWithContactListUpdate
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Known integrator IDs (assigned by WhatsApp).
|
|
20
21
|
* BirdyChat → identifier_type="email"
|
|
21
|
-
* Haiket
|
|
22
|
+
* Haiket → identifier_type="pn"
|
|
22
23
|
*/
|
|
23
24
|
const INTEGRATOR_BIRDYCHAT = 12
|
|
24
25
|
const INTEGRATOR_HAIKET = 13
|
|
@@ -34,516 +35,429 @@ const TOS_RESULT_ACCEPTED = '160'
|
|
|
34
35
|
/** Maximum users per batch lookup (enforced server-side too). */
|
|
35
36
|
const INTEROP_BATCH_MAX = 256
|
|
36
37
|
|
|
37
|
-
const makeInteropSocket = sock => {
|
|
38
|
-
|
|
38
|
+
export const makeInteropSocket = sock => {
|
|
39
|
+
const { query, generateMessageTag, logger, signalRepository } = sock
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
const mexQuery = (variables, queryId, dataPath) =>
|
|
42
|
+
executeWMexQuery(variables, queryId, dataPath, query, generateMessageTag)
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
}
|
|
44
|
+
/**
|
|
45
|
+
* Fetch all available interop integrators from the server.
|
|
46
|
+
*/
|
|
47
|
+
const fetchIntegrators = async () => {
|
|
48
|
+
const result = await query({
|
|
49
|
+
tag: 'iq',
|
|
50
|
+
attrs: {
|
|
51
|
+
type: 'get',
|
|
52
|
+
xmlns: 'w:interop',
|
|
53
|
+
to: S_WHATSAPP_NET
|
|
54
|
+
},
|
|
55
|
+
content: [{ tag: 'integrator', attrs: { fetch: 'all' } }]
|
|
56
|
+
})
|
|
57
|
+
const listNode = getBinaryNodeChild(result, 'integrator_list')
|
|
58
|
+
if (!listNode) return []
|
|
59
|
+
const globalOptedIn = listNode.attrs?.opted_in === 'true'
|
|
60
|
+
return getBinaryNodeChildren(listNode, 'integrator').map(node => {
|
|
61
|
+
const featuresNode = getBinaryNodeChild(node, 'features')
|
|
62
|
+
return {
|
|
63
|
+
id: parseInt(node.attrs.id, 10),
|
|
64
|
+
name: node.attrs.name,
|
|
65
|
+
// "active" | "onboarding" | "removed"
|
|
66
|
+
status: node.attrs.status,
|
|
67
|
+
icon: node.attrs.icon,
|
|
68
|
+
// "email" | "pn" | "username"
|
|
69
|
+
identifierType: node.attrs.identifier_type,
|
|
70
|
+
// Whether we are already opted-in to this integrator
|
|
71
|
+
optedIn: node.attrs.opted_in === 'true' || globalOptedIn,
|
|
72
|
+
features: {
|
|
73
|
+
groupMessaging: featuresNode?.attrs?.group_messaging === 'true'
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
/** Send a single TOS trackable item (shown or accepted). */
|
|
80
|
+
const sendTOSTrackable = async (id, result) => {
|
|
81
|
+
await query({
|
|
82
|
+
tag: 'iq',
|
|
83
|
+
attrs: { to: S_WHATSAPP_NET, type: 'set', xmlns: 'tos' },
|
|
84
|
+
content: [{ tag: 'trackable', attrs: { id, result } }]
|
|
85
|
+
})
|
|
86
|
+
}
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
88
|
+
/**
|
|
89
|
+
* Accept TOS for interop.
|
|
90
|
+
* Sends two trackable items: shown (105) then accepted (160).
|
|
91
|
+
*/
|
|
92
|
+
const acceptInteropTOS = async () => {
|
|
93
|
+
await sendTOSTrackable(TOS_TRACKABLE_ID, TOS_RESULT_SHOWN)
|
|
94
|
+
await sendTOSTrackable(TOS_TRACKABLE_ID, TOS_RESULT_ACCEPTED)
|
|
95
|
+
}
|
|
99
96
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
97
|
+
/**
|
|
98
|
+
* Opt in to a list of integrators (by numeric ID).
|
|
99
|
+
*/
|
|
100
|
+
const optInIntegrators = async (integratorIds = [INTEGRATOR_BIRDYCHAT, INTEGRATOR_HAIKET]) => {
|
|
101
|
+
await query({
|
|
102
|
+
tag: 'iq',
|
|
103
|
+
attrs: { type: 'set', xmlns: 'w:interop', to: S_WHATSAPP_NET },
|
|
104
|
+
content: [
|
|
105
|
+
{
|
|
106
|
+
tag: 'opt_integrators',
|
|
107
|
+
attrs: {},
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
tag: 'integrator_list',
|
|
111
|
+
attrs: {},
|
|
112
|
+
content: integratorIds.map(id => ({
|
|
113
|
+
tag: 'integrator',
|
|
114
|
+
attrs: { id: id.toString() }
|
|
115
|
+
}))
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
})
|
|
121
|
+
}
|
|
126
122
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
123
|
+
/**
|
|
124
|
+
* Opt out of a list of integrators (by numeric ID).
|
|
125
|
+
*/
|
|
126
|
+
const optOutIntegrators = async (integratorIds = [INTEGRATOR_BIRDYCHAT, INTEGRATOR_HAIKET]) => {
|
|
127
|
+
await query({
|
|
128
|
+
tag: 'iq',
|
|
129
|
+
attrs: { type: 'set', xmlns: 'w:interop', to: S_WHATSAPP_NET },
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
tag: 'opt_out_integrators',
|
|
133
|
+
attrs: {},
|
|
134
|
+
content: [
|
|
135
|
+
{
|
|
136
|
+
tag: 'integrator_list',
|
|
137
|
+
attrs: {},
|
|
138
|
+
content: integratorIds.map(id => ({
|
|
139
|
+
tag: 'integrator',
|
|
140
|
+
attrs: { id: id.toString() }
|
|
141
|
+
}))
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
})
|
|
147
|
+
}
|
|
153
148
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
jid: userNode.attrs.jid,
|
|
204
|
-
externalId: userNode.attrs.external_id,
|
|
205
|
-
normalizedExternalId: userNode.attrs.normalized_external_id,
|
|
206
|
-
integratorId: parseInt(userNode.attrs.integrator_id)
|
|
207
|
-
}
|
|
208
|
-
})
|
|
209
|
-
}
|
|
149
|
+
/**
|
|
150
|
+
* Resolve one or more interop users by external ID in a single IQ.
|
|
151
|
+
*/
|
|
152
|
+
const resolveInteropUsers = async users => {
|
|
153
|
+
if (!users || users.length === 0) return []
|
|
154
|
+
if (users.length > INTEROP_BATCH_MAX) {
|
|
155
|
+
throw new Error(`resolveInteropUsers: max ${INTEROP_BATCH_MAX} users per request`)
|
|
156
|
+
}
|
|
157
|
+
const result = await query({
|
|
158
|
+
tag: 'iq',
|
|
159
|
+
attrs: { type: 'get', xmlns: 'w:interop', to: S_WHATSAPP_NET },
|
|
160
|
+
content: [
|
|
161
|
+
{
|
|
162
|
+
tag: 'users',
|
|
163
|
+
attrs: {},
|
|
164
|
+
content: users.map(({ externalId, integratorId }) => ({
|
|
165
|
+
tag: 'user',
|
|
166
|
+
attrs: {
|
|
167
|
+
external_id: externalId,
|
|
168
|
+
integrator_id: integratorId.toString()
|
|
169
|
+
}
|
|
170
|
+
}))
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
})
|
|
174
|
+
const usersNode = getBinaryNodeChild(result, 'users')
|
|
175
|
+
if (!usersNode) return []
|
|
176
|
+
return getBinaryNodeChildren(usersNode, 'user').map(userNode => {
|
|
177
|
+
const errorNode = getBinaryNodeChild(userNode, 'error')
|
|
178
|
+
if (errorNode) {
|
|
179
|
+
return {
|
|
180
|
+
externalId: userNode.attrs.external_id,
|
|
181
|
+
integratorId: parseInt(userNode.attrs.integrator_id, 10),
|
|
182
|
+
error: {
|
|
183
|
+
code: parseInt(errorNode.attrs.code, 10),
|
|
184
|
+
text: errorNode.attrs.text
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
jid: userNode.attrs.jid,
|
|
190
|
+
externalId: userNode.attrs.external_id,
|
|
191
|
+
normalizedExternalId: userNode.attrs.normalized_external_id,
|
|
192
|
+
integratorId: parseInt(userNode.attrs.integrator_id, 10)
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
}
|
|
210
196
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
197
|
+
/**
|
|
198
|
+
* Convenience wrapper: resolve a single interop user.
|
|
199
|
+
*/
|
|
200
|
+
const resolveInteropUser = async (externalId, integratorId) => {
|
|
201
|
+
const results = await resolveInteropUsers([{ externalId, integratorId }])
|
|
202
|
+
return results[0]?? null
|
|
203
|
+
}
|
|
219
204
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
}
|
|
205
|
+
/**
|
|
206
|
+
* Get reachability settings for interop contacts.
|
|
207
|
+
*/
|
|
208
|
+
const getReachabilitySettings = async () => {
|
|
209
|
+
const result = await query({
|
|
210
|
+
tag: 'iq',
|
|
211
|
+
attrs: { type: 'get', xmlns: 'w:interop', to: S_WHATSAPP_NET },
|
|
212
|
+
content: [{ tag: 'reachability_settings', attrs: {} }]
|
|
213
|
+
})
|
|
214
|
+
const settingsNode = getBinaryNodeChild(result, 'reachability_settings')
|
|
215
|
+
if (!settingsNode) return null
|
|
216
|
+
return {
|
|
217
|
+
enabled: settingsNode.attrs?.enabled,
|
|
218
|
+
users: getBinaryNodeChildren(settingsNode, 'user').map(n => ({
|
|
219
|
+
externalId: n.attrs.external_id,
|
|
220
|
+
integratorId: parseInt(n.attrs.integrator_id, 10),
|
|
221
|
+
jid: n.attrs.jid
|
|
222
|
+
}))
|
|
223
|
+
}
|
|
224
|
+
}
|
|
242
225
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
})
|
|
266
|
-
}
|
|
226
|
+
/**
|
|
227
|
+
* Set reachability settings (subscribe to presence) for interop contacts.
|
|
228
|
+
*/
|
|
229
|
+
const setReachabilitySettings = async (users, enabled = 'true') => {
|
|
230
|
+
await query({
|
|
231
|
+
tag: 'iq',
|
|
232
|
+
attrs: { type: 'set', xmlns: 'w:interop', to: S_WHATSAPP_NET },
|
|
233
|
+
content: [
|
|
234
|
+
{
|
|
235
|
+
tag: 'reachability_settings',
|
|
236
|
+
attrs: { enabled },
|
|
237
|
+
content: users.map(({ externalId, integratorId }) => ({
|
|
238
|
+
tag: 'user',
|
|
239
|
+
attrs: {
|
|
240
|
+
external_id: externalId,
|
|
241
|
+
integrator_id: integratorId.toString()
|
|
242
|
+
}
|
|
243
|
+
}))
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
})
|
|
247
|
+
}
|
|
267
248
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
249
|
+
/**
|
|
250
|
+
* Block or unblock an interop user via the w:interop blocklist.
|
|
251
|
+
*/
|
|
252
|
+
const updateInteropBlockStatus = async (jid, action) => {
|
|
253
|
+
await query({
|
|
254
|
+
tag: 'iq',
|
|
255
|
+
attrs: { type: 'set', xmlns: 'w:interop', to: S_WHATSAPP_NET },
|
|
256
|
+
content: [
|
|
257
|
+
{
|
|
258
|
+
tag: 'blocklist',
|
|
259
|
+
attrs: {},
|
|
260
|
+
content: [{ tag: 'item', attrs: { action, jid } }]
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
})
|
|
264
|
+
}
|
|
285
265
|
|
|
286
|
-
|
|
287
|
-
|
|
266
|
+
const blockInteropUser = jid => updateInteropBlockStatus(jid, 'block')
|
|
267
|
+
const unblockInteropUser = jid => updateInteropBlockStatus(jid, 'unblock')
|
|
288
268
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
269
|
+
/**
|
|
270
|
+
* Report an interop contact as spam.
|
|
271
|
+
*/
|
|
272
|
+
const reportInteropSpam = async (jid, spamFlow = 'account_info_block') => {
|
|
273
|
+
await query({
|
|
274
|
+
tag: 'iq',
|
|
275
|
+
attrs: { type: 'set', xmlns: 'spam', to: S_WHATSAPP_NET },
|
|
276
|
+
content: [{ tag: 'spam_list', attrs: { jid, spam_flow: spamFlow } }]
|
|
277
|
+
})
|
|
278
|
+
}
|
|
300
279
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
280
|
+
/**
|
|
281
|
+
* Mark an interop JID as trusted_contact in privacy tokens.
|
|
282
|
+
*/
|
|
283
|
+
const trustInteropContact = async jid => {
|
|
284
|
+
const t = Math.floor(Date.now() / 1000).toString()
|
|
285
|
+
await query({
|
|
286
|
+
tag: 'iq',
|
|
287
|
+
attrs: { to: S_WHATSAPP_NET, xmlns: 'privacy', type: 'set' },
|
|
288
|
+
content: [
|
|
289
|
+
{
|
|
290
|
+
tag: 'tokens',
|
|
291
|
+
attrs: {},
|
|
292
|
+
content: [{ tag: 'token', attrs: { jid, type: 'trusted_contact', t } }]
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
})
|
|
296
|
+
}
|
|
319
297
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
} catch (err) {
|
|
347
|
-
logger.warn({ err }, 'interop: failed to opt-in integrators')
|
|
348
|
-
}
|
|
349
|
-
logger.info({ integrators: toOptIn.map(i => i.name) }, 'interop: initialized')
|
|
350
|
-
return integrators
|
|
351
|
-
}
|
|
298
|
+
/**
|
|
299
|
+
* Full interop initialization sequence matching WA Web.
|
|
300
|
+
*/
|
|
301
|
+
const initInterop = async () => {
|
|
302
|
+
let integrators
|
|
303
|
+
try {
|
|
304
|
+
integrators = await fetchIntegrators()
|
|
305
|
+
} catch (err) {
|
|
306
|
+
logger.warn({ err }, 'interop: failed to fetch integrators')
|
|
307
|
+
return []
|
|
308
|
+
}
|
|
309
|
+
const toOptIn = integrators.filter(i => i.status === 'active' || i.status === 'onboarding')
|
|
310
|
+
if (toOptIn.length === 0) return integrators
|
|
311
|
+
try {
|
|
312
|
+
await acceptInteropTOS()
|
|
313
|
+
} catch (err) {
|
|
314
|
+
logger.warn({ err }, 'interop: failed to accept TOS')
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
await optInIntegrators(toOptIn.map(i => i.id))
|
|
318
|
+
} catch (err) {
|
|
319
|
+
logger.warn({ err }, 'interop: failed to opt-in integrators')
|
|
320
|
+
}
|
|
321
|
+
logger.info({ integrators: toOptIn.map(i => i.name) }, 'interop: initialized')
|
|
322
|
+
return integrators
|
|
323
|
+
}
|
|
352
324
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
await signalRepository.deleteSession([jid])
|
|
361
|
-
logger.info({ jid }, '[interop] session reset — next send will use pkmsg')
|
|
362
|
-
}
|
|
325
|
+
/**
|
|
326
|
+
* Reset the Signal session with an interop contact and force a fresh pkmsg handshake.
|
|
327
|
+
*/
|
|
328
|
+
const resetInteropSession = async jid => {
|
|
329
|
+
await signalRepository.deleteSession([jid])
|
|
330
|
+
logger.info({ jid }, '[interop] session reset — next send will use pkmsg')
|
|
331
|
+
}
|
|
363
332
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
INTEROP_MEX_QUERY_IDS.CREATE_GROUP,
|
|
377
|
-
'xwa2_interop_group_create'
|
|
378
|
-
)
|
|
379
|
-
logger.info({ participants }, '[interop] group created via MEX')
|
|
380
|
-
return result
|
|
381
|
-
}
|
|
333
|
+
/**
|
|
334
|
+
* Create an interop group via MEX.
|
|
335
|
+
*/
|
|
336
|
+
const createInteropGroup = async participants => {
|
|
337
|
+
const result = await mexQuery(
|
|
338
|
+
{ input: { participants: participants.map(jid => ({ jid })) } },
|
|
339
|
+
INTEROP_MEX_QUERY_IDS.CREATE_GROUP,
|
|
340
|
+
'xwa2_interop_group_create'
|
|
341
|
+
)
|
|
342
|
+
logger.info({ participants }, '[interop] group created via MEX')
|
|
343
|
+
return result
|
|
344
|
+
}
|
|
382
345
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
INTEROP_MEX_QUERY_IDS.LEAVE_GROUP,
|
|
397
|
-
'xwa2_interop_group_leave'
|
|
398
|
-
)
|
|
399
|
-
logger.info({ jids: ids }, '[interop] left group(s) via MEX')
|
|
400
|
-
return result
|
|
401
|
-
}
|
|
346
|
+
/**
|
|
347
|
+
* Leave one or more interop groups via MEX.
|
|
348
|
+
*/
|
|
349
|
+
const leaveInteropGroup = async jids => {
|
|
350
|
+
const ids = Array.isArray(jids)? jids : [jids]
|
|
351
|
+
const result = await mexQuery(
|
|
352
|
+
{ input: { groups_to_leave: ids.map(jid => ({ gid: jid.split('@')[0] })) } },
|
|
353
|
+
INTEROP_MEX_QUERY_IDS.LEAVE_GROUP,
|
|
354
|
+
'xwa2_interop_group_leave'
|
|
355
|
+
)
|
|
356
|
+
logger.info({ jids: ids }, '[interop] left group(s) via MEX')
|
|
357
|
+
return result
|
|
358
|
+
}
|
|
402
359
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return mexQuery(
|
|
415
|
-
{ input: { gid, participants: participants.map(jid => ({ jid })) } },
|
|
416
|
-
INTEROP_MEX_QUERY_IDS.ADD_PARTICIPANTS,
|
|
417
|
-
'xwa2_interop_add_participants_to_group'
|
|
418
|
-
)
|
|
419
|
-
}
|
|
360
|
+
/**
|
|
361
|
+
* Add participants to an existing interop group via MEX.
|
|
362
|
+
*/
|
|
363
|
+
const addParticipantsToInteropGroup = async (groupJid, participants) => {
|
|
364
|
+
const gid = groupJid.split('@')[0]
|
|
365
|
+
return mexQuery(
|
|
366
|
+
{ input: { gid, participants: participants.map(jid => ({ jid })) } },
|
|
367
|
+
INTEROP_MEX_QUERY_IDS.ADD_PARTICIPANTS,
|
|
368
|
+
'xwa2_interop_add_participants_to_group'
|
|
369
|
+
)
|
|
370
|
+
}
|
|
420
371
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
*/
|
|
429
|
-
const queryInteropGroupInfo = async groupJid => {
|
|
430
|
-
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
|
-
)
|
|
436
|
-
}
|
|
372
|
+
/**
|
|
373
|
+
* Query info about an interop group via MEX.
|
|
374
|
+
*/
|
|
375
|
+
const queryInteropGroupInfo = async groupJid => {
|
|
376
|
+
const gid = groupJid.split('@')[0]
|
|
377
|
+
return mexQuery({ group_input: { gid } }, INTEROP_MEX_QUERY_IDS.QUERY_GROUP_INFO, 'xwa2_interop_group_query_by_id')
|
|
378
|
+
}
|
|
437
379
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
* @param {string} setting - New value
|
|
449
|
-
*/
|
|
450
|
-
const updateInteropPrivacySetting = async (feature, setting) => {
|
|
451
|
-
return mexQuery(
|
|
452
|
-
{ feature, setting },
|
|
453
|
-
INTEROP_MEX_QUERY_IDS.PRIVACY_SETTINGS_UPDATE,
|
|
454
|
-
'xwa2_interop_privacy_setting_update'
|
|
455
|
-
)
|
|
456
|
-
}
|
|
380
|
+
/**
|
|
381
|
+
* Update an interop privacy setting via MEX.
|
|
382
|
+
*/
|
|
383
|
+
const updateInteropPrivacySetting = async (feature, setting) => {
|
|
384
|
+
return mexQuery(
|
|
385
|
+
{ feature, setting },
|
|
386
|
+
INTEROP_MEX_QUERY_IDS.PRIVACY_SETTINGS_UPDATE,
|
|
387
|
+
'xwa2_interop_privacy_setting_update'
|
|
388
|
+
)
|
|
389
|
+
}
|
|
457
390
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
setting,
|
|
475
|
-
contacts,
|
|
476
|
-
contactListType,
|
|
477
|
-
dhash = 'none'
|
|
478
|
-
) => {
|
|
479
|
-
return mexQuery(
|
|
480
|
-
{ feature, setting, contacts, contact_list_type: contactListType, dhash },
|
|
481
|
-
INTEROP_MEX_QUERY_IDS.PRIVACY_SETTINGS_WITH_CONTACT_LIST,
|
|
482
|
-
'xwa2_interop_privacy_setting_with_contact_list_update'
|
|
483
|
-
)
|
|
484
|
-
}
|
|
391
|
+
/**
|
|
392
|
+
* Update an interop privacy setting with an explicit contact list via MEX.
|
|
393
|
+
*/
|
|
394
|
+
const updateInteropPrivacySettingWithContactList = async (
|
|
395
|
+
feature,
|
|
396
|
+
setting,
|
|
397
|
+
contacts,
|
|
398
|
+
contactListType,
|
|
399
|
+
dhash = 'none'
|
|
400
|
+
) => {
|
|
401
|
+
return mexQuery(
|
|
402
|
+
{ feature, setting, contacts, contact_list_type: contactListType, dhash },
|
|
403
|
+
INTEROP_MEX_QUERY_IDS.PRIVACY_SETTINGS_WITH_CONTACT_LIST,
|
|
404
|
+
'xwa2_interop_privacy_setting_with_contact_list_update'
|
|
405
|
+
)
|
|
406
|
+
}
|
|
485
407
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const privacyNode = getBinaryNodeChild(result, 'privacy')
|
|
514
|
-
const userNode = getBinaryNodeChild(privacyNode, 'user')
|
|
515
|
-
// "allowed" means the server confirmed the user can be added; any other value or
|
|
516
|
-
// absence of the attribute means the privacy setting blocks the add.
|
|
517
|
-
return userNode?.attrs?.result === 'allowed'
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
return {
|
|
521
|
-
...sock,
|
|
522
|
-
fetchIntegrators,
|
|
523
|
-
acceptInteropTOS,
|
|
524
|
-
optInIntegrators,
|
|
525
|
-
optOutIntegrators,
|
|
526
|
-
resolveInteropUser,
|
|
527
|
-
resolveInteropUsers,
|
|
528
|
-
getReachabilitySettings,
|
|
529
|
-
setReachabilitySettings,
|
|
530
|
-
blockInteropUser,
|
|
531
|
-
unblockInteropUser,
|
|
532
|
-
reportInteropSpam,
|
|
533
|
-
trustInteropContact,
|
|
534
|
-
initInterop,
|
|
535
|
-
resetInteropSession,
|
|
536
|
-
createInteropGroup,
|
|
537
|
-
leaveInteropGroup,
|
|
538
|
-
addParticipantsToInteropGroup,
|
|
539
|
-
queryInteropGroupInfo,
|
|
540
|
-
updateInteropPrivacySetting,
|
|
541
|
-
updateInteropPrivacySettingWithContactList,
|
|
542
|
-
getInteropGroupAddPrivacy,
|
|
543
|
-
INTEGRATOR_BIRDYCHAT,
|
|
544
|
-
INTEGRATOR_HAIKET,
|
|
545
|
-
INTEROP_MEX_QUERY_IDS
|
|
546
|
-
}
|
|
547
|
-
}
|
|
408
|
+
/**
|
|
409
|
+
* Check whether an interop user allows being added to groups (GROUPADD privacy).
|
|
410
|
+
*/
|
|
411
|
+
const getInteropGroupAddPrivacy = async (jid, integratorId) => {
|
|
412
|
+
const result = await query({
|
|
413
|
+
tag: 'iq',
|
|
414
|
+
attrs: { type: 'get', xmlns: 'w:interop', to: S_WHATSAPP_NET },
|
|
415
|
+
content: [
|
|
416
|
+
{
|
|
417
|
+
tag: 'privacy',
|
|
418
|
+
attrs: { feature: 'GROUPADD' },
|
|
419
|
+
content: [
|
|
420
|
+
{
|
|
421
|
+
tag: 'user',
|
|
422
|
+
attrs: {
|
|
423
|
+
jid,
|
|
424
|
+
integrator_id: integratorId.toString()
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
}
|
|
429
|
+
]
|
|
430
|
+
})
|
|
431
|
+
const privacyNode = getBinaryNodeChild(result, 'privacy')
|
|
432
|
+
const userNode = getBinaryNodeChild(privacyNode, 'user')
|
|
433
|
+
return userNode?.attrs?.result === 'allowed'
|
|
434
|
+
}
|
|
548
435
|
|
|
549
|
-
|
|
436
|
+
return {
|
|
437
|
+
...sock,
|
|
438
|
+
fetchIntegrators,
|
|
439
|
+
acceptInteropTOS,
|
|
440
|
+
optInIntegrators,
|
|
441
|
+
optOutIntegrators,
|
|
442
|
+
resolveInteropUser,
|
|
443
|
+
resolveInteropUsers,
|
|
444
|
+
getReachabilitySettings,
|
|
445
|
+
setReachabilitySettings,
|
|
446
|
+
blockInteropUser,
|
|
447
|
+
unblockInteropUser,
|
|
448
|
+
reportInteropSpam,
|
|
449
|
+
trustInteropContact,
|
|
450
|
+
initInterop,
|
|
451
|
+
resetInteropSession,
|
|
452
|
+
createInteropGroup,
|
|
453
|
+
leaveInteropGroup,
|
|
454
|
+
addParticipantsToInteropGroup,
|
|
455
|
+
queryInteropGroupInfo,
|
|
456
|
+
updateInteropPrivacySetting,
|
|
457
|
+
updateInteropPrivacySettingWithContactList,
|
|
458
|
+
getInteropGroupAddPrivacy,
|
|
459
|
+
INTEGRATOR_BIRDYCHAT,
|
|
460
|
+
INTEGRATOR_HAIKET,
|
|
461
|
+
INTEROP_MEX_QUERY_IDS
|
|
462
|
+
}
|
|
463
|
+
}
|