whalibmob 5.12.9 → 5.12.10

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 CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  CONTACT ME ON TELEGRAM IF YOU WANT TO WORK WITH ME AND IF YOU HAVE PROBLEM WITH WHALIBMOB : @brtyu545
11
11
 
12
- If you want News about whalibmob enter in this telegram channel : https://t.me/+sHN4MDCyB7U5OWY0
12
+ If you want News about whalibmob enter this whalibmob channel: https://t.me/+sHN4MDCyB7U5OWY0
13
13
 
14
14
 
15
15
 
@@ -678,6 +678,11 @@ wa> /about Available 24/7 for support
678
678
  about updated
679
679
  ```
680
680
 
681
+ `about updated` now means the about was read back from the server and matches
682
+ what you typed. When the server accepts the stanza but still reports something
683
+ else, it says so instead — and if the about is stored but hidden, it names the
684
+ privacy setting that is hiding it.
685
+
681
686
  #### CLI Change Profile Picture
682
687
 
683
688
  Reads the image from disk, crops it square, scales it to 640×640 and uploads it
@@ -3402,6 +3407,9 @@ const results = await client.hasWhatsapp(['919634847671', '12345678901'])
3402
3407
  ```js
3403
3408
  const about = await client.queryAbout('919634847671@s.whatsapp.net')
3404
3409
  console.log(about)
3410
+
3411
+ // your own, asked the same way
3412
+ console.log(await client.queryOwnAbout())
3405
3413
  ```
3406
3414
 
3407
3415
  ### Fetch Profile Picture
@@ -3435,6 +3443,22 @@ client.changeName('My Bot')
3435
3443
 
3436
3444
  ```js
3437
3445
  await client.changeAbout('Available 24/7')
