@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
package/lib/Socket/chats.js
CHANGED
|
@@ -15,7 +15,6 @@ const State_1 = require('../Types/State')
|
|
|
15
15
|
const Utils_1 = require('../Utils')
|
|
16
16
|
const make_mutex_1 = require('../Utils/make-mutex')
|
|
17
17
|
const process_message_1 = __importDefault(require('../Utils/process-message'))
|
|
18
|
-
const { unwrapSecretEncryptedMessage } = require('../Utils/process-message')
|
|
19
18
|
const tc_token_utils_1 = require('../Utils/tc-token-utils')
|
|
20
19
|
const WABinary_1 = require('../WABinary')
|
|
21
20
|
const WAUSync_1 = require('../WAUSync')
|
|
@@ -63,47 +62,45 @@ const makeChatsSocket = config => {
|
|
|
63
62
|
} = sock
|
|
64
63
|
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
|
|
65
64
|
let privacySettings
|
|
66
|
-
|
|
65
|
+
/** Server-assigned AB props for protocol behavior. */
|
|
67
66
|
const serverProps = {
|
|
68
|
-
|
|
67
|
+
/** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
|
|
69
68
|
privacyTokenOn1to1: true,
|
|
70
|
-
|
|
69
|
+
/** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
|
|
71
70
|
profilePicPrivacyToken: true,
|
|
72
|
-
|
|
71
|
+
/** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
|
|
73
72
|
lidTrustedTokenIssueToLid: false
|
|
74
73
|
}
|
|
75
74
|
let syncState = State_1.SyncState.Connecting
|
|
76
|
-
|
|
75
|
+
/** this mutex ensures that messages are processed in order */
|
|
77
76
|
const messageMutex = (0, make_mutex_1.makeMutex)()
|
|
78
|
-
|
|
77
|
+
/** this mutex ensures that receipts are processed in order */
|
|
79
78
|
const receiptMutex = (0, make_mutex_1.makeMutex)()
|
|
80
|
-
|
|
79
|
+
/** this mutex ensures that app state patches are processed in order */
|
|
81
80
|
const appStatePatchMutex = (0, make_mutex_1.makeMutex)()
|
|
82
|
-
|
|
81
|
+
/** this mutex ensures that notifications are processed in order */
|
|
83
82
|
const notificationMutex = (0, make_mutex_1.makeMutex)()
|
|
84
|
-
|
|
83
|
+
// Timeout for AwaitingInitialSync state
|
|
85
84
|
let awaitingSyncTimeout
|
|
86
|
-
|
|
85
|
+
// In-memory history sync completion tracking (resets on reconnection)
|
|
87
86
|
const historySyncStatus = {
|
|
88
87
|
initialBootstrapComplete: false,
|
|
89
88
|
recentSyncComplete: false
|
|
90
89
|
}
|
|
91
90
|
let historySyncPausedTimeout
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
// Collections blocked on missing app state sync keys (mirrors WA Web's "Blocked" state).
|
|
92
|
+
// When a key arrives via APP_STATE_SYNC_KEY_SHARE, these are re-synced.
|
|
94
93
|
const blockedCollections = new Set()
|
|
95
|
-
|
|
96
|
-
const _nlServerIdCache = new Map()
|
|
97
94
|
const placeholderResendCache =
|
|
98
95
|
config.placeholderResendCache ||
|
|
99
96
|
new node_cache_1.default({
|
|
100
|
-
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
|
|
97
|
+
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
101
98
|
useClones: false
|
|
102
99
|
})
|
|
103
100
|
if (!config.placeholderResendCache) {
|
|
104
101
|
config.placeholderResendCache = placeholderResendCache
|
|
105
102
|
}
|
|
106
|
-
|
|
103
|
+
/** helper function to fetch the given app state sync key */
|
|
107
104
|
const getAppStateSyncKey = async keyId => {
|
|
108
105
|
const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId])
|
|
109
106
|
return key
|
|
@@ -119,67 +116,11 @@ const makeChatsSocket = config => {
|
|
|
119
116
|
},
|
|
120
117
|
content: [{ tag: 'privacy', attrs: {} }]
|
|
121
118
|
})
|
|
122
|
-
|
|
123
|
-
privacySettings = (0, WABinary_1.reduceBinaryNodeToDictionary)(privacyNode, 'category')
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const onlinePrivacy =
|
|
128
|
-
privacySettings['online'] ||
|
|
129
|
-
(0, WABinary_1.getBinaryNodeChild)(privacyNode, 'online_privacy_setting')?.attrs?.value ||
|
|
130
|
-
'all'
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const enhancedBlockEnabled =
|
|
134
|
-
privacyNode?.attrs?.enhanced_block_enabled === 'true' ||
|
|
135
|
-
(0, WABinary_1.getBinaryNodeChild)(privacyNode, 'enhanced_block')?.attrs?.enabled === 'true'
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const mdPrivacyV2 =
|
|
139
|
-
privacyNode?.attrs?.md_privacy_v2 === 'true' ||
|
|
140
|
-
(0, WABinary_1.getBinaryNodeChild)(privacyNode, 'md_privacy_v2')?.attrs?.value === 'true'
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const syncdClearChatDeleteChatEnabled =
|
|
144
|
-
privacyNode?.attrs?.syncd_clear_chat_delete_chat_enabled === 'true' ||
|
|
145
|
-
(0, WABinary_1.getBinaryNodeChild)(privacyNode, 'syncd_clear_chat')?.attrs?.delete_chat_enabled === 'true'
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const syncdAntiTamperingEnabled =
|
|
149
|
-
privacyNode?.attrs?.syncd_anti_tampering_fatal_exception_enabled === 'true' ||
|
|
150
|
-
(0, WABinary_1.getBinaryNodeChild)(privacyNode, 'syncd_anti_tampering')?.attrs?.fatal_exception_enabled ===
|
|
151
|
-
'true'
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const keyRotationEnabled =
|
|
155
|
-
privacyNode?.attrs?.syncd_key_rotation_enabled === 'true' ||
|
|
156
|
-
(0, WABinary_1.getBinaryNodeChild)(privacyNode, 'syncd_key_rotation')?.attrs?.enabled === 'true'
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
ev.emit('settings.update', {
|
|
160
|
-
onlinePrivacy,
|
|
161
|
-
enhancedBlockEnabled,
|
|
162
|
-
mdPrivacyV2,
|
|
163
|
-
syncdClearChatDeleteChatEnabled,
|
|
164
|
-
...(syncdAntiTamperingEnabled ? { syncdAntiTamperingEnabled: true } : {}),
|
|
165
|
-
keyRotationEnabled
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
ev.emit('creds.update', {
|
|
170
|
-
privacySettings: {
|
|
171
|
-
onlinePrivacy,
|
|
172
|
-
enhancedBlockEnabled,
|
|
173
|
-
mdPrivacyV2,
|
|
174
|
-
syncdClearChatDeleteChatEnabled,
|
|
175
|
-
syncdAntiTamperingEnabled,
|
|
176
|
-
keyRotationEnabled
|
|
177
|
-
}
|
|
178
|
-
})
|
|
119
|
+
privacySettings = (0, WABinary_1.reduceBinaryNodeToDictionary)(content?.[0], 'category')
|
|
179
120
|
}
|
|
180
121
|
return privacySettings
|
|
181
122
|
}
|
|
182
|
-
|
|
123
|
+
/** helper function to run a privacy IQ query */
|
|
183
124
|
const privacyQuery = async (name, value) => {
|
|
184
125
|
await query({
|
|
185
126
|
tag: 'iq',
|
|
@@ -220,7 +161,11 @@ const makeChatsSocket = config => {
|
|
|
220
161
|
const updateStatusPrivacy = async value => {
|
|
221
162
|
await privacyQuery('status', value)
|
|
222
163
|
}
|
|
223
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Fetch status privacy settings via `xmlns="status"` IQ GET.
|
|
166
|
+
* Returns the current distribution type and any custom lists.
|
|
167
|
+
* Source: GetStatusPrivacyJob.java, feature flag 3843 controls retry.
|
|
168
|
+
*/
|
|
224
169
|
const getStatusPrivacy = async () => {
|
|
225
170
|
const result = await query({
|
|
226
171
|
tag: 'iq',
|
|
@@ -234,24 +179,31 @@ const makeChatsSocket = config => {
|
|
|
234
179
|
const privacyNode = result?.content?.[0]
|
|
235
180
|
if (!privacyNode) return null
|
|
236
181
|
const lists = []
|
|
237
|
-
for (const listNode of privacyNode.content || []) {
|
|
182
|
+
for (const listNode of (privacyNode.content || [])) {
|
|
238
183
|
const { type, id, listname, emoji, selected, deleted } = listNode.attrs || {}
|
|
239
184
|
const members = (listNode.content || []).map(u => u.attrs?.jid).filter(Boolean)
|
|
240
185
|
lists.push({ type, id, listname, emoji, selected: selected === 'true', deleted: deleted === 'true', members })
|
|
241
186
|
}
|
|
242
187
|
return lists
|
|
243
188
|
}
|
|
244
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Set status privacy via `xmlns="status"` IQ SET.
|
|
191
|
+
* Supports simple distribution types and contact-level whitelist/blacklist/customlist.
|
|
192
|
+
*
|
|
193
|
+
* @param {'contacts'|'whitelist'|'blacklist'|'null'} type - Distribution type
|
|
194
|
+
* @param {string[]} [jids] - JIDs for the list (whitelist/blacklist)
|
|
195
|
+
* @param {Array<{id: string, listname: string, emoji?: string, selected?: boolean, deleted?: boolean, members?: string[]}>} [customLists]
|
|
196
|
+
*/
|
|
245
197
|
const setStatusPrivacy = async (type, jids = [], customLists = []) => {
|
|
246
198
|
const content = []
|
|
247
|
-
|
|
199
|
+
// main distribution list
|
|
248
200
|
const mainList = {
|
|
249
201
|
tag: 'list',
|
|
250
202
|
attrs: { type },
|
|
251
203
|
content: jids.map(jid => ({ tag: 'user', attrs: { jid }, content: [] }))
|
|
252
204
|
}
|
|
253
205
|
content.push(mainList)
|
|
254
|
-
|
|
206
|
+
// custom named lists
|
|
255
207
|
for (const cl of customLists) {
|
|
256
208
|
const attrs = { type: 'customlist', id: cl.id, listname: cl.listname }
|
|
257
209
|
if (cl.emoji) attrs.emoji = cl.emoji
|
|
@@ -297,7 +249,12 @@ const makeChatsSocket = config => {
|
|
|
297
249
|
]
|
|
298
250
|
})
|
|
299
251
|
}
|
|
300
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Fetch broadcast list quota from the server.
|
|
254
|
+
* Source: BroadcastListQuotaProtocol.java — IQ xmlns="w:biz", 32s timeout.
|
|
255
|
+
*
|
|
256
|
+
* Returns: { messagesLeft, totalLimit, isHeavySender, startTs, endTs, resetTs }
|
|
257
|
+
*/
|
|
301
258
|
const fetchBroadcastListQuota = async () => {
|
|
302
259
|
const result = await query(
|
|
303
260
|
{
|
|
@@ -315,35 +272,12 @@ const makeChatsSocket = config => {
|
|
|
315
272
|
const timeframeNode = (0, WABinary_1.getBinaryNodeChild)(result, 'timeframe')
|
|
316
273
|
if (!limitsNode) return null
|
|
317
274
|
return {
|
|
318
|
-
messagesLeft: parseInt(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
),
|
|
324
|
-
totalLimit: parseInt(
|
|
325
|
-
limitsNode.attrs?.total_limit ?? (0, WABinary_1.getBinaryNodeChild)(limitsNode, 'total_limit')?.content ?? '0',
|
|
326
|
-
10
|
|
327
|
-
),
|
|
328
|
-
isHeavySender:
|
|
329
|
-
(limitsNode.attrs?.is_heavy_sender ??
|
|
330
|
-
(0, WABinary_1.getBinaryNodeChild)(limitsNode, 'is_heavy_sender')?.content) === 'true',
|
|
331
|
-
startTs: parseInt(
|
|
332
|
-
timeframeNode?.attrs?.start_ts_s ??
|
|
333
|
-
(0, WABinary_1.getBinaryNodeChild)(timeframeNode, 'start_ts_s')?.content ??
|
|
334
|
-
'0',
|
|
335
|
-
10
|
|
336
|
-
),
|
|
337
|
-
endTs: parseInt(
|
|
338
|
-
timeframeNode?.attrs?.end_ts_s ?? (0, WABinary_1.getBinaryNodeChild)(timeframeNode, 'end_ts_s')?.content ?? '0',
|
|
339
|
-
10
|
|
340
|
-
),
|
|
341
|
-
resetTs: parseInt(
|
|
342
|
-
timeframeNode?.attrs?.reset_ts_s ??
|
|
343
|
-
(0, WABinary_1.getBinaryNodeChild)(timeframeNode, 'reset_ts_s')?.content ??
|
|
344
|
-
'0',
|
|
345
|
-
10
|
|
346
|
-
)
|
|
275
|
+
messagesLeft: parseInt(limitsNode.attrs?.messages_left ?? (0, WABinary_1.getBinaryNodeChild)(limitsNode, 'messages_left')?.content ?? '0'),
|
|
276
|
+
totalLimit: parseInt(limitsNode.attrs?.total_limit ?? (0, WABinary_1.getBinaryNodeChild)(limitsNode, 'total_limit')?.content ?? '0'),
|
|
277
|
+
isHeavySender: (limitsNode.attrs?.is_heavy_sender ?? (0, WABinary_1.getBinaryNodeChild)(limitsNode, 'is_heavy_sender')?.content) === 'true',
|
|
278
|
+
startTs: parseInt(timeframeNode?.attrs?.start_ts_s ?? (0, WABinary_1.getBinaryNodeChild)(timeframeNode, 'start_ts_s')?.content ?? '0'),
|
|
279
|
+
endTs: parseInt(timeframeNode?.attrs?.end_ts_s ?? (0, WABinary_1.getBinaryNodeChild)(timeframeNode, 'end_ts_s')?.content ?? '0'),
|
|
280
|
+
resetTs: parseInt(timeframeNode?.attrs?.reset_ts_s ?? (0, WABinary_1.getBinaryNodeChild)(timeframeNode, 'reset_ts_s')?.content ?? '0')
|
|
347
281
|
}
|
|
348
282
|
}
|
|
349
283
|
|
|
@@ -378,7 +312,11 @@ const makeChatsSocket = config => {
|
|
|
378
312
|
}
|
|
379
313
|
return botList
|
|
380
314
|
}
|
|
381
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Get the global chat-blocking status (block messages from unknown accounts).
|
|
317
|
+
* Ported from WhatsApp Web's WASmaxPsaChatBlockGetRPC (xmlns `w:comms:chat`).
|
|
318
|
+
* @returns {Promise<'blocked' | 'unblocked' | undefined>}
|
|
319
|
+
*/
|
|
382
320
|
const getChatBlockingStatus = async () => {
|
|
383
321
|
const result = await query({
|
|
384
322
|
tag: 'iq',
|
|
@@ -394,7 +332,12 @@ const makeChatsSocket = config => {
|
|
|
394
332
|
(0, WABinary_1.getBinaryNodeChild)((0, WABinary_1.getBinaryNodeChild)(result, 'query'), 'blocking')
|
|
395
333
|
return blocking?.attrs?.status
|
|
396
334
|
}
|
|
397
|
-
|
|
335
|
+
/**
|
|
336
|
+
* Set the global chat-blocking status (block messages from unknown accounts).
|
|
337
|
+
* Ported from WhatsApp Web's WASmaxPsaChatBlockSetRPC (xmlns `w:comms:chat`).
|
|
338
|
+
* @param {'block' | 'unblock'} action
|
|
339
|
+
* @returns {Promise<'blocked' | 'unblocked' | undefined>} the resulting status
|
|
340
|
+
*/
|
|
398
341
|
const updateChatBlockingStatus = async action => {
|
|
399
342
|
const result = await query({
|
|
400
343
|
tag: 'iq',
|
|
@@ -408,7 +351,12 @@ const makeChatsSocket = config => {
|
|
|
408
351
|
const blocking = (0, WABinary_1.getBinaryNodeChild)(result, 'blocking')
|
|
409
352
|
return blocking?.attrs?.status
|
|
410
353
|
}
|
|
411
|
-
|
|
354
|
+
/**
|
|
355
|
+
* Get the user's pending TOS disclosures / notices.
|
|
356
|
+
* Ported from WhatsApp Web's WASmaxUserNoticeGetDisclosuresRPC (xmlns `tos`).
|
|
357
|
+
* @param {number} [t] last-seen disclosure timestamp
|
|
358
|
+
* @returns {Promise<Array<Record<string, string>>>} the `<notice>` attributes
|
|
359
|
+
*/
|
|
412
360
|
const getUserDisclosures = async (t = 0) => {
|
|
413
361
|
const result = await query({
|
|
414
362
|
tag: 'iq',
|
|
@@ -417,65 +365,18 @@ const makeChatsSocket = config => {
|
|
|
417
365
|
})
|
|
418
366
|
return (0, WABinary_1.getBinaryNodeChildren)(result, 'notice').map(n => ({ ...n.attrs }))
|
|
419
367
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
tag: 'iq',
|
|
424
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, xmlns: 'tos', type: 'set' },
|
|
425
|
-
content: [{ tag: 'trackable', attrs: { id: String(noticeId), result: String(result) } }]
|
|
426
|
-
})
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const reportSpam = async (jid, messages, spamFlow = 'contact_info_report', subject) => {
|
|
430
|
-
const msgNodes = (messages || []).map(m => ({
|
|
431
|
-
tag: 'message',
|
|
432
|
-
attrs: {
|
|
433
|
-
from: String(jid),
|
|
434
|
-
t: String(m.t),
|
|
435
|
-
id: String(m.id)
|
|
436
|
-
}
|
|
437
|
-
}))
|
|
438
|
-
await query({
|
|
439
|
-
tag: 'iq',
|
|
440
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, xmlns: 'spam', type: 'set' },
|
|
441
|
-
content: [
|
|
442
|
-
{
|
|
443
|
-
tag: 'spam_list',
|
|
444
|
-
attrs: {
|
|
445
|
-
jid: String(jid),
|
|
446
|
-
spam_flow: String(spamFlow),
|
|
447
|
-
...(subject ? { subject: String(subject) } : {})
|
|
448
|
-
},
|
|
449
|
-
content: msgNodes
|
|
450
|
-
}
|
|
451
|
-
]
|
|
452
|
-
})
|
|
453
|
-
}
|
|
454
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Get the account opt-out list (`optoutlist` IQ). Returns the raw result node.
|
|
370
|
+
*/
|
|
455
371
|
const getOptOutList = async () => {
|
|
456
372
|
return query({
|
|
457
373
|
tag: 'iq',
|
|
458
374
|
attrs: { to: WABinary_1.S_WHATSAPP_NET, xmlns: 'optoutlist', type: 'get' }
|
|
459
375
|
})
|
|
460
376
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
tag: 'iq',
|
|
465
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, xmlns: 'privatestats', type: 'get' },
|
|
466
|
-
content: [
|
|
467
|
-
{
|
|
468
|
-
tag: 'sign_credential',
|
|
469
|
-
attrs: { version: '1' },
|
|
470
|
-
content: [{ tag: 'blinded_credential', attrs: {}, content: blindedCredential }]
|
|
471
|
-
}
|
|
472
|
-
]
|
|
473
|
-
})
|
|
474
|
-
const signedNode = (0, WABinary_1.getBinaryNodeChild)(result, 'sign_credential')
|
|
475
|
-
const signedBytes = (0, WABinary_1.getBinaryNodeChild)(signedNode, 'signed_credential')
|
|
476
|
-
return signedBytes?.content instanceof Uint8Array ? Buffer.from(signedBytes.content) : undefined
|
|
477
|
-
}
|
|
478
|
-
|
|
377
|
+
/**
|
|
378
|
+
* Get push-notification settings (`urn:xmpp:whatsapp:push`).
|
|
379
|
+
*/
|
|
479
380
|
const getPushConfig = async () => {
|
|
480
381
|
const result = await query({
|
|
481
382
|
tag: 'iq',
|
|
@@ -484,7 +385,11 @@ const makeChatsSocket = config => {
|
|
|
484
385
|
})
|
|
485
386
|
return (0, WABinary_1.getBinaryNodeChild)(result, 'settings')
|
|
486
387
|
}
|
|
487
|
-
|
|
388
|
+
/**
|
|
389
|
+
* Set push-notification config (`urn:xmpp:whatsapp:push`). Mainly web push —
|
|
390
|
+
* pass the FCM-style config (platform / endpoint / auth / p256dh).
|
|
391
|
+
* @param {Record<string, string>} config
|
|
392
|
+
*/
|
|
488
393
|
const setPushConfig = async config => {
|
|
489
394
|
await query({
|
|
490
395
|
tag: 'iq',
|
|
@@ -497,7 +402,7 @@ const makeChatsSocket = config => {
|
|
|
497
402
|
for (const jid of jids) {
|
|
498
403
|
usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid))
|
|
499
404
|
}
|
|
500
|
-
const result = await executeUSyncQuery(usyncQuery)
|
|
405
|
+
const result = await sock.executeUSyncQuery(usyncQuery)
|
|
501
406
|
if (result) {
|
|
502
407
|
return result.list
|
|
503
408
|
}
|
|
@@ -507,12 +412,12 @@ const makeChatsSocket = config => {
|
|
|
507
412
|
for (const jid of jids) {
|
|
508
413
|
usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid))
|
|
509
414
|
}
|
|
510
|
-
const result = await executeUSyncQuery(usyncQuery)
|
|
415
|
+
const result = await sock.executeUSyncQuery(usyncQuery)
|
|
511
416
|
if (result) {
|
|
512
417
|
return result.list
|
|
513
418
|
}
|
|
514
419
|
}
|
|
515
|
-
|
|
420
|
+
/** update the profile picture for yourself or a group */
|
|
516
421
|
const updateProfilePicture = async (jid, content, dimensions) => {
|
|
517
422
|
let targetJid
|
|
518
423
|
if (!jid) {
|
|
@@ -521,7 +426,7 @@ const makeChatsSocket = config => {
|
|
|
521
426
|
)
|
|
522
427
|
}
|
|
523
428
|
if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
|
|
524
|
-
targetJid = (0, WABinary_1.jidNormalizedUser)(jid)
|
|
429
|
+
targetJid = (0, WABinary_1.jidNormalizedUser)(jid) // in case it is someone other than us
|
|
525
430
|
} else {
|
|
526
431
|
targetJid = undefined
|
|
527
432
|
}
|
|
@@ -543,7 +448,7 @@ const makeChatsSocket = config => {
|
|
|
543
448
|
]
|
|
544
449
|
})
|
|
545
450
|
}
|
|
546
|
-
|
|
451
|
+
/** remove the profile picture for yourself or a group */
|
|
547
452
|
const removeProfilePicture = async jid => {
|
|
548
453
|
let targetJid
|
|
549
454
|
if (!jid) {
|
|
@@ -552,7 +457,7 @@ const makeChatsSocket = config => {
|
|
|
552
457
|
)
|
|
553
458
|
}
|
|
554
459
|
if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
|
|
555
|
-
targetJid = (0, WABinary_1.jidNormalizedUser)(jid)
|
|
460
|
+
targetJid = (0, WABinary_1.jidNormalizedUser)(jid) // in case it is someone other than us
|
|
556
461
|
} else {
|
|
557
462
|
targetJid = undefined
|
|
558
463
|
}
|
|
@@ -566,7 +471,7 @@ const makeChatsSocket = config => {
|
|
|
566
471
|
}
|
|
567
472
|
})
|
|
568
473
|
}
|
|
569
|
-
|
|
474
|
+
/** update the profile status for yourself */
|
|
570
475
|
const updateProfileStatus = async status => {
|
|
571
476
|
await query({
|
|
572
477
|
tag: 'iq',
|
|
@@ -587,24 +492,17 @@ const makeChatsSocket = config => {
|
|
|
587
492
|
const updateProfileName = async name => {
|
|
588
493
|
await chatModify({ pushNameSetting: name }, '')
|
|
589
494
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
const fetchBlocklist = async (dhash = null) => {
|
|
495
|
+
const fetchBlocklist = async () => {
|
|
595
496
|
const result = await query({
|
|
596
497
|
tag: 'iq',
|
|
597
498
|
attrs: {
|
|
598
499
|
xmlns: 'blocklist',
|
|
599
500
|
to: WABinary_1.S_WHATSAPP_NET,
|
|
600
501
|
type: 'get'
|
|
601
|
-
}
|
|
602
|
-
content: dhash ? [{ tag: 'item', attrs: { dhash } }] : null
|
|
502
|
+
}
|
|
603
503
|
})
|
|
604
504
|
const listNode = (0, WABinary_1.getBinaryNodeChild)(result, 'list')
|
|
605
|
-
|
|
606
|
-
ev.emit('blocklist.set', { blocklist: jids })
|
|
607
|
-
return jids
|
|
505
|
+
return (0, WABinary_1.getBinaryNodeChildren)(listNode, 'item').map(n => n.attrs.jid)
|
|
608
506
|
}
|
|
609
507
|
const updateBlockStatus = async (jid, action) => {
|
|
610
508
|
await query({
|
|
@@ -626,67 +524,26 @@ const makeChatsSocket = config => {
|
|
|
626
524
|
})
|
|
627
525
|
}
|
|
628
526
|
const getBusinessProfile = async jid => {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
tag: 'profile',
|
|
647
|
-
attrs: { jid }
|
|
648
|
-
}
|
|
649
|
-
]
|
|
650
|
-
}
|
|
651
|
-
]
|
|
652
|
-
}),
|
|
653
|
-
query({
|
|
654
|
-
tag: 'iq',
|
|
655
|
-
attrs: {
|
|
656
|
-
to: 's.whatsapp.net',
|
|
657
|
-
xmlns: 'w:biz',
|
|
658
|
-
type: 'get'
|
|
659
|
-
},
|
|
660
|
-
content: [
|
|
661
|
-
{
|
|
662
|
-
tag: 'verified_name',
|
|
663
|
-
attrs: { jid }
|
|
664
|
-
}
|
|
665
|
-
]
|
|
666
|
-
})
|
|
667
|
-
])
|
|
668
|
-
|
|
669
|
-
const verifiedNameNode = (0, WABinary_1.getBinaryNodeChild)(verifiedNameResult, 'verified_name')
|
|
670
|
-
let verifiedNameCert
|
|
671
|
-
if (verifiedNameNode) {
|
|
672
|
-
const certNode = (0, WABinary_1.getBinaryNodeChild)(verifiedNameNode, 'certificate')
|
|
673
|
-
if (certNode) {
|
|
674
|
-
const detailsNode = (0, WABinary_1.getBinaryNodeChild)(certNode, 'details')
|
|
675
|
-
const localizedNames = (0, WABinary_1.getBinaryNodeChildren)(certNode, 'localized_name').map(n => ({
|
|
676
|
-
lg: n.attrs?.lg,
|
|
677
|
-
lc: n.attrs?.lc,
|
|
678
|
-
verifiedName: n.attrs?.verified_name || n.content?.toString()
|
|
679
|
-
}))
|
|
680
|
-
verifiedNameCert = {
|
|
681
|
-
certSerial: certNode.attrs?.serial ? +certNode.attrs.serial : undefined,
|
|
682
|
-
issuer: certNode.attrs?.issuer,
|
|
683
|
-
details: {
|
|
684
|
-
verifiedName: detailsNode?.attrs?.verified_name || detailsNode?.content?.toString(),
|
|
685
|
-
localizedNames
|
|
686
|
-
}
|
|
527
|
+
const results = await query({
|
|
528
|
+
tag: 'iq',
|
|
529
|
+
attrs: {
|
|
530
|
+
to: 's.whatsapp.net',
|
|
531
|
+
xmlns: 'w:biz',
|
|
532
|
+
type: 'get'
|
|
533
|
+
},
|
|
534
|
+
content: [
|
|
535
|
+
{
|
|
536
|
+
tag: 'business_profile',
|
|
537
|
+
attrs: { v: '244' },
|
|
538
|
+
content: [
|
|
539
|
+
{
|
|
540
|
+
tag: 'profile',
|
|
541
|
+
attrs: { jid }
|
|
542
|
+
}
|
|
543
|
+
]
|
|
687
544
|
}
|
|
688
|
-
|
|
689
|
-
}
|
|
545
|
+
]
|
|
546
|
+
})
|
|
690
547
|
const profileNode = (0, WABinary_1.getBinaryNodeChild)(results, 'business_profile')
|
|
691
548
|
const profiles = (0, WABinary_1.getBinaryNodeChild)(profileNode, 'profile')
|
|
692
549
|
if (profiles) {
|
|
@@ -703,31 +560,9 @@ const makeChatsSocket = config => {
|
|
|
703
560
|
? (0, WABinary_1.getBinaryNodeChildren)(businessHours, 'business_hours_config')
|
|
704
561
|
: undefined
|
|
705
562
|
const websiteStr = website?.content?.toString()
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
const catalogStatus = {
|
|
709
|
-
exists: profiles.attrs?.catalog_exists === 'true' || profiles.attrs?.catalog_exists === true || false,
|
|
710
|
-
sendAll: profiles.attrs?.catalog_send_all === 'true' || profiles.attrs?.catalog_send_all === true || false
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
const cartEnabled =
|
|
715
|
-
profiles.attrs?.cart_enabled !== undefined
|
|
716
|
-
? profiles.attrs.cart_enabled === 'true' || profiles.attrs.cart_enabled === true
|
|
717
|
-
: undefined
|
|
718
|
-
const webCartEnabled =
|
|
719
|
-
profiles.attrs?.web_cart_enabled !== undefined
|
|
720
|
-
? profiles.attrs.web_cart_enabled === 'true' || profiles.attrs.web_cart_enabled === true
|
|
721
|
-
: undefined
|
|
722
|
-
const webCartOnOff = profiles.attrs?.web_cart_on_off
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const commerceExperience = profiles.attrs?.commerce_experience
|
|
726
|
-
|
|
727
563
|
return {
|
|
728
564
|
wid: profiles.attrs?.jid,
|
|
729
565
|
address: address?.content?.toString(),
|
|
730
|
-
businessAddress: address?.content?.toString(),
|
|
731
566
|
description: description?.content?.toString() || '',
|
|
732
567
|
website: websiteStr ? [websiteStr] : [],
|
|
733
568
|
email: email?.content?.toString(),
|
|
@@ -735,24 +570,7 @@ const makeChatsSocket = config => {
|
|
|
735
570
|
business_hours: {
|
|
736
571
|
timezone: businessHours?.attrs?.timezone,
|
|
737
572
|
business_config: businessHoursConfig?.map(({ attrs }) => attrs)
|
|
738
|
-
}
|
|
739
|
-
businessHours: businessHoursConfig
|
|
740
|
-
? {
|
|
741
|
-
timezone: businessHours?.attrs?.timezone ?? null,
|
|
742
|
-
config: businessHoursConfig.map(({ attrs }) => ({
|
|
743
|
-
dayOfWeek: attrs?.day_of_week ?? null,
|
|
744
|
-
openTime: attrs?.open_time ?? null,
|
|
745
|
-
closeTime: attrs?.close_time ?? null,
|
|
746
|
-
mode: attrs?.mode ?? null
|
|
747
|
-
}))
|
|
748
|
-
}
|
|
749
|
-
: null,
|
|
750
|
-
catalogStatus,
|
|
751
|
-
cartEnabled,
|
|
752
|
-
webCartEnabled,
|
|
753
|
-
webCartOnOff,
|
|
754
|
-
commerceExperience,
|
|
755
|
-
verifiedNameCert
|
|
573
|
+
}
|
|
756
574
|
}
|
|
757
575
|
}
|
|
758
576
|
}
|
|
@@ -787,13 +605,6 @@ const makeChatsSocket = config => {
|
|
|
787
605
|
isInitialSync ? { accountSettings: authState.creds.accountSettings } : undefined,
|
|
788
606
|
logger
|
|
789
607
|
)
|
|
790
|
-
|
|
791
|
-
const _nctSalt = mutation?.syncAction?.value?.nctSaltSyncAction?.salt
|
|
792
|
-
if (_nctSalt?.length) {
|
|
793
|
-
authState.keys
|
|
794
|
-
.set({ 'nct-salt': { default: Buffer.from(_nctSalt) } })
|
|
795
|
-
.catch(err => logger.debug({ err: err?.message }, 'nct: failed to persist salt'))
|
|
796
|
-
}
|
|
797
608
|
}
|
|
798
609
|
}
|
|
799
610
|
}
|
|
@@ -801,24 +612,24 @@ const makeChatsSocket = config => {
|
|
|
801
612
|
const appStateSyncKeyCache = new Map()
|
|
802
613
|
const getCachedAppStateSyncKey = async keyId => {
|
|
803
614
|
if (appStateSyncKeyCache.has(keyId)) {
|
|
804
|
-
return appStateSyncKeyCache.get(keyId)
|
|
615
|
+
return appStateSyncKeyCache.get(keyId) ?? undefined
|
|
805
616
|
}
|
|
806
617
|
const key = await getAppStateSyncKey(keyId)
|
|
807
618
|
appStateSyncKeyCache.set(keyId, key ?? null)
|
|
808
619
|
return key
|
|
809
620
|
}
|
|
810
|
-
|
|
811
|
-
|
|
621
|
+
// we use this to determine which events to fire
|
|
622
|
+
// otherwise when we resync from scratch -- all notifications will fire
|
|
812
623
|
const initialVersionMap = {}
|
|
813
624
|
const globalMutationMap = {}
|
|
814
625
|
await authState.keys.transaction(async () => {
|
|
815
626
|
const collectionsToHandle = new Set(collections)
|
|
816
|
-
|
|
627
|
+
// in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
|
|
817
628
|
const attemptsMap = {}
|
|
818
629
|
const forceSnapshotCollections = new Set()
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
630
|
+
// keep executing till all collections are done
|
|
631
|
+
// sometimes a single patch request will not return all the patches (God knows why)
|
|
632
|
+
// so we fetch till they're all done (this is determined by the "has_more_patches" flag)
|
|
822
633
|
while (collectionsToHandle.size) {
|
|
823
634
|
const states = {}
|
|
824
635
|
const nodes = []
|
|
@@ -826,7 +637,7 @@ const makeChatsSocket = config => {
|
|
|
826
637
|
const result = await authState.keys.get('app-state-sync-version', [name])
|
|
827
638
|
let state = result[name]
|
|
828
639
|
if (state) {
|
|
829
|
-
if (initialVersionMap[name] === undefined) {
|
|
640
|
+
if (typeof initialVersionMap[name] === 'undefined') {
|
|
830
641
|
initialVersionMap[name] = state.version
|
|
831
642
|
}
|
|
832
643
|
} else {
|
|
@@ -843,7 +654,7 @@ const makeChatsSocket = config => {
|
|
|
843
654
|
attrs: {
|
|
844
655
|
name,
|
|
845
656
|
version: state.version.toString(),
|
|
846
|
-
|
|
657
|
+
// return snapshot if syncing from scratch or forcing after a failed attempt
|
|
847
658
|
return_snapshot: (shouldForceSnapshot || !state.version).toString()
|
|
848
659
|
}
|
|
849
660
|
})
|
|
@@ -863,7 +674,7 @@ const makeChatsSocket = config => {
|
|
|
863
674
|
}
|
|
864
675
|
]
|
|
865
676
|
})
|
|
866
|
-
|
|
677
|
+
// extract from binary node
|
|
867
678
|
const decoded = await (0, Utils_1.extractSyncdPatches)(result, config?.options)
|
|
868
679
|
for (const key in decoded) {
|
|
869
680
|
const name = key
|
|
@@ -882,7 +693,7 @@ const makeChatsSocket = config => {
|
|
|
882
693
|
logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`)
|
|
883
694
|
await authState.keys.set({ 'app-state-sync-version': { [name]: newState } })
|
|
884
695
|
}
|
|
885
|
-
|
|
696
|
+
// only process if there are syncd patches
|
|
886
697
|
if (patches.length) {
|
|
887
698
|
const { state: newState, mutationMap } = await (0, Utils_1.decodePatches)(
|
|
888
699
|
name,
|
|
@@ -902,7 +713,7 @@ const makeChatsSocket = config => {
|
|
|
902
713
|
if (hasMorePatches) {
|
|
903
714
|
logger.info(`${name} has more patches...`)
|
|
904
715
|
} else {
|
|
905
|
-
|
|
716
|
+
// collection is done with sync
|
|
906
717
|
collectionsToHandle.delete(name)
|
|
907
718
|
}
|
|
908
719
|
} catch (error) {
|
|
@@ -944,15 +755,18 @@ const makeChatsSocket = config => {
|
|
|
944
755
|
onMutation(globalMutationMap[key])
|
|
945
756
|
}
|
|
946
757
|
})
|
|
947
|
-
|
|
758
|
+
/**
|
|
759
|
+
* fetch the profile picture of a user/group
|
|
760
|
+
* type = "preview" for a low res picture
|
|
761
|
+
* type = "image" for the high res picture URL (adds query="url")
|
|
762
|
+
* type = "avatar" for the avatar variant (no query attr, confirmed from interop logs)
|
|
763
|
+
*/
|
|
948
764
|
const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
const picAttrs = { type, query: 'url' }
|
|
765
|
+
const picAttrs = type === 'image' ? { type, query: 'url' } : { type }
|
|
952
766
|
const baseContent = [{ tag: 'picture', attrs: picAttrs }]
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
767
|
+
// WA Web only includes tctoken for user JIDs (not groups/newsletters)
|
|
768
|
+
// and never for own profile pic (Chat model for self has no tcToken).
|
|
769
|
+
// Including tctoken for own JID causes the server to never respond.
|
|
956
770
|
const normalizedJid = (0, WABinary_1.jidNormalizedUser)(jid)
|
|
957
771
|
const isUserJid = (0, WABinary_1.isPnUser)(normalizedJid) || (0, WABinary_1.isLidUser)(normalizedJid)
|
|
958
772
|
const me = authState.creds.me
|
|
@@ -1007,7 +821,13 @@ const makeChatsSocket = config => {
|
|
|
1007
821
|
const child = (0, WABinary_1.getBinaryNodeChild)(result, 'link_create')
|
|
1008
822
|
return child?.attrs?.token
|
|
1009
823
|
}
|
|
1010
|
-
|
|
824
|
+
/**
|
|
825
|
+
* Toggle the waiting room on an existing call link.
|
|
826
|
+
* Ported from WhatsApp Web's WASmaxVoipWaitingRoomToggleCallLinkRPC.
|
|
827
|
+
* @param {string} linkToken the call link token (from createCallLink)
|
|
828
|
+
* @param {boolean} enabled
|
|
829
|
+
* @param {'audio' | 'video'} [media]
|
|
830
|
+
*/
|
|
1011
831
|
const toggleCallLinkWaitingRoom = async (linkToken, enabled, media = 'audio') => {
|
|
1012
832
|
const result = await query({
|
|
1013
833
|
tag: 'call',
|
|
@@ -1059,120 +879,25 @@ const makeChatsSocket = config => {
|
|
|
1059
879
|
})
|
|
1060
880
|
}
|
|
1061
881
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
write[jid] = {
|
|
1069
|
-
token: Buffer.isBuffer(privacyToken) ? privacyToken : Buffer.from(privacyToken),
|
|
1070
|
-
ts: String(privacyModeTs || '')
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
if (Object.keys(write).length) {
|
|
1074
|
-
await authState.keys.set({ 'privacy-token': write })
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
const executeUSyncQuery = async usyncQuery => {
|
|
1080
|
-
const result = await sock.executeUSyncQuery(usyncQuery)
|
|
1081
|
-
if (!result) return result
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
const privacyEntries = []
|
|
1085
|
-
const blockedContacts = []
|
|
1086
|
-
for (const entry of [...(result.list || []), ...(result.sideList || [])]) {
|
|
1087
|
-
if (entry.privacy?.token) {
|
|
1088
|
-
privacyEntries.push({
|
|
1089
|
-
jid: entry.id,
|
|
1090
|
-
privacyToken: entry.privacy.token,
|
|
1091
|
-
privacyModeTs: entry.privacy.modeTs
|
|
1092
|
-
})
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
if (entry.isBlockedByContact) {
|
|
1096
|
-
blockedContacts.push({ id: entry.id, isBlockedByContact: true })
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
if (privacyEntries.length) {
|
|
1100
|
-
storePrivacyTokens(privacyEntries).catch(err => logger.warn({ err }, 'failed to store privacy tokens from usync'))
|
|
1101
|
-
}
|
|
1102
|
-
if (blockedContacts.length) {
|
|
1103
|
-
ev.emit('contacts.update', blockedContacts)
|
|
1104
|
-
}
|
|
1105
|
-
return result
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
const presenceSubscribe = async (toJid, { presenceType, presenceName, groupJid } = {}) => {
|
|
1110
|
-
|
|
882
|
+
/**
|
|
883
|
+
* @param toJid the jid to subscribe to
|
|
884
|
+
* @param tcToken token for subscription, use if present
|
|
885
|
+
*/
|
|
886
|
+
const presenceSubscribe = async toJid => {
|
|
887
|
+
// Only include tctoken for user JIDs — groups/newsletters don't use tctokens
|
|
1111
888
|
const normalizedToJid = (0, WABinary_1.jidNormalizedUser)(toJid)
|
|
1112
889
|
const isUserJid = (0, WABinary_1.isPnUser)(normalizedToJid) || (0, WABinary_1.isLidUser)(normalizedToJid)
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
to: toJid,
|
|
1117
|
-
id: generateMessageTag(),
|
|
1118
|
-
type: 'subscribe'
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
const presenceContent = []
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
if (isUserJid) {
|
|
1126
|
-
try {
|
|
1127
|
-
const storageJid = await (0, tc_token_utils_1.resolveTcTokenJid)(normalizedToJid, getLIDForPN)
|
|
1128
|
-
const tcTokenData = await authState.keys.get('tctoken', [storageJid])
|
|
1129
|
-
const entry = tcTokenData?.[storageJid]
|
|
1130
|
-
const tcTokenBuffer = entry?.token
|
|
1131
|
-
if (tcTokenBuffer?.length && !(0, tc_token_utils_1.isTcTokenExpired)(entry?.timestamp)) {
|
|
1132
|
-
presenceAttrs.tc_token = tcTokenBuffer.toString('base64')
|
|
1133
|
-
}
|
|
1134
|
-
} catch (e) {
|
|
1135
|
-
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
try {
|
|
1142
|
-
const privTokenData = await authState.keys.get('privacy-token', [normalizedToJid])
|
|
1143
|
-
const privEntry = privTokenData?.[normalizedToJid]
|
|
1144
|
-
if (privEntry?.token?.length) {
|
|
1145
|
-
const privTokenAttrs = {}
|
|
1146
|
-
if (privEntry.ts) privTokenAttrs.t = privEntry.ts
|
|
1147
|
-
presenceContent.push({
|
|
1148
|
-
tag: 'privacy_token',
|
|
1149
|
-
attrs: privTokenAttrs,
|
|
1150
|
-
content: privEntry.token
|
|
1151
|
-
})
|
|
1152
|
-
}
|
|
1153
|
-
} catch (e) {
|
|
1154
|
-
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
if (presenceType) {
|
|
1160
|
-
presenceAttrs.presenceType = presenceType
|
|
1161
|
-
}
|
|
1162
|
-
if (presenceName) {
|
|
1163
|
-
presenceAttrs.presenceName = presenceName
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
if (groupJid) {
|
|
1168
|
-
presenceAttrs.context = 'group'
|
|
1169
|
-
presenceAttrs.group_jid = (0, WABinary_1.jidNormalizedUser)(groupJid)
|
|
1170
|
-
}
|
|
1171
|
-
|
|
890
|
+
const tcTokenContent = isUserJid
|
|
891
|
+
? await (0, tc_token_utils_1.buildTcTokenFromJid)({ authState, jid: normalizedToJid, getLIDForPN })
|
|
892
|
+
: undefined
|
|
1172
893
|
return sendNode({
|
|
1173
894
|
tag: 'presence',
|
|
1174
|
-
attrs:
|
|
1175
|
-
|
|
895
|
+
attrs: {
|
|
896
|
+
to: toJid,
|
|
897
|
+
id: generateMessageTag(),
|
|
898
|
+
type: 'subscribe'
|
|
899
|
+
},
|
|
900
|
+
content: tcTokenContent
|
|
1176
901
|
})
|
|
1177
902
|
}
|
|
1178
903
|
const handlePresenceUpdate = ({ tag, attrs, content }) => {
|
|
@@ -1271,9 +996,9 @@ const makeChatsSocket = config => {
|
|
|
1271
996
|
}
|
|
1272
997
|
}
|
|
1273
998
|
}
|
|
1274
|
-
|
|
999
|
+
/** sending non-abt props may fix QR scan fail if server expects */
|
|
1275
1000
|
const fetchProps = async () => {
|
|
1276
|
-
|
|
1001
|
+
//TODO: implement both protocol 1 and protocol 2 prop fetching, specially for abKey for WM
|
|
1277
1002
|
const resultNode = await query({
|
|
1278
1003
|
tag: 'iq',
|
|
1279
1004
|
attrs: {
|
|
@@ -1295,13 +1020,13 @@ const makeChatsSocket = config => {
|
|
|
1295
1020
|
let props = {}
|
|
1296
1021
|
if (propsNode) {
|
|
1297
1022
|
if (propsNode.attrs?.hash) {
|
|
1298
|
-
|
|
1023
|
+
// on some clients, the hash is returning as undefined
|
|
1299
1024
|
authState.creds.lastPropHash = propsNode?.attrs?.hash
|
|
1300
1025
|
ev.emit('creds.update', authState.creds)
|
|
1301
1026
|
}
|
|
1302
1027
|
props = (0, WABinary_1.reduceBinaryNodeToDictionary)(propsNode, 'prop')
|
|
1303
1028
|
}
|
|
1304
|
-
|
|
1029
|
+
// Extract protocol-relevant AB props (only the ones we need)
|
|
1305
1030
|
const privacyTokenProp = props['10518'] ?? props['privacy_token_sending_on_all_1_on_1_messages']
|
|
1306
1031
|
if (privacyTokenProp !== undefined) {
|
|
1307
1032
|
serverProps.privacyTokenOn1to1 = privacyTokenProp === 'true' || privacyTokenProp === '1'
|
|
@@ -1317,12 +1042,18 @@ const makeChatsSocket = config => {
|
|
|
1317
1042
|
logger.debug({ serverProps }, 'fetched props')
|
|
1318
1043
|
return props
|
|
1319
1044
|
}
|
|
1320
|
-
|
|
1045
|
+
/**
|
|
1046
|
+
* modify a chat -- mark unread, read etc.
|
|
1047
|
+
* lastMessages must be sorted in reverse chronologically
|
|
1048
|
+
* requires the last messages till the last message received; required for archive & unread
|
|
1049
|
+
*/
|
|
1321
1050
|
const chatModify = (mod, jid) => {
|
|
1322
1051
|
const patch = (0, Utils_1.chatModificationToAppPatch)(mod, jid)
|
|
1323
1052
|
return appPatch(patch)
|
|
1324
1053
|
}
|
|
1325
|
-
|
|
1054
|
+
/**
|
|
1055
|
+
* Enable/Disable link preview privacy, not related to baileys link preview generation
|
|
1056
|
+
*/
|
|
1326
1057
|
const updateDisableLinkPreviewsPrivacy = isPreviewsDisabled => {
|
|
1327
1058
|
return chatModify(
|
|
1328
1059
|
{
|
|
@@ -1331,7 +1062,9 @@ const makeChatsSocket = config => {
|
|
|
1331
1062
|
''
|
|
1332
1063
|
)
|
|
1333
1064
|
}
|
|
1334
|
-
|
|
1065
|
+
/**
|
|
1066
|
+
* Star or Unstar a message
|
|
1067
|
+
*/
|
|
1335
1068
|
const star = (jid, messages, star) => {
|
|
1336
1069
|
return chatModify(
|
|
1337
1070
|
{
|
|
@@ -1343,7 +1076,9 @@ const makeChatsSocket = config => {
|
|
|
1343
1076
|
jid
|
|
1344
1077
|
)
|
|
1345
1078
|
}
|
|
1346
|
-
|
|
1079
|
+
/**
|
|
1080
|
+
* Add or Edit Contact
|
|
1081
|
+
*/
|
|
1347
1082
|
const addOrEditContact = (jid, contact) => {
|
|
1348
1083
|
return chatModify(
|
|
1349
1084
|
{
|
|
@@ -1352,7 +1087,9 @@ const makeChatsSocket = config => {
|
|
|
1352
1087
|
jid
|
|
1353
1088
|
)
|
|
1354
1089
|
}
|
|
1355
|
-
|
|
1090
|
+
/**
|
|
1091
|
+
* Remove Contact
|
|
1092
|
+
*/
|
|
1356
1093
|
const removeContact = jid => {
|
|
1357
1094
|
return chatModify(
|
|
1358
1095
|
{
|
|
@@ -1361,7 +1098,9 @@ const makeChatsSocket = config => {
|
|
|
1361
1098
|
jid
|
|
1362
1099
|
)
|
|
1363
1100
|
}
|
|
1364
|
-
|
|
1101
|
+
/**
|
|
1102
|
+
* Adds label
|
|
1103
|
+
*/
|
|
1365
1104
|
const addLabel = (jid, labels) => {
|
|
1366
1105
|
return chatModify(
|
|
1367
1106
|
{
|
|
@@ -1372,7 +1111,9 @@ const makeChatsSocket = config => {
|
|
|
1372
1111
|
jid
|
|
1373
1112
|
)
|
|
1374
1113
|
}
|
|
1375
|
-
|
|
1114
|
+
/**
|
|
1115
|
+
* Adds label for the chats
|
|
1116
|
+
*/
|
|
1376
1117
|
const addChatLabel = (jid, labelId) => {
|
|
1377
1118
|
return chatModify(
|
|
1378
1119
|
{
|
|
@@ -1383,7 +1124,9 @@ const makeChatsSocket = config => {
|
|
|
1383
1124
|
jid
|
|
1384
1125
|
)
|
|
1385
1126
|
}
|
|
1386
|
-
|
|
1127
|
+
/**
|
|
1128
|
+
* Removes label for the chat
|
|
1129
|
+
*/
|
|
1387
1130
|
const removeChatLabel = (jid, labelId) => {
|
|
1388
1131
|
return chatModify(
|
|
1389
1132
|
{
|
|
@@ -1394,7 +1137,9 @@ const makeChatsSocket = config => {
|
|
|
1394
1137
|
jid
|
|
1395
1138
|
)
|
|
1396
1139
|
}
|
|
1397
|
-
|
|
1140
|
+
/**
|
|
1141
|
+
* Adds label for the message
|
|
1142
|
+
*/
|
|
1398
1143
|
const addMessageLabel = (jid, messageId, labelId) => {
|
|
1399
1144
|
return chatModify(
|
|
1400
1145
|
{
|
|
@@ -1406,7 +1151,9 @@ const makeChatsSocket = config => {
|
|
|
1406
1151
|
jid
|
|
1407
1152
|
)
|
|
1408
1153
|
}
|
|
1409
|
-
|
|
1154
|
+
/**
|
|
1155
|
+
* Removes label for the message
|
|
1156
|
+
*/
|
|
1410
1157
|
const removeMessageLabel = (jid, messageId, labelId) => {
|
|
1411
1158
|
return chatModify(
|
|
1412
1159
|
{
|
|
@@ -1418,7 +1165,9 @@ const makeChatsSocket = config => {
|
|
|
1418
1165
|
jid
|
|
1419
1166
|
)
|
|
1420
1167
|
}
|
|
1421
|
-
|
|
1168
|
+
/**
|
|
1169
|
+
* Add or Edit Quick Reply
|
|
1170
|
+
*/
|
|
1422
1171
|
const addOrEditQuickReply = quickReply => {
|
|
1423
1172
|
return chatModify(
|
|
1424
1173
|
{
|
|
@@ -1427,7 +1176,9 @@ const makeChatsSocket = config => {
|
|
|
1427
1176
|
''
|
|
1428
1177
|
)
|
|
1429
1178
|
}
|
|
1430
|
-
|
|
1179
|
+
/**
|
|
1180
|
+
* Remove Quick Reply
|
|
1181
|
+
*/
|
|
1431
1182
|
const removeQuickReply = timestamp => {
|
|
1432
1183
|
return chatModify(
|
|
1433
1184
|
{
|
|
@@ -1436,49 +1187,34 @@ const makeChatsSocket = config => {
|
|
|
1436
1187
|
''
|
|
1437
1188
|
)
|
|
1438
1189
|
}
|
|
1439
|
-
|
|
1190
|
+
/**
|
|
1191
|
+
* Rename an AI chat thread
|
|
1192
|
+
*/
|
|
1440
1193
|
const renameAIThread = (jid, title) => {
|
|
1441
1194
|
return chatModify({ aiThreadRename: { title } }, jid)
|
|
1442
1195
|
}
|
|
1443
|
-
|
|
1196
|
+
/**
|
|
1197
|
+
* Pin or unpin a message in a thread/AI chat
|
|
1198
|
+
*/
|
|
1444
1199
|
const pinThreadMessage = (jid, messageId, pinned = true) => {
|
|
1445
1200
|
return chatModify({ threadPin: { pinned, messageId } }, jid)
|
|
1446
1201
|
}
|
|
1447
|
-
|
|
1202
|
+
/**
|
|
1203
|
+
* Toggle AI private processing (end-to-end encrypted AI processing)
|
|
1204
|
+
*/
|
|
1448
1205
|
const updatePrivateProcessingSetting = enabled => {
|
|
1449
1206
|
return chatModify({ privateProcessingSetting: enabled ? 'enabled' : 'disabled' }, '')
|
|
1450
1207
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
const replyModeEnum =
|
|
1456
|
-
require('../../WAProto/index.js').proto.SyncActionValue.MaibaAIFeaturesControlAction.MaibaAIReplyMode
|
|
1457
|
-
const statusMap = {
|
|
1458
|
-
enabled: statusEnum.ENABLED,
|
|
1459
|
-
enabled_has_learning: statusEnum.ENABLED_HAS_LEARNING,
|
|
1460
|
-
disabled: statusEnum.DISABLED
|
|
1461
|
-
}
|
|
1462
|
-
const replyModeMap = {
|
|
1463
|
-
muted: replyModeEnum.MUTED,
|
|
1464
|
-
ai_agent: replyModeEnum.AI_AGENT,
|
|
1465
|
-
suggestions: replyModeEnum.SUGGESTIONS
|
|
1466
|
-
}
|
|
1467
|
-
return chatModify(
|
|
1468
|
-
{
|
|
1469
|
-
maibaAIFeatures: {
|
|
1470
|
-
status: statusMap[status] ?? statusEnum.ENABLED,
|
|
1471
|
-
replyMode: replyModeMap[replyMode] ?? replyModeEnum.SUGGESTIONS
|
|
1472
|
-
}
|
|
1473
|
-
},
|
|
1474
|
-
''
|
|
1475
|
-
)
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1208
|
+
/**
|
|
1209
|
+
* Update bio/about privacy (who can see your About text)
|
|
1210
|
+
* @param value 'all' | 'contacts' | 'contact_blacklist' | 'none'
|
|
1211
|
+
*/
|
|
1478
1212
|
const updateBioPrivacy = async value => {
|
|
1479
1213
|
await privacyQuery('about', value)
|
|
1480
1214
|
}
|
|
1481
|
-
|
|
1215
|
+
/**
|
|
1216
|
+
* Block a bot JID
|
|
1217
|
+
*/
|
|
1482
1218
|
const blockBot = async botJid => {
|
|
1483
1219
|
await query({
|
|
1484
1220
|
tag: 'iq',
|
|
@@ -1495,63 +1231,71 @@ const makeChatsSocket = config => {
|
|
|
1495
1231
|
]
|
|
1496
1232
|
})
|
|
1497
1233
|
}
|
|
1498
|
-
|
|
1234
|
+
/**
|
|
1235
|
+
* Unblock a bot JID
|
|
1236
|
+
*/
|
|
1499
1237
|
const unblockBot = async botJid => {
|
|
1500
1238
|
await updateBlockStatus(botJid, 'unblock')
|
|
1501
1239
|
}
|
|
1502
|
-
|
|
1240
|
+
/**
|
|
1241
|
+
* Mute or unmute a contact's status updates
|
|
1242
|
+
*/
|
|
1503
1243
|
const muteContactStatus = (jid, muted = true) => {
|
|
1504
1244
|
return chatModify({ muteStatus: { muted } }, jid)
|
|
1505
1245
|
}
|
|
1506
|
-
|
|
1246
|
+
/**
|
|
1247
|
+
* Add or remove a contact from favorites
|
|
1248
|
+
*/
|
|
1507
1249
|
const toggleFavorite = (jid, isFavorite = true) => {
|
|
1508
1250
|
return chatModify({ favorite: { isFavorite } }, jid)
|
|
1509
1251
|
}
|
|
1510
|
-
|
|
1252
|
+
/**
|
|
1253
|
+
* Reorder labels
|
|
1254
|
+
* @param sortedLabelIds ordered array of label IDs
|
|
1255
|
+
*/
|
|
1511
1256
|
const reorderLabels = sortedLabelIds => {
|
|
1512
1257
|
return chatModify({ reorderLabel: { sortedLabelIds } }, '')
|
|
1513
1258
|
}
|
|
1514
|
-
|
|
1259
|
+
/**
|
|
1260
|
+
* Delete an individual call log entry
|
|
1261
|
+
*/
|
|
1515
1262
|
const deleteCallLog = (callId, jid = '') => {
|
|
1516
1263
|
return chatModify({ deleteCallLog: { callId } }, jid)
|
|
1517
1264
|
}
|
|
1518
|
-
|
|
1265
|
+
/**
|
|
1266
|
+
* Create or update a note/draft for a chat
|
|
1267
|
+
*/
|
|
1519
1268
|
const setChatNote = (jid, note) => {
|
|
1520
1269
|
return chatModify({ noteEdit: { note } }, jid)
|
|
1521
1270
|
}
|
|
1522
|
-
|
|
1271
|
+
/**
|
|
1272
|
+
* Delete the note/draft for a chat
|
|
1273
|
+
*/
|
|
1523
1274
|
const deleteChatNote = jid => {
|
|
1524
1275
|
return chatModify({ noteEdit: { note: '', deleted: true } }, jid)
|
|
1525
1276
|
}
|
|
1526
|
-
|
|
1277
|
+
/**
|
|
1278
|
+
* Explicitly mark a chat as unread (shows unread dot even if read)
|
|
1279
|
+
*/
|
|
1527
1280
|
const markChatAsUnread = (jid, lastMessages) => {
|
|
1528
1281
|
return chatModify({ markAsUnread: true, lastMessages }, jid)
|
|
1529
1282
|
}
|
|
1530
|
-
|
|
1283
|
+
/**
|
|
1284
|
+
* Set per-chat ephemeral message duration
|
|
1285
|
+
* @param duration seconds (0 = off, 86400 = 1d, 604800 = 7d, 7776000 = 90d)
|
|
1286
|
+
*/
|
|
1531
1287
|
const setChatEphemeral = (jid, duration) => {
|
|
1532
1288
|
return chatModify({ setChatEphemeral: duration }, jid)
|
|
1533
1289
|
}
|
|
1534
|
-
|
|
1290
|
+
/**
|
|
1291
|
+
* Silence a chat (mute without timestamp = permanent, or provide until timestamp)
|
|
1292
|
+
*/
|
|
1535
1293
|
const silenceChat = (jid, silent = true, until = null) => {
|
|
1536
1294
|
return chatModify({ silenceChat: { silent, until } }, jid)
|
|
1537
1295
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
const pinChat = (jid, pinned = true) => {
|
|
1544
|
-
return chatModify({ pin: { pinned } }, jid)
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
const starMessages = (jid, messageIds, starred = true) => {
|
|
1548
|
-
return chatModify({ star: { messages: messageIds, star: starred } }, jid)
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
const setQuickReply = (text, shortcut) => {
|
|
1552
|
-
return chatModify({ quickReply: { text, shortcut } }, '')
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1296
|
+
/**
|
|
1297
|
+
* Fetch bot profiles for a list of JIDs using USyncBotProfileProtocol
|
|
1298
|
+
*/
|
|
1555
1299
|
const fetchBotProfiles = async jids => {
|
|
1556
1300
|
const { USyncQuery, USyncUser, USyncBotProfileProtocol } = require('../WAUSync')
|
|
1557
1301
|
const q = new USyncQuery()
|
|
@@ -1559,25 +1303,37 @@ const makeChatsSocket = config => {
|
|
|
1559
1303
|
for (const jid of jids) {
|
|
1560
1304
|
q.withUser(new USyncUser().withId(jid))
|
|
1561
1305
|
}
|
|
1562
|
-
const result = await executeUSyncQuery(q)
|
|
1306
|
+
const result = await sock.executeUSyncQuery(q)
|
|
1563
1307
|
return result?.list || []
|
|
1564
1308
|
}
|
|
1565
|
-
|
|
1309
|
+
/**
|
|
1310
|
+
* Lock or unlock a chat with an optional secret code
|
|
1311
|
+
*/
|
|
1566
1312
|
const updateChatLock = (jid, locked) => {
|
|
1567
1313
|
return chatModify({ chatLock: { locked } }, jid)
|
|
1568
1314
|
}
|
|
1569
|
-
|
|
1315
|
+
/**
|
|
1316
|
+
* Set a custom wallpaper for a chat
|
|
1317
|
+
* @param jid the chat JID
|
|
1318
|
+
* @param wallpaper wallpaper data or null to remove
|
|
1319
|
+
*/
|
|
1570
1320
|
const updateChatWallpaper = (jid, wallpaper) => {
|
|
1571
1321
|
if (!wallpaper) {
|
|
1572
1322
|
return chatModify({ wallpaper: { remove: true } }, jid)
|
|
1573
1323
|
}
|
|
1574
1324
|
return chatModify({ wallpaper }, jid)
|
|
1575
1325
|
}
|
|
1576
|
-
|
|
1326
|
+
/**
|
|
1327
|
+
* Set media visibility (auto-download) for a chat
|
|
1328
|
+
* @param jid the chat JID
|
|
1329
|
+
* @param visibility 'default' | 'on' | 'off'
|
|
1330
|
+
*/
|
|
1577
1331
|
const updateChatMediaVisibility = (jid, visibility) => {
|
|
1578
1332
|
return chatModify({ mediaVisibility: visibility }, jid)
|
|
1579
1333
|
}
|
|
1580
|
-
|
|
1334
|
+
/**
|
|
1335
|
+
* Fetch details for a specific bot by JID
|
|
1336
|
+
*/
|
|
1581
1337
|
const getBotProfile = async botJid => {
|
|
1582
1338
|
const resp = await query({
|
|
1583
1339
|
tag: 'iq',
|
|
@@ -1602,16 +1358,15 @@ const makeChatsSocket = config => {
|
|
|
1602
1358
|
description: botNode.attrs.description
|
|
1603
1359
|
}
|
|
1604
1360
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Fetch AB-test (abt) props from server.
|
|
1363
|
+
* Mirrors ABPropsProtocolHelper — protocol 1 or 2, optional hash/refresh_id/group.
|
|
1364
|
+
*/
|
|
1365
|
+
const fetchABProps = async (protocol = '2', hash = '', refreshId = null, group = null) => {
|
|
1366
|
+
const propAttrs = { protocol }
|
|
1367
|
+
if (hash) propAttrs.hash = hash
|
|
1368
|
+
if (refreshId != null) propAttrs.refresh_id = String(refreshId)
|
|
1369
|
+
if (group != null) propAttrs.group = String(group)
|
|
1615
1370
|
const result = await query({
|
|
1616
1371
|
tag: 'iq',
|
|
1617
1372
|
attrs: { to: WABinary_1.S_WHATSAPP_NET, xmlns: 'abt', type: 'get' },
|
|
@@ -1621,20 +1376,29 @@ const makeChatsSocket = config => {
|
|
|
1621
1376
|
if (!propsNode) return {}
|
|
1622
1377
|
return (0, WABinary_1.reduceBinaryNodeToDictionary)(propsNode, 'prop')
|
|
1623
1378
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1379
|
+
/**
|
|
1380
|
+
* Remove a companion (linked) device from the account.
|
|
1381
|
+
* Mirrors CompanionDeviceRemovalJob — xmlns="md", child tag "remove-companion-device".
|
|
1382
|
+
* reason: "user_initiated" | "server_initiated" | any WA-defined reason string.
|
|
1383
|
+
*/
|
|
1384
|
+
const removeCompanionDevice = async (keyIndex, reason = 'user_initiated') => {
|
|
1626
1385
|
await query({
|
|
1627
1386
|
tag: 'iq',
|
|
1628
1387
|
attrs: { to: WABinary_1.S_WHATSAPP_NET, xmlns: 'md', type: 'set' },
|
|
1629
1388
|
content: [
|
|
1630
1389
|
{
|
|
1631
1390
|
tag: 'remove-companion-device',
|
|
1632
|
-
attrs: {
|
|
1391
|
+
attrs: { platform: 'true', reason, id: String(keyIndex) }
|
|
1633
1392
|
}
|
|
1634
1393
|
]
|
|
1635
1394
|
})
|
|
1636
1395
|
}
|
|
1637
|
-
|
|
1396
|
+
/**
|
|
1397
|
+
* Push an updated key-index-list to the server (multi-device key announcement).
|
|
1398
|
+
* Mirrors KeyIndexListJob — xmlns="md", child tag "key-index-list" with a binary proto body.
|
|
1399
|
+
* ts: unix timestamp seconds (string or number).
|
|
1400
|
+
* content: Buffer — serialized proto KeyIndexList.
|
|
1401
|
+
*/
|
|
1638
1402
|
const updateKeyIndexList = async (ts, content) => {
|
|
1639
1403
|
await query({
|
|
1640
1404
|
tag: 'iq',
|
|
@@ -1648,39 +1412,11 @@ const makeChatsSocket = config => {
|
|
|
1648
1412
|
]
|
|
1649
1413
|
})
|
|
1650
1414
|
}
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
logger.debug('no ADV account / signed identity key, skipping key-index-list')
|
|
1657
|
-
return
|
|
1658
|
-
}
|
|
1659
|
-
const deviceIdentity = index_js_1.proto.ADVDeviceIdentity.decode(account.details)
|
|
1660
|
-
const keyIndex = deviceIdentity.keyIndex || 0
|
|
1661
|
-
const accountType = deviceIdentity.accountType ?? index_js_1.proto.ADVEncryptionType.E2EE
|
|
1662
|
-
const isHosted = accountType === index_js_1.proto.ADVEncryptionType.HOSTED
|
|
1663
|
-
const ts = Math.floor(Date.now() / 1000)
|
|
1664
|
-
const details = index_js_1.proto.ADVKeyIndexList.encode({
|
|
1665
|
-
rawId: deviceIdentity.rawId || 0,
|
|
1666
|
-
timestamp: ts,
|
|
1667
|
-
currentIndex: keyIndex,
|
|
1668
|
-
validIndexes: [keyIndex],
|
|
1669
|
-
accountType
|
|
1670
|
-
}).finish()
|
|
1671
|
-
const sigPrefix = isHosted
|
|
1672
|
-
? Defaults_1.WA_ADV_HOSTED_KEY_INDEX_LIST_SIG_PREFIX
|
|
1673
|
-
: Defaults_1.WA_ADV_KEY_INDEX_LIST_SIG_PREFIX
|
|
1674
|
-
const accountSignature = Utils_1.Curve.sign(signedIdentityKey.private, Buffer.concat([sigPrefix, details]))
|
|
1675
|
-
const signedKeyIndexList = { details, accountSignature }
|
|
1676
|
-
if (isHosted && account.accountSignatureKey?.length) {
|
|
1677
|
-
signedKeyIndexList.accountSignatureKey = account.accountSignatureKey
|
|
1678
|
-
}
|
|
1679
|
-
const content = index_js_1.proto.ADVSignedKeyIndexList.encode(signedKeyIndexList).finish()
|
|
1680
|
-
await updateKeyIndexList(ts, Buffer.from(content))
|
|
1681
|
-
logger.info({ ts, keyIndex }, 'sent key-index-list')
|
|
1682
|
-
}
|
|
1683
|
-
|
|
1415
|
+
/**
|
|
1416
|
+
* Request a media upload connection token from the server.
|
|
1417
|
+
* Mirrors MediaConnFetcher — xmlns="w:m", type="set", optional last_id.
|
|
1418
|
+
* Returns the raw media_conn node.
|
|
1419
|
+
*/
|
|
1684
1420
|
const fetchMediaConn = async (lastId = null) => {
|
|
1685
1421
|
const attrs = {}
|
|
1686
1422
|
if (lastId != null) attrs.last_id = String(lastId)
|
|
@@ -1691,7 +1427,10 @@ const makeChatsSocket = config => {
|
|
|
1691
1427
|
})
|
|
1692
1428
|
return (0, WABinary_1.getBinaryNodeChild)(result, 'media_conn') || null
|
|
1693
1429
|
}
|
|
1694
|
-
|
|
1430
|
+
/**
|
|
1431
|
+
* Delete a broadcast list by ID.
|
|
1432
|
+
* Mirrors BroadcastListDeleteJob — xmlns="w:b", wraps <delete><list id="..."/></delete>.
|
|
1433
|
+
*/
|
|
1695
1434
|
const deleteBroadcastList = async listId => {
|
|
1696
1435
|
await query({
|
|
1697
1436
|
tag: 'iq',
|
|
@@ -1705,7 +1444,11 @@ const makeChatsSocket = config => {
|
|
|
1705
1444
|
]
|
|
1706
1445
|
})
|
|
1707
1446
|
}
|
|
1708
|
-
|
|
1447
|
+
/**
|
|
1448
|
+
* Fetch a QR code from the server (e.g. for linked-device linking).
|
|
1449
|
+
* Mirrors QRCodeFetcher — xmlns="w:qr", type="get".
|
|
1450
|
+
* addressingMode: "lid" | undefined — set to "lid" for LID-addressed QR.
|
|
1451
|
+
*/
|
|
1709
1452
|
const fetchQRCode = async (code, addressingMode = null) => {
|
|
1710
1453
|
const attrs = { code }
|
|
1711
1454
|
if (addressingMode) attrs.addressing_mode = addressingMode
|
|
@@ -1716,13 +1459,15 @@ const makeChatsSocket = config => {
|
|
|
1716
1459
|
})
|
|
1717
1460
|
return (0, WABinary_1.getBinaryNodeChild)(result, 'qr') || null
|
|
1718
1461
|
}
|
|
1719
|
-
|
|
1462
|
+
/**
|
|
1463
|
+
* Confirm or deny a device-logout request from the server.
|
|
1464
|
+
* Mirrors AccountDefenceDeviceLogoutJob — xmlns="w:account_defence", smax_id=87.
|
|
1465
|
+
* approve: true to confirm the logout, false to deny.
|
|
1466
|
+
*/
|
|
1720
1467
|
const confirmDeviceLogout = async (id, approve = true) => {
|
|
1721
1468
|
await query({
|
|
1722
1469
|
tag: 'iq',
|
|
1723
1470
|
attrs: {
|
|
1724
|
-
|
|
1725
|
-
id: String(id),
|
|
1726
1471
|
to: WABinary_1.S_WHATSAPP_NET,
|
|
1727
1472
|
xmlns: 'w:account_defence',
|
|
1728
1473
|
type: 'set',
|
|
@@ -1736,78 +1481,14 @@ const makeChatsSocket = config => {
|
|
|
1736
1481
|
]
|
|
1737
1482
|
})
|
|
1738
1483
|
}
|
|
1739
|
-
|
|
1484
|
+
/**
|
|
1485
|
+
* queries need to be fired on connection open
|
|
1486
|
+
* help ensure parity with WA Web
|
|
1487
|
+
* */
|
|
1740
1488
|
const executeInitQueries = async () => {
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
const shouldInitInterop = authState.creds.interopEnabled !== false
|
|
1744
|
-
const [, , , abProps] = await Promise.all([
|
|
1745
|
-
fetchProps(),
|
|
1746
|
-
fetchBlocklist(),
|
|
1747
|
-
fetchPrivacySettings(),
|
|
1748
|
-
fetchABProps(),
|
|
1749
|
-
...(shouldInitInterop ? [initInterop()] : [])
|
|
1750
|
-
])
|
|
1751
|
-
const INTEROP_FLAGS = ['stella_interop_enabled', 'stella_ios_enabled']
|
|
1752
|
-
for (const flag of INTEROP_FLAGS) {
|
|
1753
|
-
if (flag in abProps) {
|
|
1754
|
-
const enabled = abProps[flag] === 'true' || abProps[flag] === '1'
|
|
1755
|
-
ev.emit('interop.feature-update', { feature: flag, enabled })
|
|
1756
|
-
}
|
|
1757
|
-
}
|
|
1758
|
-
|
|
1759
|
-
const abCredsUpdate = {}
|
|
1760
|
-
if ('stella_interop_enabled' in abProps) {
|
|
1761
|
-
abCredsUpdate.interopEnabled =
|
|
1762
|
-
abProps['stella_interop_enabled'] === 'true' || abProps['stella_interop_enabled'] === '1'
|
|
1763
|
-
}
|
|
1764
|
-
if ('stella_ios_enabled' in abProps) {
|
|
1765
|
-
abCredsUpdate.interopIosEnabled =
|
|
1766
|
-
abProps['stella_ios_enabled'] === 'true' || abProps['stella_ios_enabled'] === '1'
|
|
1767
|
-
}
|
|
1768
|
-
if ('md_privacy_v2' in abProps) {
|
|
1769
|
-
abCredsUpdate.mdPrivacyV2 = abProps['md_privacy_v2'] === 'true' || abProps['md_privacy_v2'] === '1'
|
|
1770
|
-
}
|
|
1771
|
-
|
|
1772
|
-
const MEDIA_AB_PROPS = [
|
|
1773
|
-
'hd_image_dual_upload',
|
|
1774
|
-
'hd_video_dual_upload',
|
|
1775
|
-
'hevc_video_dual_upload',
|
|
1776
|
-
'partial_pjpeg_enabled',
|
|
1777
|
-
'multi_scan_pjpeg',
|
|
1778
|
-
'media_poll'
|
|
1779
|
-
]
|
|
1780
|
-
const mediaAbProps = {}
|
|
1781
|
-
for (const prop of MEDIA_AB_PROPS) {
|
|
1782
|
-
if (prop in abProps) {
|
|
1783
|
-
mediaAbProps[prop] = abProps[prop] === 'true' || abProps[prop] === '1'
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
if (Object.keys(mediaAbProps).length) {
|
|
1787
|
-
abCredsUpdate.mediaAbProps = { ...(authState.creds.mediaAbProps || {}), ...mediaAbProps }
|
|
1788
|
-
}
|
|
1789
|
-
if (Object.keys(abCredsUpdate).length) {
|
|
1790
|
-
ev.emit('creds.update', abCredsUpdate)
|
|
1791
|
-
}
|
|
1489
|
+
await Promise.all([fetchProps(), fetchBlocklist(), fetchPrivacySettings(), initInterop()])
|
|
1792
1490
|
}
|
|
1793
1491
|
const upsertMessage = ev.createBufferedFunction(async (msg, type) => {
|
|
1794
|
-
|
|
1795
|
-
if (msg.newsletter && msg.newsletter_server_id && msg.key?.id) {
|
|
1796
|
-
_nlServerIdCache.set(msg.key.id, msg.newsletter_server_id)
|
|
1797
|
-
}
|
|
1798
|
-
|
|
1799
|
-
if (msg.message) {
|
|
1800
|
-
const ci = Object.values(msg.message).find(v => v?.contextInfo)?.contextInfo
|
|
1801
|
-
if (ci?.stanzaId && (0, WABinary_1.isJidNewsletter)(ci.remoteJid)) {
|
|
1802
|
-
const sid = _nlServerIdCache.get(ci.stanzaId)
|
|
1803
|
-
if (sid != null) msg.quotedNewsletterServerId = sid
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
if (msg.message?.secretEncryptedMessage || msg.message?.editedMessage?.message?.secretEncryptedMessage) {
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
await unwrapSecretEncryptedMessage(msg, { creds: authState.creds, getMessage, logger })
|
|
1810
|
-
}
|
|
1811
1492
|
ev.emit('messages.upsert', { messages: [msg], type })
|
|
1812
1493
|
if (!!msg.pushName) {
|
|
1813
1494
|
let jid = msg.key.fromMe ? authState.creds.me.id : msg.key.participant || msg.key.remoteJid
|
|
@@ -1815,7 +1496,7 @@ const makeChatsSocket = config => {
|
|
|
1815
1496
|
if (!msg.key.fromMe) {
|
|
1816
1497
|
ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName }])
|
|
1817
1498
|
}
|
|
1818
|
-
|
|
1499
|
+
// update our pushname too
|
|
1819
1500
|
if (msg.key.fromMe && msg.pushName && authState.creds.me?.name !== msg.pushName) {
|
|
1820
1501
|
ev.emit('creds.update', { me: { ...authState.creds.me, name: msg.pushName } })
|
|
1821
1502
|
}
|
|
@@ -1826,7 +1507,7 @@ const makeChatsSocket = config => {
|
|
|
1826
1507
|
: false
|
|
1827
1508
|
if (historyMsg && shouldProcessHistoryMsg) {
|
|
1828
1509
|
const syncType = historyMsg.syncType
|
|
1829
|
-
|
|
1510
|
+
// INITIAL_BOOTSTRAP — fire immediately, no progress check
|
|
1830
1511
|
if (
|
|
1831
1512
|
syncType === index_js_1.proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP &&
|
|
1832
1513
|
!historySyncStatus.initialBootstrapComplete
|
|
@@ -1838,7 +1519,7 @@ const makeChatsSocket = config => {
|
|
|
1838
1519
|
explicit: true
|
|
1839
1520
|
})
|
|
1840
1521
|
}
|
|
1841
|
-
|
|
1522
|
+
// RECENT with progress === 100 — explicit completion
|
|
1842
1523
|
if (
|
|
1843
1524
|
syncType === index_js_1.proto.HistorySync.HistorySyncType.RECENT &&
|
|
1844
1525
|
historyMsg.progress === 100 &&
|
|
@@ -1853,7 +1534,7 @@ const makeChatsSocket = config => {
|
|
|
1853
1534
|
explicit: true
|
|
1854
1535
|
})
|
|
1855
1536
|
}
|
|
1856
|
-
|
|
1537
|
+
// Reset 120s paused timeout on any RECENT chunk
|
|
1857
1538
|
if (syncType === index_js_1.proto.HistorySync.HistorySyncType.RECENT && !historySyncStatus.recentSyncComplete) {
|
|
1858
1539
|
clearTimeout(historySyncPausedTimeout)
|
|
1859
1540
|
historySyncPausedTimeout = setTimeout(() => {
|
|
@@ -1869,7 +1550,7 @@ const makeChatsSocket = config => {
|
|
|
1869
1550
|
}, Defaults_1.HISTORY_SYNC_PAUSED_TIMEOUT_MS)
|
|
1870
1551
|
}
|
|
1871
1552
|
}
|
|
1872
|
-
|
|
1553
|
+
// State machine: decide on sync and flush
|
|
1873
1554
|
if (historyMsg && syncState === State_1.SyncState.AwaitingInitialSync) {
|
|
1874
1555
|
if (awaitingSyncTimeout) {
|
|
1875
1556
|
clearTimeout(awaitingSyncTimeout)
|
|
@@ -1878,7 +1559,7 @@ const makeChatsSocket = config => {
|
|
|
1878
1559
|
if (shouldProcessHistoryMsg) {
|
|
1879
1560
|
syncState = State_1.SyncState.Syncing
|
|
1880
1561
|
logger.info('Transitioned to Syncing state')
|
|
1881
|
-
|
|
1562
|
+
// Let doAppStateSync handle the final flush after it's done
|
|
1882
1563
|
} else {
|
|
1883
1564
|
syncState = State_1.SyncState.Online
|
|
1884
1565
|
logger.info('History sync skipped, transitioning to Online state and flushing buffer')
|
|
@@ -1887,11 +1568,11 @@ const makeChatsSocket = config => {
|
|
|
1887
1568
|
}
|
|
1888
1569
|
const doAppStateSync = async () => {
|
|
1889
1570
|
if (syncState === State_1.SyncState.Syncing) {
|
|
1890
|
-
|
|
1571
|
+
// All collections will be synced, so clear any blocked ones
|
|
1891
1572
|
blockedCollections.clear()
|
|
1892
1573
|
logger.info('Doing app state sync')
|
|
1893
1574
|
await resyncAppState(Types_1.ALL_WA_PATCH_NAMES, true)
|
|
1894
|
-
|
|
1575
|
+
// Sync is complete, go online and flush everything
|
|
1895
1576
|
syncState = State_1.SyncState.Online
|
|
1896
1577
|
logger.info('App state sync complete, transitioning to Online state and flushing buffer')
|
|
1897
1578
|
ev.flush()
|
|
@@ -1917,7 +1598,7 @@ const makeChatsSocket = config => {
|
|
|
1917
1598
|
getMessage
|
|
1918
1599
|
})
|
|
1919
1600
|
])
|
|
1920
|
-
|
|
1601
|
+
// If the app state key arrives and we are waiting to sync, trigger the sync now.
|
|
1921
1602
|
if (msg.message?.protocolMessage?.appStateSyncKeyShare && syncState === State_1.SyncState.Syncing) {
|
|
1922
1603
|
logger.info('App state sync key arrived, triggering app state sync')
|
|
1923
1604
|
await doAppStateSync()
|
|
@@ -1925,20 +1606,6 @@ const makeChatsSocket = config => {
|
|
|
1925
1606
|
})
|
|
1926
1607
|
ws.on('CB:presence', handlePresenceUpdate)
|
|
1927
1608
|
ws.on('CB:chatstate', handlePresenceUpdate)
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
ws.on('CB:iq,xmlns:w:account_defence', async node => {
|
|
1932
|
-
const deviceLogout = (0, WABinary_1.getBinaryNodeChild)(node, 'device_logout')
|
|
1933
|
-
if (!deviceLogout) return
|
|
1934
|
-
const id = node.attrs.id
|
|
1935
|
-
logger.info({ id }, 'received account_defence device_logout challenge, approving')
|
|
1936
|
-
try {
|
|
1937
|
-
await confirmDeviceLogout(id, true)
|
|
1938
|
-
} catch (error) {
|
|
1939
|
-
onUnexpectedError(error, 'account_defence device_logout approve')
|
|
1940
|
-
}
|
|
1941
|
-
})
|
|
1942
1609
|
ws.on('CB:ib,,dirty', async node => {
|
|
1943
1610
|
const { attrs } = (0, WABinary_1.getBinaryNodeChild)(node, 'dirty')
|
|
1944
1611
|
const type = attrs.type
|
|
@@ -1954,7 +1621,7 @@ const makeChatsSocket = config => {
|
|
|
1954
1621
|
}
|
|
1955
1622
|
break
|
|
1956
1623
|
case 'groups':
|
|
1957
|
-
|
|
1624
|
+
// handled in groups.ts
|
|
1958
1625
|
break
|
|
1959
1626
|
default:
|
|
1960
1627
|
logger.info({ node }, 'received unknown sync')
|
|
@@ -1974,9 +1641,6 @@ const makeChatsSocket = config => {
|
|
|
1974
1641
|
sendPresenceUpdate(markOnlineOnConnect ? 'available' : 'unavailable').catch(error =>
|
|
1975
1642
|
onUnexpectedError(error, 'presence update requests')
|
|
1976
1643
|
)
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
sendKeyIndexList().catch(error => onUnexpectedError(error, 'send key-index-list'))
|
|
1980
1644
|
}
|
|
1981
1645
|
if (!receivedPendingNotifications || syncState !== State_1.SyncState.Connecting) {
|
|
1982
1646
|
return
|
|
@@ -1999,9 +1663,9 @@ const makeChatsSocket = config => {
|
|
|
1999
1663
|
setTimeout(() => ev.flush(), 0)
|
|
2000
1664
|
return
|
|
2001
1665
|
}
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
1666
|
+
// On reconnection (accountSyncCounter > 0), the server does not push
|
|
1667
|
+
// history sync notifications — the device already has its data.
|
|
1668
|
+
// Skip the 20s wait and go online immediately.
|
|
2005
1669
|
if (authState.creds.accountSyncCounter > 0) {
|
|
2006
1670
|
logger.info('Reconnection with existing sync data, skipping history sync wait. Transitioning to Online.')
|
|
2007
1671
|
syncState = State_1.SyncState.Online
|
|
@@ -2017,18 +1681,18 @@ const makeChatsSocket = config => {
|
|
|
2017
1681
|
logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer')
|
|
2018
1682
|
syncState = State_1.SyncState.Online
|
|
2019
1683
|
ev.flush()
|
|
2020
|
-
|
|
1684
|
+
// Increment so subsequent reconnections skip the 20s wait.
|
|
2021
1685
|
const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1
|
|
2022
1686
|
ev.emit('creds.update', { accountSyncCounter })
|
|
2023
1687
|
}
|
|
2024
1688
|
}, 20000)
|
|
2025
1689
|
})
|
|
2026
|
-
|
|
1690
|
+
// When an app state sync key arrives and there are collections blocked on a missing key, re-sync them.
|
|
2027
1691
|
ev.on('creds.update', ({ myAppStateKeyId }) => {
|
|
2028
1692
|
if (!myAppStateKeyId || blockedCollections.size === 0) {
|
|
2029
1693
|
return
|
|
2030
1694
|
}
|
|
2031
|
-
|
|
1695
|
+
// If we're in the middle of a full sync, doAppStateSync handles all collections
|
|
2032
1696
|
if (syncState === State_1.SyncState.Syncing) {
|
|
2033
1697
|
blockedCollections.clear()
|
|
2034
1698
|
return
|
|
@@ -2054,12 +1718,9 @@ const makeChatsSocket = config => {
|
|
|
2054
1718
|
getChatBlockingStatus,
|
|
2055
1719
|
updateChatBlockingStatus,
|
|
2056
1720
|
getUserDisclosures,
|
|
2057
|
-
acceptTosNotice,
|
|
2058
|
-
reportSpam,
|
|
2059
1721
|
getOptOutList,
|
|
2060
1722
|
getPushConfig,
|
|
2061
1723
|
setPushConfig,
|
|
2062
|
-
signPrivateCredential,
|
|
2063
1724
|
messageMutex,
|
|
2064
1725
|
receiptMutex,
|
|
2065
1726
|
appStatePatchMutex,
|
|
@@ -2108,7 +1769,6 @@ const makeChatsSocket = config => {
|
|
|
2108
1769
|
renameAIThread,
|
|
2109
1770
|
pinThreadMessage,
|
|
2110
1771
|
updatePrivateProcessingSetting,
|
|
2111
|
-
updateAIFeatures,
|
|
2112
1772
|
updateBioPrivacy,
|
|
2113
1773
|
blockBot,
|
|
2114
1774
|
unblockBot,
|
|
@@ -2122,10 +1782,6 @@ const makeChatsSocket = config => {
|
|
|
2122
1782
|
markChatAsUnread,
|
|
2123
1783
|
setChatEphemeral,
|
|
2124
1784
|
silenceChat,
|
|
2125
|
-
clearChat,
|
|
2126
|
-
pinChat,
|
|
2127
|
-
starMessages,
|
|
2128
|
-
setQuickReply,
|
|
2129
1785
|
fetchBotProfiles,
|
|
2130
1786
|
updateChatLock,
|
|
2131
1787
|
updateChatWallpaper,
|
|
@@ -2154,12 +1810,7 @@ const makeChatsSocket = config => {
|
|
|
2154
1810
|
fetchMediaConn,
|
|
2155
1811
|
deleteBroadcastList,
|
|
2156
1812
|
fetchQRCode,
|
|
2157
|
-
confirmDeviceLogout
|
|
2158
|
-
updateKeyIndexList,
|
|
2159
|
-
sendKeyIndexList,
|
|
2160
|
-
storePrivacyTokens,
|
|
2161
|
-
executeUSyncQuery,
|
|
2162
|
-
newsletterServerIdCache: _nlServerIdCache
|
|
1813
|
+
confirmDeviceLogout
|
|
2163
1814
|
}
|
|
2164
1815
|
}
|
|
2165
1816
|
exports.makeChatsSocket = makeChatsSocket
|