@alannxd/baileys 6.1.7 → 6.2.8
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 +440 -203
- package/lib/Defaults/index.js +2 -2
- package/lib/Socket/Client/websocket.js +35 -5
- package/lib/Socket/chats.js +0 -5
- package/lib/Socket/index.js +1 -9
- package/lib/Socket/luxu.js +4 -5
- package/lib/Socket/messages-recv.js +1 -1
- package/lib/Socket/messages-send.js +56 -114
- package/lib/Socket/mex.js +38 -51
- package/lib/Socket/newsletter.js +276 -745
- package/lib/Socket/socket.js +27 -161
- package/lib/Socket/username.js +204 -206
- package/lib/Store/make-in-memory-store.js +1 -47
- package/lib/Types/Mex.js +2 -76
- package/lib/Utils/browser-utils.js +1 -0
- package/lib/Utils/generics.js +2 -2
- package/lib/Utils/index.js +0 -1
- package/lib/Utils/messages-media.js +0 -82
- package/lib/Utils/messages.js +2 -136
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +50 -52
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +52 -55
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +25 -28
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +36 -37
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +23 -25
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
- package/lib/WAUSync/Protocols/index.js +6 -12
- package/lib/WAUSync/USyncQuery.js +96 -149
- package/lib/WAUSync/USyncUser.js +29 -54
- package/lib/WAUSync/index.js +4 -3
- package/lib/index.js +5 -2
- package/package.json +14 -13
- package/lib/Socket/graphql.js +0 -716
- package/lib/Socket/interop.js +0 -463
- package/lib/Socket/message-builder.js +0 -475
- package/lib/Socket/privacy.js +0 -318
- package/lib/Utils/sticker.js +0 -133
- package/lib/Utils/use-sqlite-auth-state.js +0 -162
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +0 -53
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +0 -43
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +0 -58
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -30
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +0 -32
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +0 -28
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +0 -38
package/lib/Socket/socket.js
CHANGED
|
@@ -23,10 +23,7 @@ export const makeSocket = (config) => {
|
|
|
23
23
|
const publicWAMBuffer = new BinaryInfo();
|
|
24
24
|
let serverTimeOffsetMs = 0;
|
|
25
25
|
const uqTagId = generateMdTagPrefix();
|
|
26
|
-
const generateMessageTag = () => `
|
|
27
|
-
if (browser[1].toLocaleLowerCase().includes('android')) {
|
|
28
|
-
logger.warn('⚠️ Using the Android browser is experimental and may lead to unexpected behavior. Use at your own risk.');
|
|
29
|
-
}
|
|
26
|
+
const generateMessageTag = () => `ALANXD-${epoch++}`;
|
|
30
27
|
if (printQRInTerminal) {
|
|
31
28
|
logger.warn({}, '⚠️ The printQRInTerminal option has been deprecated. You will no longer receive QR codes in the terminal automatically. Please listen to the connection.update event yourself and handle the QR your way. You can remove this message by removing this opttion. This message will be removed in a future version.');
|
|
32
29
|
}
|
|
@@ -219,60 +216,31 @@ export const makeSocket = (config) => {
|
|
|
219
216
|
const result = await query(iq);
|
|
220
217
|
return usyncQuery.parseUSyncQueryResult(result);
|
|
221
218
|
};
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
.withBotProfileProtocol()
|
|
229
|
-
.withUsernameProtocol()
|
|
230
|
-
.withBusinessProtocol()
|
|
231
|
-
.withPictureProtocol()
|
|
232
|
-
.withTextStatusProtocol()
|
|
233
|
-
.withSidelistProtocol()
|
|
234
|
-
.withFeatureProtocol();
|
|
235
|
-
const onWhatsApp = async (...pn) => {
|
|
236
|
-
const usyncQuery = buildAllProtocolsQuery();
|
|
237
|
-
for (const jid of pn) {
|
|
219
|
+
const onWhatsApp = async (...phoneNumber) => {
|
|
220
|
+
let usyncQuery = new USyncQuery()
|
|
221
|
+
.withContactProtocol()
|
|
222
|
+
.withLIDProtocol();
|
|
223
|
+
let contactEnabled = false;
|
|
224
|
+
for (const jid of phoneNumber) {
|
|
238
225
|
if (isLidUser(jid)) {
|
|
239
226
|
logger?.warn('LIDs are not supported with onWhatsApp');
|
|
240
227
|
continue;
|
|
241
228
|
}
|
|
242
|
-
|
|
243
|
-
|
|
229
|
+
else {
|
|
230
|
+
if (!contactEnabled) {
|
|
231
|
+
contactEnabled = true;
|
|
232
|
+
usyncQuery = usyncQuery.withContactProtocol();
|
|
233
|
+
}
|
|
234
|
+
const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`;
|
|
235
|
+
usyncQuery.withUser(new USyncUser().withPhone(phone));
|
|
236
|
+
}
|
|
244
237
|
}
|
|
245
238
|
if (usyncQuery.users.length === 0) {
|
|
246
239
|
return []; // return early without forcing an empty query
|
|
247
240
|
}
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
results = await executeUSyncQuery(usyncQuery);
|
|
251
|
-
}
|
|
252
|
-
catch (err) {
|
|
253
|
-
logger?.warn({ err }, 'onWhatsApp: full usync query failed, retrying with contact+lid protocols only');
|
|
254
|
-
const fallbackQuery = new USyncQuery().withContactProtocol().withLIDProtocol();
|
|
255
|
-
fallbackQuery.users = usyncQuery.users;
|
|
256
|
-
results = await executeUSyncQuery(fallbackQuery);
|
|
257
|
-
}
|
|
241
|
+
const results = await executeUSyncQuery(usyncQuery);
|
|
258
242
|
if (results) {
|
|
259
|
-
return results.list
|
|
260
|
-
.filter(a => !!a.contact)
|
|
261
|
-
.map(({ contact, id, lid, devices, status, disappearing_mode, bot, username, business, picture, text_status, sidelist, feature }) => ({
|
|
262
|
-
jid: id,
|
|
263
|
-
exists: contact,
|
|
264
|
-
lid: lid ?? null,
|
|
265
|
-
devices: devices ?? null,
|
|
266
|
-
status: status ?? null,
|
|
267
|
-
disappearingMode: disappearing_mode ?? null,
|
|
268
|
-
bot: bot ?? null,
|
|
269
|
-
username: username ?? null,
|
|
270
|
-
business: business ?? null,
|
|
271
|
-
picture: picture ?? null,
|
|
272
|
-
textStatus: text_status ?? null,
|
|
273
|
-
sidelist: sidelist ?? null,
|
|
274
|
-
feature: feature ?? null
|
|
275
|
-
}));
|
|
243
|
+
return results.list.filter(a => !!a.contact).map(({ contact, id, lid }) => ({ jid: id, lid, exists: contact }));
|
|
276
244
|
}
|
|
277
245
|
};
|
|
278
246
|
const pnFromLIDUSync = async (jids) => {
|
|
@@ -295,115 +263,14 @@ export const makeSocket = (config) => {
|
|
|
295
263
|
}
|
|
296
264
|
return [];
|
|
297
265
|
};
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
.withLIDProtocol()
|
|
307
|
-
for (const l of lids) {
|
|
308
|
-
const decoded = jidDecode(l)
|
|
309
|
-
if (!decoded) continue
|
|
310
|
-
usyncQuery.withUser(
|
|
311
|
-
new USyncUser()
|
|
312
|
-
.withId(jidEncode(decoded.user, 's.whatsapp.net'))
|
|
313
|
-
.withLid(l)
|
|
314
|
-
)
|
|
315
|
-
}
|
|
316
|
-
const result = await executeUSyncQuery(usyncQuery)
|
|
317
|
-
return lids.map(l => {
|
|
318
|
-
const decoded = jidDecode(l)
|
|
319
|
-
if (!decoded) return { lid: l, pn: null }
|
|
320
|
-
|
|
321
|
-
const match = result?.list?.find(entry => {
|
|
322
|
-
const entryDecoded = jidDecode(entry.id)
|
|
323
|
-
return entryDecoded?.user === decoded.user
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
if (!match?.contact) return { lid: l, pn: null }
|
|
327
|
-
|
|
328
|
-
const pn = jidEncode(jidDecode(match.id)?.user, 's.whatsapp.net')
|
|
329
|
-
return { lid: l, pn: pn ?? null }
|
|
330
|
-
})
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* @param {string | string[]} s.whatsapp.net - @s.whatsapp.net JID or array of @s.whatsapp.net JID
|
|
334
|
-
* @returns {Promise<{ pn: string, lid: string | null }[]>}
|
|
335
|
-
*/
|
|
336
|
-
const toLID = async pn => {
|
|
337
|
-
const pns = Array.isArray(pn) ? pn : [pn]
|
|
338
|
-
const usyncQuery = new USyncQuery()
|
|
339
|
-
.withContactProtocol()
|
|
340
|
-
.withLIDProtocol()
|
|
341
|
-
for (const p of pns) {
|
|
342
|
-
const decoded = jidDecode(p)
|
|
343
|
-
if (!decoded) continue
|
|
344
|
-
usyncQuery.withUser(
|
|
345
|
-
new USyncUser().withId(jidEncode(decoded.user, 's.whatsapp.net'))
|
|
346
|
-
)
|
|
347
|
-
}
|
|
348
|
-
const result = await executeUSyncQuery(usyncQuery)
|
|
349
|
-
return pns.map(p => {
|
|
350
|
-
const decoded = jidDecode(p)
|
|
351
|
-
if (!decoded) return { pn: p, lid: null }
|
|
352
|
-
|
|
353
|
-
const match = result?.list?.find(entry => {
|
|
354
|
-
return jidDecode(entry.id)?.user === decoded.user
|
|
355
|
-
})
|
|
356
|
-
|
|
357
|
-
if (!match?.contact) return { pn: p, lid: null }
|
|
358
|
-
|
|
359
|
-
const lidVal = match?.lid ?? null
|
|
360
|
-
const lid = lidVal ? jidEncode(jidDecode(lidVal)?.user ?? lidVal, 'lid') : null
|
|
361
|
-
return { pn: p, lid }
|
|
362
|
-
})
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* @param {string, pin} username - username to fetch, pin - pin of username if da user enable it
|
|
366
|
-
* @returns {Promise<{ username: string, pn: string | null, lid: string | null }[]>}
|
|
367
|
-
*/
|
|
368
|
-
const fetchUsername = async (username, pin) => {
|
|
369
|
-
const usernames = Array.isArray(username) ? username : [username]
|
|
370
|
-
const usyncQuery = new USyncQuery()
|
|
371
|
-
.withContactProtocol()
|
|
372
|
-
.withLIDProtocol()
|
|
373
|
-
for (const u of usernames) {
|
|
374
|
-
const user = new USyncUser().withUsername(u)
|
|
375
|
-
if (pin) user.withUsernameKey(pin)
|
|
376
|
-
usyncQuery.withUser(user)
|
|
377
|
-
}
|
|
378
|
-
const result = await executeUSyncQuery(usyncQuery)
|
|
379
|
-
return usernames.map(u => {
|
|
380
|
-
const match = result?.list?.find(entry => entry?.username === u)
|
|
381
|
-
if (!match?.contact) return { username: u, pn: null, lid: null }
|
|
382
|
-
const lid = match.lid;
|
|
383
|
-
const pn = jidEncode(jidDecode(match.id)?.user, 's.whatsapp.net')
|
|
384
|
-
return { username: u, pn: pn ?? null, lid: lid ?? null }
|
|
385
|
-
})
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* @params {string} phone number - wazap phone number to check
|
|
389
|
-
* @returns {Prommise<{ banned: boolean, violation: number, details: any }>}
|
|
390
|
-
*/
|
|
391
|
-
const checkBan = async (number) => {
|
|
392
|
-
const normalizedNumber = number.startsWith('+') ? number.replace(/[^0-9]/g, '') : number;
|
|
393
|
-
let res = await fetch('https://xzc-corporation.biz.id/lrp?number=' + normalizedNumber, {
|
|
394
|
-
method: "GET",
|
|
395
|
-
headers: {
|
|
396
|
-
'Accept': 'application/json',
|
|
397
|
-
'neckhurt': 'hate4jew'
|
|
398
|
-
}
|
|
399
|
-
})
|
|
400
|
-
let data = res.json();
|
|
401
|
-
return {
|
|
402
|
-
author: "DsynC",
|
|
403
|
-
...data
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
|
|
266
|
+
const toPn = async (jid) => {
|
|
267
|
+
const results = await pnFromLIDUSync([jid]);
|
|
268
|
+
return results?.[0]?.pn ?? null;
|
|
269
|
+
}
|
|
270
|
+
const toLid = async (jid) => {
|
|
271
|
+
const results = await onWhatsApp(jid);
|
|
272
|
+
return results?.[0]?.lid ?? null;
|
|
273
|
+
}
|
|
407
274
|
const ev = makeEventBuffer(logger);
|
|
408
275
|
const { creds } = authState;
|
|
409
276
|
// add transaction capability
|
|
@@ -1097,9 +964,8 @@ export const makeSocket = (config) => {
|
|
|
1097
964
|
fetchAccountReachoutTimelock,
|
|
1098
965
|
fetchNewChatMessageCap,
|
|
1099
966
|
toPn,
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
checkBan
|
|
967
|
+
toLid,
|
|
968
|
+
pnFromLIDUSync
|
|
1103
969
|
};
|
|
1104
970
|
};
|
|
1105
971
|
/**
|
package/lib/Socket/username.js
CHANGED
|
@@ -1,236 +1,234 @@
|
|
|
1
1
|
import { executeWMexQuery } from './mex.js'
|
|
2
2
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js'
|
|
3
3
|
import { makeNewsletterSocket } from './newsletter.js'
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
/**
|
|
6
6
|
* w:mex query IDs for username operations.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* These numeric IDs are assigned by WhatsApp's Pando/MEX infrastructure.
|
|
9
|
+
* They can be obtained by capturing a real WA session that performs these
|
|
10
|
+
* operations and inspecting the query_id field in the <query> IQ node.
|
|
11
|
+
*
|
|
12
|
+
* Source: Java decompilation of WhatsApp 2.26.17.2 (C1568872p.java)
|
|
13
|
+
* Operations confirmed: UsernameCheck, UsernameSet, UsernameGet, UsernamePinSet
|
|
14
|
+
* Data path confirmed: xwa2_username_check (C164057Wg.java:81)
|
|
10
15
|
*/
|
|
11
|
-
const USERNAME_QUERY_IDS = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
export const USERNAME_QUERY_IDS = {
|
|
17
|
+
CHECK: '26124072630599520', // UsernameCheck
|
|
18
|
+
CHECK_MULTI: '27134626522840290', // UsernameCheckMulti
|
|
19
|
+
SET: '27108705368767936', // UsernameSet
|
|
20
|
+
GET: '32618050064506056', // UsernameGet
|
|
21
|
+
GET_RECOMMENDATIONS: '26077456248616956', // UsernameGetRecommendationsQuery
|
|
22
|
+
PIN_SET: '25529696019976770' // UsernamePinSet
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
/**
|
|
21
26
|
* Source enum values from EnumC141106Vn (UsernameCheck result)
|
|
22
27
|
* and EnumC141056Vi (rejection reasons) confirmed via C164057Wg.java
|
|
23
28
|
*/
|
|
24
|
-
const USERNAME_CHECK_RESULT = {
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
export const USERNAME_CHECK_RESULT = {
|
|
30
|
+
SUCCESS: 'SUCCESS',
|
|
31
|
+
INVALID: 'INVALID'
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
const USERNAME_SOURCE = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
export const USERNAME_SOURCE = {
|
|
35
|
+
FB: 'FB',
|
|
36
|
+
IG: 'IG',
|
|
37
|
+
USER_INPUT: 'USER_INPUT',
|
|
38
|
+
SUGGESTION: 'SUGGESTION'
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
export const makeUsernameSocket = config => {
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
const sock = makeNewsletterSocket(config)
|
|
43
|
+
const { query, generateMessageTag, executeUSyncQuery } = sock
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
const mexQuery = (variables, queryId, dataPath) =>
|
|
46
|
+
executeWMexQuery(variables, queryId, dataPath, query, generateMessageTag)
|
|
42
47
|
|
|
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
|
-
session_id,
|
|
80
|
-
suggestions: data?.suggestions?? [],
|
|
81
|
-
rejectionReasons: data?.rejection_reasons?? [],
|
|
82
|
-
suggestionsEligible: data?.suggestions_eligible?? true
|
|
83
|
-
}
|
|
84
|
-
}
|
|
48
|
+
/**
|
|
49
|
+
* Check whether a username is available.
|
|
50
|
+
*
|
|
51
|
+
* @param {string} username - The @username to check (without @)
|
|
52
|
+
* @param {boolean} includeSuggestions - Request alternative suggestions when taken
|
|
53
|
+
* @returns {object}
|
|
54
|
+
* On success: { available: true, username }
|
|
55
|
+
* On taken: { available: false, username, suggestions: string[], rejectionReasons: string[], suggestionsEligible: boolean }
|
|
56
|
+
* On rate-limit: throws Boom with statusCode 429
|
|
57
|
+
*
|
|
58
|
+
* Confirmed fields from C164057Wg.java:
|
|
59
|
+
* data.xwa2_username_check.result → 'SUCCESS' | 'INVALID'
|
|
60
|
+
* data.xwa2_username_check.suggestions
|
|
61
|
+
* data.xwa2_username_check.rejection_reasons
|
|
62
|
+
* data.xwa2_username_check.suggestions_eligible
|
|
63
|
+
*/
|
|
64
|
+
const checkUsername = async (username, includeSuggestions = true) => {
|
|
65
|
+
if (!USERNAME_QUERY_IDS.CHECK) {
|
|
66
|
+
throw new Error('Username CHECK query_id not configured — capture a live WA session to obtain it')
|
|
67
|
+
}
|
|
68
|
+
const data = await mexQuery(
|
|
69
|
+
{ username, include_suggestions: includeSuggestions },
|
|
70
|
+
USERNAME_QUERY_IDS.CHECK,
|
|
71
|
+
'xwa2_username_check'
|
|
72
|
+
)
|
|
73
|
+
if (data?.result === USERNAME_CHECK_RESULT.SUCCESS) {
|
|
74
|
+
return { available: true, username }
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
available: false,
|
|
78
|
+
username,
|
|
79
|
+
suggestions: data?.suggestions?? [],
|
|
80
|
+
rejectionReasons: data?.rejection_reasons?? [],
|
|
81
|
+
suggestionsEligible: data?.suggestions_eligible?? true
|
|
82
|
+
}
|
|
83
|
+
}
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const checkAndSetUsername = async (username) => {
|
|
114
|
-
const r = await checkUsername(username);
|
|
115
|
-
if (r.available) {
|
|
116
|
-
return await setUsername(username)
|
|
117
|
-
}
|
|
118
|
-
return r
|
|
119
|
-
}
|
|
85
|
+
/**
|
|
86
|
+
* Set your own username.
|
|
87
|
+
*
|
|
88
|
+
* @param {string} username - The username to set (without @)
|
|
89
|
+
* @param {object} options
|
|
90
|
+
* @param {string} [options.source] - 'USER_INPUT' | 'FB' | 'IG' | 'SUGGESTION'
|
|
91
|
+
* @param {string} [options.sessionId] - Optional session tracking ID
|
|
92
|
+
* @param {string} [options.pin] - Optional PIN for protected usernames
|
|
93
|
+
*
|
|
94
|
+
* Confirmed variables from C1568872p.java A00():
|
|
95
|
+
* username, reserved (bool), session_id, source, pin
|
|
96
|
+
*/
|
|
97
|
+
const setUsername = async (username, options = {}) => {
|
|
98
|
+
if (!USERNAME_QUERY_IDS.SET) {
|
|
99
|
+
throw new Error('Username SET query_id not configured — capture a live WA session to obtain it')
|
|
100
|
+
}
|
|
101
|
+
const { source = USERNAME_SOURCE.USER_INPUT, sessionId, pin } = options
|
|
102
|
+
const variables = {
|
|
103
|
+
username,
|
|
104
|
+
reserved: false,
|
|
105
|
+
source,
|
|
106
|
+
...(sessionId? { session_id: sessionId } : {}),
|
|
107
|
+
...(pin? { pin } : {})
|
|
108
|
+
}
|
|
109
|
+
return mexQuery(variables, USERNAME_QUERY_IDS.SET, 'xwa2_username_set')
|
|
110
|
+
}
|
|
120
111
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Delete (unset) your own username.
|
|
114
|
+
*
|
|
115
|
+
* Confirmed from C1568872p.java:
|
|
116
|
+
* str4 = str == null? "delete" : "set"
|
|
117
|
+
* → sending username=null triggers the delete path on the server.
|
|
118
|
+
*/
|
|
119
|
+
const deleteUsername = async () => {
|
|
120
|
+
if (!USERNAME_QUERY_IDS.SET) {
|
|
121
|
+
throw new Error('Username SET query_id not configured — capture a live WA session to obtain it')
|
|
122
|
+
}
|
|
123
|
+
return mexQuery({ username: null }, USERNAME_QUERY_IDS.SET, 'xwa2_username_delete')
|
|
124
|
+
}
|
|
131
125
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Get your own current username.
|
|
128
|
+
*
|
|
129
|
+
* Confirmed from C1568872p.java A02():
|
|
130
|
+
* AbstractC41851rT.A0L(AbstractC130045pa.A0T(), C1363664w.class, "UsernameGet", false)
|
|
131
|
+
*/
|
|
132
|
+
const getMyUsername = async () => {
|
|
133
|
+
if (!USERNAME_QUERY_IDS.GET) {
|
|
134
|
+
throw new Error('Username GET query_id not configured — capture a live WA session to obtain it')
|
|
135
|
+
}
|
|
136
|
+
const data = await mexQuery({}, USERNAME_QUERY_IDS.GET, 'xwa2_username_get')
|
|
137
|
+
return data?.username?? null
|
|
138
|
+
}
|
|
142
139
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Set or delete the PIN that protects your username.
|
|
142
|
+
*
|
|
143
|
+
* @param {string|null} pin - New PIN, or null to delete the PIN
|
|
144
|
+
*
|
|
145
|
+
* Confirmed from MexUsernamePinProtocolApi.java:
|
|
146
|
+
* operation "UsernamePinSet", variable "pin"
|
|
147
|
+
* pin=null triggers the "delete" path on the server.
|
|
148
|
+
*/
|
|
149
|
+
const setUsernamePin = async pin => {
|
|
150
|
+
if (!USERNAME_QUERY_IDS.PIN_SET) {
|
|
151
|
+
throw new Error('Username PIN_SET query_id not configured — capture a live WA session to obtain it')
|
|
152
|
+
}
|
|
153
|
+
return mexQuery({ pin }, USERNAME_QUERY_IDS.PIN_SET, 'xwa2_username_pin_set')
|
|
154
|
+
}
|
|
157
155
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Look up a contact by their @username via USync.
|
|
158
|
+
*
|
|
159
|
+
* Confirmed via USyncContactProtocol.getUserElement():
|
|
160
|
+
* { tag: 'contact', attrs: { username, pin? } }
|
|
161
|
+
*
|
|
162
|
+
* @param {string} username - The username to look up (without @)
|
|
163
|
+
* @param {string} [pin] - Optional PIN if the username is PIN-protected
|
|
164
|
+
* @returns {{ jid, lid?, contact: boolean }|null}
|
|
165
|
+
*/
|
|
166
|
+
const findUserByUsername = async (username, pin) => {
|
|
167
|
+
const usyncQuery = new USyncQuery().withContactProtocol()
|
|
168
|
+
const user = new USyncUser().withUsername(username)
|
|
169
|
+
if (pin) user.withUsernameKey(pin)
|
|
170
|
+
usyncQuery.withUser(user)
|
|
171
|
+
const result = await executeUSyncQuery(usyncQuery)
|
|
172
|
+
if (!result?.list?.length) return null
|
|
173
|
+
const entry = result.list[0]
|
|
174
|
+
return {
|
|
175
|
+
jid: entry.id,
|
|
176
|
+
contact: entry.contact?? false
|
|
177
|
+
}
|
|
178
|
+
}
|
|
181
179
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Fetch the username of one or more contacts by their JID.
|
|
182
|
+
* Uses USync with the username protocol.
|
|
183
|
+
*
|
|
184
|
+
* @param {...string} jids - One or more JIDs
|
|
185
|
+
* @returns {Array<{ id, username: string|null }>}
|
|
186
|
+
*/
|
|
187
|
+
const fetchContactUsernames = async (...jids) => {
|
|
188
|
+
const usyncQuery = new USyncQuery().withUsernameProtocol()
|
|
189
|
+
for (const jid of jids) {
|
|
190
|
+
usyncQuery.withUser(new USyncUser().withId(jid))
|
|
191
|
+
}
|
|
192
|
+
const result = await executeUSyncQuery(usyncQuery)
|
|
193
|
+
return result?.list?? []
|
|
194
|
+
}
|
|
197
195
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Check multiple usernames for availability at once.
|
|
198
|
+
* @param {string[]} usernames - Array of usernames (without @)
|
|
199
|
+
*/
|
|
200
|
+
const checkUsernameMulti = async usernames => {
|
|
201
|
+
const data = await mexQuery(
|
|
202
|
+
{ usernames },
|
|
203
|
+
USERNAME_QUERY_IDS.CHECK_MULTI,
|
|
204
|
+
'xwa2_username_check_multi'
|
|
205
|
+
)
|
|
206
|
+
return data
|
|
207
|
+
}
|
|
210
208
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Fetch username recommendations for the current user.
|
|
211
|
+
* @param {string} [source] - Source hint: 'FB' | 'IG' | 'USER_INPUT'
|
|
212
|
+
*/
|
|
213
|
+
const getUsernameRecommendations = async (source = null) => {
|
|
214
|
+
const variables = {}
|
|
215
|
+
if (source) variables.source = source
|
|
216
|
+
return mexQuery(variables, USERNAME_QUERY_IDS.GET_RECOMMENDATIONS, 'xwa2_username_get_recommendations')
|
|
217
|
+
}
|
|
220
218
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
219
|
+
return {
|
|
220
|
+
...sock,
|
|
221
|
+
checkUsername,
|
|
222
|
+
checkUsernameMulti,
|
|
223
|
+
setUsername,
|
|
224
|
+
deleteUsername,
|
|
225
|
+
getMyUsername,
|
|
226
|
+
getUsernameRecommendations,
|
|
227
|
+
setUsernamePin,
|
|
228
|
+
findUserByUsername,
|
|
229
|
+
fetchContactUsernames,
|
|
230
|
+
USERNAME_QUERY_IDS,
|
|
231
|
+
USERNAME_CHECK_RESULT,
|
|
232
|
+
USERNAME_SOURCE
|
|
233
|
+
}
|
|
236
234
|
}
|