whalibmob 5.12.14 → 5.12.16
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/.env.example +6 -4
- package/README.md +137 -6
- package/lib/Registration.js +36 -11
- package/lib/noise.js +20 -3
- package/package.json +1 -1
package/.env.example
CHANGED
|
@@ -52,11 +52,13 @@
|
|
|
52
52
|
|
|
53
53
|
# ─── WhatsApp version ────────────────────────────────────────────────────────
|
|
54
54
|
# Pin the WhatsApp client version. When set, the live version lookup is skipped
|
|
55
|
-
# entirely
|
|
55
|
+
# entirely, and this is what is announced on connect in place of the version
|
|
56
|
+
# stored in the session. Leave unset to fetch the current version automatically.
|
|
56
57
|
#
|
|
57
|
-
# On Android this is normally not needed
|
|
58
|
-
#
|
|
59
|
-
#
|
|
58
|
+
# On Android this is normally not needed: the version comes from the APK the
|
|
59
|
+
# token material was read from. On iOS it is looked up on the App Store, and a
|
|
60
|
+
# lookup that fails leaves a built-in fallback version in the session — which
|
|
61
|
+
# the server refuses at connect with a 405. That is what this is for.
|
|
60
62
|
# WA_VERSION=2.24.10.75
|
|
61
63
|
|
|
62
64
|
# Override the static registration token. iOS only — Android has no static token
|
package/README.md
CHANGED
|
@@ -254,6 +254,7 @@ npm install -g whalibmob
|
|
|
254
254
|
- [Android Profiles](#android-profiles)
|
|
255
255
|
- [Custom Device Fields](#custom-device-fields)
|
|
256
256
|
- [Version & Token Overrides](#version--token-overrides)
|
|
257
|
+
- [When the server answers 405 on connect](#when-the-server-answers-405-on-connect)
|
|
257
258
|
|
|
258
259
|
---
|
|
259
260
|
|
|
@@ -291,14 +292,40 @@ wa registration --request-code 919634847671 --method wa_old
|
|
|
291
292
|
```
|
|
292
293
|
|
|
293
294
|
**Registering as Android** is the same command with the platform named. Nothing
|
|
294
|
-
else to prepare — see [what it does behind that one command](#registering-as-android)
|
|
295
|
+
else to prepare — see [what it does behind that one command](#registering-as-android).
|
|
296
|
+
|
|
297
|
+
Linux, macOS, Termux:
|
|
295
298
|
|
|
296
299
|
```sh
|
|
297
300
|
WA_OS=android WA_DEVICE=samsung-s24-ultra wa registration --request-code 919634847671 --debug
|
|
298
301
|
```
|
|
299
302
|
|
|
300
|
-
|
|
301
|
-
|
|
303
|
+
Windows, Command Prompt — `set` on its own line, because `VAR=value` in front of
|
|
304
|
+
a command is Unix syntax and Windows refuses it:
|
|
305
|
+
|
|
306
|
+
```bat
|
|
307
|
+
set WA_OS=android
|
|
308
|
+
set WA_DEVICE=samsung-s24-ultra
|
|
309
|
+
wa registration --request-code 919634847671 --debug
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Windows, PowerShell:
|
|
313
|
+
|
|
314
|
+
```powershell
|
|
315
|
+
$env:WA_OS = "android"
|
|
316
|
+
$env:WA_DEVICE = "samsung-s24-ultra"
|
|
317
|
+
wa registration --request-code 919634847671 --debug
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
A `.env` file in the directory you run from works the same everywhere and saves
|
|
321
|
+
repeating it — see [Device Quick Start](#device-quick-start). `--debug` prints
|
|
322
|
+
every request and reply, which is worth having the first time: its first line
|
|
323
|
+
names the platform that actually went out, so you can see whether the variables
|
|
324
|
+
arrived.
|
|
325
|
+
|
|
326
|
+
The variables only matter for the command that *creates* the session. What a
|
|
327
|
+
session registered as is written into it, so the confirmation step and every
|
|
328
|
+
later connect follow the session, not whatever the shell carries at the time.
|
|
302
329
|
|
|
303
330
|
The CLI sends the code request, prints the result, and then **stays open** in the interactive shell. You will see:
|
|
304
331
|
|
|
@@ -1342,6 +1369,28 @@ registered session saved to /home/user/.waSession/919634847671.json
|
|
|
1342
1369
|
now run: /connect 919634847671
|
|
1343
1370
|
```
|
|
1344
1371
|
|
|
1372
|
+
**Registering as Android from the shell** works the same way, but `WA_OS` has to
|
|
1373
|
+
be set when the shell *starts* — the `wa>` prompt is already inside a running
|
|
1374
|
+
process, and nothing typed at it can change the environment that process was
|
|
1375
|
+
launched with:
|
|
1376
|
+
|
|
1377
|
+
```sh
|
|
1378
|
+
WA_OS=android WA_DEVICE=samsung-s24-ultra wa
|
|
1379
|
+
```
|
|
1380
|
+
```sh
|
|
1381
|
+
wa> /reg code 919634847671
|
|
1382
|
+
no Android token material yet — fetching the WhatsApp APK from Google Play
|
|
1383
|
+
...
|
|
1384
|
+
status sent
|
|
1385
|
+
wa> /reg confirm 919634847671 123456
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
A `.env` file with `WA_OS=android` in the directory you start from does the same
|
|
1389
|
+
and saves the typing. Either way it only matters for the command that *creates*
|
|
1390
|
+
the session: what a session registered as is written into it, and every later
|
|
1391
|
+
step — the confirmation, a reconnect from a different shell tomorrow — follows
|
|
1392
|
+
the session rather than the environment.
|
|
1393
|
+
|
|
1345
1394
|
---
|
|
1346
1395
|
|
|
1347
1396
|
### Connection Commands (in-shell)
|
|
@@ -4282,12 +4331,56 @@ Copy `.env.example` to `.env` in your project root and set the variables you nee
|
|
|
4282
4331
|
|
|
4283
4332
|
### Device Quick Start
|
|
4284
4333
|
|
|
4285
|
-
Emulate an Android Pixel 8 Pro
|
|
4334
|
+
Emulate an Android Pixel 8 Pro. **The syntax for setting a variable differs per
|
|
4335
|
+
shell**, and getting it wrong is the most common reason a device profile appears
|
|
4336
|
+
to be ignored:
|
|
4337
|
+
|
|
4338
|
+
**Linux, macOS, Termux** — set them for the one command:
|
|
4286
4339
|
|
|
4287
4340
|
```sh
|
|
4288
4341
|
WA_OS=android WA_DEVICE=pixel_8_pro node your-app.js
|
|
4342
|
+
WA_OS=android WA_DEVICE=pixel_8_pro wa registration --request-code 919634847671
|
|
4343
|
+
```
|
|
4344
|
+
|
|
4345
|
+
**Windows, Command Prompt** — `set` first, one per line. `VAR=value` in front of
|
|
4346
|
+
a command is Unix syntax and Windows answers it with
|
|
4347
|
+
`'WA_OS' is not recognized as an internal or external command`:
|
|
4348
|
+
|
|
4349
|
+
```bat
|
|
4350
|
+
set WA_OS=android
|
|
4351
|
+
set WA_DEVICE=pixel_8_pro
|
|
4352
|
+
wa registration --request-code 919634847671
|
|
4353
|
+
```
|
|
4354
|
+
|
|
4355
|
+
Keep them on separate lines. Chaining with `&&` puts the space before the `&&`
|
|
4356
|
+
inside the value.
|
|
4357
|
+
|
|
4358
|
+
**Windows, PowerShell**:
|
|
4359
|
+
|
|
4360
|
+
```powershell
|
|
4361
|
+
$env:WA_OS = "android"
|
|
4362
|
+
$env:WA_DEVICE = "pixel_8_pro"
|
|
4363
|
+
wa registration --request-code 919634847671
|
|
4289
4364
|
```
|
|
4290
4365
|
|
|
4366
|
+
**Anywhere, and the one worth preferring** — a `.env` file in the directory you
|
|
4367
|
+
run from, which behaves identically on every platform:
|
|
4368
|
+
|
|
4369
|
+
```dotenv
|
|
4370
|
+
WA_OS=android
|
|
4371
|
+
WA_DEVICE=pixel_8_pro
|
|
4372
|
+
```
|
|
4373
|
+
|
|
4374
|
+
```sh
|
|
4375
|
+
wa registration --request-code 919634847671
|
|
4376
|
+
```
|
|
4377
|
+
|
|
4378
|
+
The CLI reads `.env` from the **current directory**, not from where whalibmob is
|
|
4379
|
+
installed, so `cd` to the directory holding it before running. Whichever way you
|
|
4380
|
+
choose, the first line of `--debug` output tells you whether it took:
|
|
4381
|
+
`User-Agent: WhatsApp/… Android/14 Device/Google-Pixel 8 Pro`. An `iOS/…` there
|
|
4382
|
+
means the variables never arrived.
|
|
4383
|
+
|
|
4291
4384
|
Or put the variables in a `.env` file. When using the **CLI** (`wa` command) the file is loaded automatically. When using the **library directly**, load it before `require('whalibmob')`:
|
|
4292
4385
|
|
|
4293
4386
|
```js
|
|
@@ -4374,8 +4467,46 @@ These variables override individual fields on top of the selected profile:
|
|
|
4374
4467
|
|
|
4375
4468
|
| Variable | Description |
|
|
4376
4469
|
|---|---|
|
|
4377
|
-
| `WA_VERSION` | Pin the WhatsApp version (e.g. `2.24.13.80`). Skips the live store fetch. |
|
|
4378
|
-
| `WA_STATIC_TOKEN` | Override the static token used in registration token computation. |
|
|
4470
|
+
| `WA_VERSION` | Pin the WhatsApp version (e.g. `2.24.13.80`). Skips the live store fetch, and is announced on connect in place of the version stored in the session. |
|
|
4471
|
+
| `WA_STATIC_TOKEN` | Override the static token used in registration token computation. iOS only — Android has no static token. |
|
|
4472
|
+
|
|
4473
|
+
### When the server answers 405 on connect
|
|
4474
|
+
|
|
4475
|
+
```
|
|
4476
|
+
WhatsApp auth failure 405 — client outdated — the version this session
|
|
4477
|
+
announces is not one the server accepts.
|
|
4478
|
+
```
|
|
4479
|
+
|
|
4480
|
+
**The session is fine and the number is still registered.** 405 is the server
|
|
4481
|
+
declining the *client*, not the account: the version being announced is one it no
|
|
4482
|
+
longer accepts. Registering the number again is the one move that cannot help —
|
|
4483
|
+
the same version would go out and be refused identically, at the cost of a real
|
|
4484
|
+
phone number and a code request.
|
|
4485
|
+
|
|
4486
|
+
Announce a current version instead:
|
|
4487
|
+
|
|
4488
|
+
```sh
|
|
4489
|
+
WA_VERSION=2.26.30.3 wa connect 919634847671
|
|
4490
|
+
```
|
|
4491
|
+
|
|
4492
|
+
Or put `WA_VERSION` in the `.env` file, where it applies to every command.
|
|
4493
|
+
|
|
4494
|
+
**Where the stale version comes from.** Each platform learns its version
|
|
4495
|
+
differently:
|
|
4496
|
+
|
|
4497
|
+
| | how the version is found | what happens when that fails |
|
|
4498
|
+
|---|---|---|
|
|
4499
|
+
| iOS | looked up on the App Store | falls back to a version compiled into the library, which goes stale |
|
|
4500
|
+
| Android | read from the APK the token material came from | `wa apk-material --download` fetches the current one |
|
|
4501
|
+
|
|
4502
|
+
So this is mostly an iOS story: a lookup that times out or is rate limited leaves
|
|
4503
|
+
a months-old fallback version in the session, and nothing says so until the
|
|
4504
|
+
handshake is refused. On Android the version travels with the APK, and refreshing
|
|
4505
|
+
the material refreshes the version with it:
|
|
4506
|
+
|
|
4507
|
+
```sh
|
|
4508
|
+
wa apk-material --download
|
|
4509
|
+
```
|
|
4379
4510
|
|
|
4380
4511
|
## License
|
|
4381
4512
|
|
package/lib/Registration.js
CHANGED
|
@@ -575,6 +575,39 @@ function tryLoadAndroidMaterial() {
|
|
|
575
575
|
try { return loadAndroidMaterial(); } catch (_) { return null; }
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
+
/**
|
|
579
|
+
* Which platform a registration speaks.
|
|
580
|
+
*
|
|
581
|
+
* Once a session has an account behind it, or has a code outstanding, its
|
|
582
|
+
* platform is settled: the account was created as that, the token and the
|
|
583
|
+
* User-Agent have to keep saying so, and re-reading WA_OS could only break it.
|
|
584
|
+
* A confirmation run from a shell without the variables must not flip to iOS
|
|
585
|
+
* halfway through.
|
|
586
|
+
*
|
|
587
|
+
* Before that, a session holds nothing but keys. Re-running the code request is
|
|
588
|
+
* how you start it over, and the environment is how you say what to start it
|
|
589
|
+
* over as — so the environment decides, and this stops being consulted the
|
|
590
|
+
* moment a code goes out.
|
|
591
|
+
*
|
|
592
|
+
* When the two disagree on a session that is settled, that is said out loud.
|
|
593
|
+
* Silently ignoring WA_OS is how you end up watching an Android registration go
|
|
594
|
+
* out under an iOS User-Agent and not knowing why.
|
|
595
|
+
*/
|
|
596
|
+
function deviceForRegistration(store, opts) {
|
|
597
|
+
const env = getDeviceConfig();
|
|
598
|
+
const stored = store && store.device;
|
|
599
|
+
const settled = !!(store && (store.registered || store.codePending));
|
|
600
|
+
if (!settled || !stored) return env;
|
|
601
|
+
|
|
602
|
+
if (stored.os !== env.os) {
|
|
603
|
+
const say = (opts && opts.onProgress) || (m => _whaDbg('[DBG] REG ' + m));
|
|
604
|
+
say('note: this session was started as ' + stored.os + ', so it stays ' + stored.os +
|
|
605
|
+
' — WA_OS=' + env.os + ' does not apply to a number that is already part-way ' +
|
|
606
|
+
'through registering. Delete the session file to start it over as ' + env.os + '.');
|
|
607
|
+
}
|
|
608
|
+
return stored;
|
|
609
|
+
}
|
|
610
|
+
|
|
578
611
|
/**
|
|
579
612
|
* Have the Android token material ready, fetching the APK if it is not.
|
|
580
613
|
*
|
|
@@ -1333,11 +1366,7 @@ async function requestSmsCode(store, method, opts) {
|
|
|
1333
1366
|
opts = opts || {};
|
|
1334
1367
|
// Before the version is read, since on Android the version comes out of the
|
|
1335
1368
|
// APK this fetches.
|
|
1336
|
-
|
|
1337
|
-
// store that decides — not whatever WA_OS the shell happens to carry now. A
|
|
1338
|
-
// confirmation run from a shell without the variables would otherwise sign an
|
|
1339
|
-
// Android registration with an iOS token.
|
|
1340
|
-
const _device = store.device || getDeviceConfig();
|
|
1369
|
+
const _device = deviceForRegistration(store, opts);
|
|
1341
1370
|
await ensureAndroidMaterial(opts, _device);
|
|
1342
1371
|
const waVersion = await fetchWaVersion(_device);
|
|
1343
1372
|
store.version = waVersion;
|
|
@@ -1459,11 +1488,7 @@ async function verifyCode(store, code, opts) {
|
|
|
1459
1488
|
opts = opts || {};
|
|
1460
1489
|
// Normally already there from the code request, but a confirmation can be run
|
|
1461
1490
|
// from a fresh shell that never made one.
|
|
1462
|
-
|
|
1463
|
-
// store that decides — not whatever WA_OS the shell happens to carry now. A
|
|
1464
|
-
// confirmation run from a shell without the variables would otherwise sign an
|
|
1465
|
-
// Android registration with an iOS token.
|
|
1466
|
-
const _device = store.device || getDeviceConfig();
|
|
1491
|
+
const _device = deviceForRegistration(store, opts);
|
|
1467
1492
|
await ensureAndroidMaterial(opts, _device);
|
|
1468
1493
|
const waVersion = await fetchWaVersion(_device);
|
|
1469
1494
|
store.version = waVersion;
|
|
@@ -1559,7 +1584,7 @@ module.exports = { checkIfRegistered, checkNumberStatus, requestSmsCode, verifyC
|
|
|
1559
1584
|
module.exports._http = { readHttpResponse, parseHttpResponse, decodeChunkedBody };
|
|
1560
1585
|
|
|
1561
1586
|
// Token computation, exposed for tests. Not part of the public API.
|
|
1562
|
-
module.exports._token = { computeToken, androidMaterialPath, registrationHeaders, ensureAndroidMaterial };
|
|
1587
|
+
module.exports._token = { computeToken, androidMaterialPath, registrationHeaders, ensureAndroidMaterial, deviceForRegistration };
|
|
1563
1588
|
|
|
1564
1589
|
// Challenge / two-factor internals, exposed for tests. Not part of the public API.
|
|
1565
1590
|
module.exports._verify = {
|
package/lib/noise.js
CHANGED
|
@@ -375,7 +375,12 @@ class NoiseSocket extends EventEmitter {
|
|
|
375
375
|
oc: false,
|
|
376
376
|
userAgent: {
|
|
377
377
|
platform: (this.store.device && this.store.device.platform) || 1,
|
|
378
|
-
version
|
|
378
|
+
// The version the session was registered with, unless WA_VERSION says
|
|
379
|
+
// otherwise. Without that override there is no way out of a 405: the
|
|
380
|
+
// version lives in the session file, the server refuses it, and the
|
|
381
|
+
// only remaining move is to register the number again — which is the
|
|
382
|
+
// one thing that should never be the answer to a client-side problem.
|
|
383
|
+
version: process.env.WA_VERSION || this.store.version,
|
|
379
384
|
mcc: _phoneMeta.mcc,
|
|
380
385
|
mnc: _phoneMeta.mnc,
|
|
381
386
|
osVersion: this.store.device.osVersion,
|
|
@@ -463,8 +468,20 @@ class NoiseSocket extends EventEmitter {
|
|
|
463
468
|
'402': { wipe: false, text: 'temporarily banned.' },
|
|
464
469
|
'403': { wipe: true, text: "the account's primary device is gone " +
|
|
465
470
|
'— it is no longer a multi-device account.' },
|
|
466
|
-
|
|
467
|
-
|
|
471
|
+
// Not a spent session, however much it looks like one. The server
|
|
472
|
+
// declined the *client*: the version we announced is not one it
|
|
473
|
+
// accepts. The registration behind the session is untouched, and
|
|
474
|
+
// telling people to register again over this costs them a real
|
|
475
|
+
// phone number for nothing — the same version would be announced
|
|
476
|
+
// and refused identically. _handleFailure already reads it this way
|
|
477
|
+
// once a session is up; this is the same code arriving during the
|
|
478
|
+
// handshake, and it was the one path still calling it revoked.
|
|
479
|
+
'405': { wipe: false, text: 'client outdated — the version this ' +
|
|
480
|
+
'session announces is not one the server accepts. The ' +
|
|
481
|
+
'session itself is fine: set WA_VERSION to a current ' +
|
|
482
|
+
'WhatsApp version and connect again. On Android, ' +
|
|
483
|
+
'`wa apk-material --download` picks the current one up on ' +
|
|
484
|
+
'its own.' },
|
|
468
485
|
'406': { wipe: true, text: 'banned.' },
|
|
469
486
|
'409': { wipe: true, text: 'bad user agent — the client identified ' +
|
|
470
487
|
'itself in a way the server rejects.' },
|