3446
+
3447
+ // what the server actually has now — the set IQ is answered before the new
3448
+ // text has to be visible anywhere, so this is the part worth reading
3449
+ const stored = await client.queryOwnAbout()
3450
+ ```
3451
+
3452
+ `changeAbout` throws when the server refuses the change or never answers; it
3453
+ used to hand back the reply unread, so a refusal looked exactly like a success.
3454
+ An about is limited to 139 characters — a longer one is dropped rather than
3455
+ refused, and that too is now a thrown error instead of silence.
3456
+
3457
+ An about the server stores and nobody can see is a privacy setting rather than a
3458
+ failed write. The category that governs who may read it is `status`:
3459
+
3460
+ ```js
3461
+ await client.changePrivacySetting('status', 'all')
3438
3462
  ```
3439
3463
 
3440
3464
  ### Change Profile Picture
package/cli.js CHANGED
@@ -1411,7 +1411,26 @@ async function handleLine(line) {
1411
1411
  const text = p.slice(1).join(' ');
1412
1412
  if (!text) { fail('usage: /about <text>'); break; }
1413
1413
  await _client.changeAbout(text);
1414
- out('about updated');
1414
+
1415
+ // The server answers the set IQ before the new about has to be visible
1416
+ // anywhere, so "result" is not the same as "changed" — this used to
1417
+ // report success on the strength of that empty reply alone. Read it
1418
+ // back and say what is actually stored.
1419
+ let stored = null;
1420
+ try { stored = await _client.queryOwnAbout(); } catch (_) {}
1421
+ if (stored === text) out('about updated');
1422
+ else if (stored) out('sent, but the server still reports: ' + stored);
1423
+ else out('sent, and the server accepted it — it reports no about for this number yet');
1424
+
1425
+ // An about that is stored and still nowhere to be seen is a privacy
1426
+ // setting rather than a failed write: on the wire the category that
1427
+ // governs who may read it is "status".
1428
+ try {
1429
+ const priv = await _client.queryPrivacySettings({ force: true });
1430
+ if (priv && priv.status && priv.status !== 'all') {
1431
+ out(' about visibility is "' + priv.status + '" — /privacy status all shows it to everyone');
1432
+ }
1433
+ } catch (_) {}
1415
1434
  break;
1416
1435
  }
1417
1436
 
package/lib/Client.js CHANGED
@@ -59,6 +59,10 @@ const INVITE_LINK_PREFIX = 'https://chat.whatsapp.com/';
59
59
  // with a different query.
60
60
  const MEX_QUERY_REACHOUT_TIMELOCK = '23983697327930364';
61
61
 
62
+ // How long an about is allowed to be. The apps stop you at this length; the
63
+ // server takes a longer one, answers <iq type="result"/> and keeps the old text.
64
+ const ABOUT_MAX_LENGTH = 139;
65
+
62
66
  // The names privacy settings actually go by on the wire, and the friendly
63
67
  // aliases this library has always accepted for them. The wire names are the
64
68
  // right-hand column.
@@ -4446,17 +4450,62 @@ class WhalibmobClient extends EventEmitter {
4446
4450
  }
4447
4451
 
4448
4452
  // Change bio/about text
4453
+ //
4454
+ // The <status> child is byte-for-byte what Baileys and whatsmeow send. The
4455
+ // envelope was not: both of them address this IQ to the server as a *JID*
4456
+ // with nobody in the user part — Baileys writes '@s.whatsapp.net', whatsmeow
4457
+ // uses types.ServerJID — which goes out as JID_PAIR + empty user + the server
4458
+ // token. This wrote the bare string 's.whatsapp.net', and a bare string is
4459
+ // encoded as a plain dictionary token, so where every other client puts an
4460
+ // address the server was reading text. That is the whole of the difference,
4461
+ // and it is invisible in a stanza log, which prints the node before it is
4462
+ // encoded: both spellings read `to="s.whatsapp.net"` on screen.
4463
+ //
4464
+ // The reply was thrown away as well. _sendIq answers null on a timeout and
4465
+ // hands back error stanzas unread, so a refusal, a silence and a success all
4466
+ // returned the same thing — which is how "about updated" came to be printed
4467
+ // for a change that never happened.
4449
4468
  async changeAbout(text) {
4450
- const id = this._genMsgId();
4469
+ const body = String(text == null ? '' : text);
4470
+ // The limit the apps impose. A longer one is dropped rather than refused,
4471
+ // so it would otherwise look exactly like this bug.
4472
+ if (Array.from(body).length > ABOUT_MAX_LENGTH) {
4473
+ throw new Error('changeAbout: an about is limited to ' + ABOUT_MAX_LENGTH +
4474
+ ' characters — the server drops a longer one instead of refusing it');
4475
+ }
4476
+
4451
4477
  const node = new BinaryNode('iq', {
4452
- id,
4478
+ id: this._genMsgId(),
4453
4479
  xmlns: 'status',
4454
- to: 's.whatsapp.net',
4480
+ to: jidStrToObj('@s.whatsapp.net'),
4455
4481
  type: 'set'
4456
4482
  }, [
4457
- new BinaryNode('status', {}, Buffer.from(text, 'utf8'))
4483
+ new BinaryNode('status', {}, Buffer.from(body, 'utf8'))
4458
4484
  ]);
4459
- return this._sendIq(node);
4485
+
4486
+ const resp = await this._sendIq(node);
4487
+ if (!resp) throw new Error('changeAbout: no reply from server (IQ timed out)');
4488
+ if (resp.attrs && resp.attrs.type === 'error') {
4489
+ const errNode = findChild(resp, 'error');
4490
+ const code = errNode && errNode.attrs && errNode.attrs.code;
4491
+ const errText = errNode && errNode.attrs && errNode.attrs.text;
4492
+ throw new Error('changeAbout: server rejected the change' +
4493
+ (code ? ' (' + code + (errText ? ' ' + errText : '') + ')' : ''));
4494
+ }
4495
+ return resp;
4496
+ }
4497
+
4498
+ // The about this account currently has, as the server reports it.
4499
+ //
4500
+ // The set IQ is answered before the new text has to be visible anywhere, so
4501
+ // an empty result proves only that the stanza was understood. Reading it back
4502
+ // is the only way to tell an about the server stored from one it took and
4503
+ // dropped — and it is asked exactly the way a contact's is.
4504
+ async queryOwnAbout() {
4505
+ const me = this._store &&
4506
+ (this._store.phoneNumber || (this._store.me && this._store.me.id));
4507
+ if (!me) throw new Error('queryOwnAbout: not connected');
4508
+ return this.queryAbout(String(me));
4460
4509
  }
4461
4510
 
4462
4511
  // Change profile picture
@@ -4,10 +4,45 @@ const crypto = require('crypto');
4
4
  const https = require('https');
5
5
  const tls = require('tls');
6
6
  const curveJs = require('curve25519-js');
7
+ const { v4: uuidv4 } = require('uuid');
7
8
  const { getDeviceConfig } = require('./DeviceConfig');
8
9
  const attestation = require('./Attestation');
9
10
  const { dbg: _whaDbg } = require('./logger');
10
11
 
12
+ // ---------- Request envelope ----------
13
+ //
14
+ // The registration server reads which platform is calling out of the
15
+ // User-Agent. There is no form field for it — neither this library nor Cobalt
16
+ // sends one — so a request whose User-Agent does not name a platform it knows is
17
+ // refused with {"param":"platform","reason":"bad_param"} on every endpoint. The
18
+ // giveaway is that /client_log is refused the same way, and its body carries no
19
+ // device fields at all: nothing about the platform is in the body to begin with.
20
+ //
21
+ // Android used to be sent as `WhatsApp/<version> A`, which names nothing, and
22
+ // was refused everywhere. iOS has always sent the full form and has always
23
+ // worked, which is why only one of the two platforms was broken.
24
+ //
25
+ // The three extra Android headers come from Cobalt's AndroidClientRegistration,
26
+ // which records them as observed on a live native Android registration. Its iOS
27
+ // counterpart documents that the native iOS client omits all three, so the iOS
28
+ // envelope stays exactly as it was.
29
+ function registrationHeaders(device, waVersion) {
30
+ if (device.os === 'android') {
31
+ return {
32
+ 'User-Agent': `WhatsApp/${waVersion} Android/${device.osVersion} Device/${device.manufacturer}-${device.modelId}`,
33
+ 'Content-Type': 'application/x-www-form-urlencoded',
34
+ 'Accept': 'text/json',
35
+ 'WaMsysRequest': '1',
36
+ // A fresh one per request, the way the native client mints it.
37
+ 'request_token': uuidv4()
38
+ };
39
+ }
40
+ return {
41
+ 'User-Agent': `WhatsApp/${waVersion} iOS/${device.osVersion} Device/${device.model}`,
42
+ 'Content-Type': 'application/x-www-form-urlencoded'
43
+ };
44
+ }
45
+
11
46
  // ---------- SOCKS4 / SOCKS5 / Tor support ----------
12
47
  //
13
48
  // Set SOCKS_PROXY (or TOR_PROXY) to route registration traffic through a proxy:
@@ -125,15 +160,11 @@ async function httpPostViaSocks(path, body, waVersion, proxyUrl, authHeader) {
125
160
  tlsSocket.once('error', rej);
126
161
  });
127
162
 
128
- const _dev = getDeviceConfig();
129
- const userAgent = _dev.os === 'android'
130
- ? `WhatsApp/${waVersion} A`
131
- : `WhatsApp/${waVersion} iOS/${_dev.osVersion} Device/${_dev.model}`;
163
+ const headers = registrationHeaders(getDeviceConfig(), waVersion);
132
164
  const reqLines = [
133
165
  `POST /v2${path} HTTP/1.1`,
134
166
  `Host: ${dHost}`,
135
- `User-Agent: ${userAgent}`,
136
- `Content-Type: application/x-www-form-urlencoded`,
167
+ ...Object.keys(headers).map(k => `${k}: ${headers[k]}`),
137
168
  `Content-Length: ${Buffer.byteLength(body)}`
138
169
  ];
139
170
  if (authHeader) reqLines.push(`Authorization: ${authHeader}`);
@@ -703,16 +734,11 @@ function httpPost(path, body, waVersion, authHeader) {
703
734
  if (proxy) return httpPostViaSocks(path, body, waVersion, proxy, authHeader);
704
735
 
705
736
  return new Promise((resolve, reject) => {
706
- const _httpDev = getDeviceConfig();
707
- const userAgent = _httpDev.os === 'android'
708
- ? `WhatsApp/${waVersion} A`
709
- : `WhatsApp/${waVersion} iOS/${_httpDev.osVersion} Device/${_httpDev.model}`;
710
737
  const bodyBuf = Buffer.from(body, 'utf8');
711
- const headers = {
712
- 'User-Agent': userAgent,
713
- 'Content-Type': 'application/x-www-form-urlencoded',
714
- 'Content-Length': bodyBuf.length
715
- };
738
+ const headers = Object.assign(
739
+ registrationHeaders(getDeviceConfig(), waVersion),
740
+ { 'Content-Length': bodyBuf.length }
741
+ );
716
742
  // Attestation cert-chain / App Attest header (Android cert chain, iOS
717
743
  // <attestation>|<keyId>). Only present when body attestation is available.
718
744
  if (authHeader) headers['Authorization'] = authHeader;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whalibmob",
3
- "version": "5.12.9",
3
+ "version": "5.12.10",
4
4
  "description": "WhatsApp library for interaction with WhatsApp Mobile API no web",
5
5
  "author": "Kunboruto20",
6
6
  "main": "index.js",