whalibmob 5.14.4 → 5.14.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.
Files changed (3) hide show
  1. package/cli.js +6 -1
  2. package/lib/noise.js +55 -0
  3. package/package.json +1 -1
package/cli.js CHANGED
@@ -202,7 +202,12 @@ function enableWireTrace() {
202
202
  return origWrite(chunk, ...rest);
203
203
  };
204
204
 
205
- sock.on('data', (d) => {
205
+ // Prepended, not appended: the socket already carries the handshake's own
206
+ // data listener, registered while connect() was building the socket. An
207
+ // appended one runs after the frame has been read, so a frame the server
208
+ // sent would print *after* the error it caused — or not at all, once the
209
+ // failure tears the connection down. The trace has to come first.
210
+ sock.prependListener('data', (d) => {
206
211
  if (this.secured) return;
207
212
  // Label positionally, but say so when the reply is plainly not a Noise
208
213
  // frame — a proxy or captive portal answering in ASCII is worth reading
package/lib/noise.js CHANGED
@@ -301,6 +301,25 @@ function readFrameLength(data) {
301
301
  return (data[0] << 16) | (data[1] << 8) | data[2];
302
302
  }
303
303
 
304
+ // ─── Handshake trace ─────────────────────────────────────────────────────────
305
+ //
306
+ // The handshake runs before there are stanzas to log, so without this the debug
307
+ // output jumps from "connecting" to either a secured channel or an error with
308
+ // nothing in between — and when it fails, nothing to say which step it got to.
309
+ //
310
+ // Only public material is rendered: ephemeral and static public keys, frame and
311
+ // field sizes, certificate outcome. Derived session keys and anything private
312
+ // are named but never printed, because a debug trace is the thing people paste
313
+ // into a bug report.
314
+ function _hsKey(buf) {
315
+ if (!Buffer.isBuffer(buf)) return String(buf);
316
+ return buf.toString('hex') + ' (' + buf.length + 'B)';
317
+ }
318
+
319
+ function _hsSize(buf) {
320
+ return Buffer.isBuffer(buf) ? buf.length + 'B' : 'absent';
321
+ }
322
+
304
323
  // ─── NoiseSocket ─────────────────────────────────────────────────────────────
305
324
  //
306
325
  // Events emitted:
@@ -395,9 +414,18 @@ class NoiseSocket extends EventEmitter {
395
414
  };
396
415
  this.noiseState.hash(this._ephemeralKeyPair.public);
397
416
 
417
+ _whaDbg('[DBG] NOISE handshake begin transport=' + this.transport +
418
+ ' prologue=' + this._prologue.toString('hex') +
419
+ ' pattern=Noise_XX_25519_AESGCM_SHA256');
420
+ _whaDbg('[DBG] NOISE ──▶ ClientHello ephemeral=' + _hsKey(this._ephemeralKeyPair.public));
421
+
398
422
  const helloPayload = encodeHandshakeClientHello(this._ephemeralKeyPair.public);
399
423
  const frame = Buffer.concat([this._prologue, makeFrame(helloPayload)]);
424
+ _whaDbg('[DBG] NOISE ──▶ ClientHello ' + frame.length + 'B on the wire = prologue ' +
425
+ this._prologue.length + 'B + header ' + FRAME_HEADER_SIZE + 'B + payload ' +
426
+ helloPayload.length + 'B');
400
427
  this.socket.write(frame);
428
+ _whaDbg('[DBG] NOISE waiting for ServerHello');
401
429
  }
402
430
 
403
431
  _onData(data) {
@@ -424,16 +452,24 @@ class NoiseSocket extends EventEmitter {
424
452
 
425
453
  _handleHandshakeFrame(frame) {
426
454
  try {
455
+ _whaDbg('[DBG] NOISE ◀── ServerHello ' + frame.length + 'B frame');
427
456
  const serverHello = decodeServerHello(frame);
457
+ _whaDbg('[DBG] NOISE ◀── ServerHello ephemeral=' + _hsSize(serverHello.ephemeral) +
458
+ ' static=' + _hsSize(serverHello.staticEnc) + ' encrypted' +
459
+ ' certificate=' + _hsSize(serverHello.payload) + ' encrypted');
428
460
  if (!serverHello.ephemeral) throw new Error('No server ephemeral in ServerHello');
461
+ _whaDbg('[DBG] NOISE ◀── server ephemeral=' + _hsKey(serverHello.ephemeral));
429
462
 
430
463
  this.noiseState.hash(serverHello.ephemeral);
431
464
  const sharedEE = dhShared(this._ephemeralKeyPair.private, serverHello.ephemeral);
432
465
  this.noiseState.mixKey(sharedEE);
466
+ _whaDbg('[DBG] NOISE mixed DH(our ephemeral, server ephemeral)');
433
467
 
434
468
  const serverStaticDec = this.noiseState.decryptWithAd(serverHello.staticEnc);
469
+ _whaDbg('[DBG] NOISE ◀── server static key decrypted=' + _hsKey(serverStaticDec));
435
470
  const sharedSE = dhShared(this._ephemeralKeyPair.private, serverStaticDec);
436
471
  this.noiseState.mixKey(sharedSE);
472
+ _whaDbg('[DBG] NOISE mixed DH(our ephemeral, server static)');
437
473
 
438
474
  // The server is authenticated here, before ClientFinish hands it our
439
475
  // static key and payload. A ServerHello without a certificate leaves
@@ -442,14 +478,20 @@ class NoiseSocket extends EventEmitter {
442
478
  throw new Error('WA server cert validation failed: the server sent no certificate');
443
479
  }
444
480
  const certPlain = this.noiseState.decryptWithAd(serverHello.payload);
481
+ _whaDbg('[DBG] NOISE ◀── certificate decrypted=' + certPlain.length + 'B — verifying');
445
482
  validateServerCert(certPlain, serverStaticDec);
483
+ _whaDbg('[DBG] NOISE ◀── certificate verified: signed by the root CA and ' +
484
+ 'certifying the static key above — server authenticated');
446
485
 
447
486
  const noisePriv = this.store.noiseKeyPair.private;
448
487
  // Send the raw 32-byte noise public key (no 0x05 Signal prefix)
449
488
  const noisePub = stripKeyPrefix(this.store.noiseKeyPair.public);
450
489
  const encStatic = this.noiseState.encryptWithAd(noisePub);
490
+ _whaDbg('[DBG] NOISE ──▶ our static key=' + _hsKey(noisePub) +
491
+ ' encrypted to ' + encStatic.length + 'B');
451
492
  const sharedSS = dhShared(noisePriv, serverHello.ephemeral);
452
493
  this.noiseState.mixKey(sharedSS);
494
+ _whaDbg('[DBG] NOISE mixed DH(our static, server ephemeral)');
453
495
 
454
496
  // Web mode hands us a finished companion payload; there is no phone
455
497
  // identity to derive anything from, and the fields below do not exist on
@@ -457,6 +499,9 @@ class NoiseSocket extends EventEmitter {
457
499
  if (this._buildPayload) {
458
500
  const encPayload = this.noiseState.encryptWithAd(this._buildPayload());
459
501
  const finish = encodeHandshakeClientFinish(encStatic, encPayload);
502
+ _whaDbg('[DBG] NOISE ──▶ ClientFinish static=' + encStatic.length + 'B payload=' +
503
+ encPayload.length + 'B (companion) ' + (finish.length + FRAME_HEADER_SIZE) +
504
+ 'B on the wire');
460
505
  this.socket.write(makeFrame(finish));
461
506
 
462
507
  const webKeys = this.noiseState.split();
@@ -465,6 +510,7 @@ class NoiseSocket extends EventEmitter {
465
510
  this.writeCounter = 0;
466
511
  this.readCounter = 0;
467
512
  this.secured = true;
513
+ _whaDbg('[DBG] NOISE split() derived the send and receive keys — channel secured');
468
514
 
469
515
  if (this._expectSuccess) {
470
516
  this._awaitingAuth = true;
@@ -560,6 +606,9 @@ class NoiseSocket extends EventEmitter {
560
606
 
561
607
  const encPayload = this.noiseState.encryptWithAd(payload);
562
608
  const finish = encodeHandshakeClientFinish(encStatic, encPayload);
609
+ _whaDbg('[DBG] NOISE ──▶ ClientFinish static=' + encStatic.length + 'B payload=' +
610
+ encPayload.length + 'B (username=' + this.store.phoneNumber + ' version=' +
611
+ _version + ') ' + (finish.length + FRAME_HEADER_SIZE) + 'B on the wire');
563
612
  this.socket.write(makeFrame(finish));
564
613
 
565
614
  const keys = this.noiseState.split();
@@ -567,6 +616,8 @@ class NoiseSocket extends EventEmitter {
567
616
  this.readKey = keys.readKey;
568
617
  this.writeCounter = 0;
569
618
  this.readCounter = 0;
619
+ _whaDbg('[DBG] NOISE split() derived the send and receive keys — channel secured');
620
+ _whaDbg('[DBG] NOISE waiting for the server to accept the payload');
570
621
  this.secured = true;
571
622
 
572
623
  // Wait for the server's <success> or <failure> confirmation before
@@ -575,6 +626,8 @@ class NoiseSocket extends EventEmitter {
575
626
  this._awaitingAuth = true;
576
627
 
577
628
  } catch (err) {
629
+ // The step that failed is the one after the last line traced above.
630
+ _whaDbg('[DBG] NOISE ✗ handshake failed: ' + (err && err.message));
578
631
  if (this._connectReject) {
579
632
  this._connectReject(err);
580
633
  this._connectResolve = null;
@@ -596,6 +649,8 @@ class NoiseSocket extends EventEmitter {
596
649
  if (this._awaitingAuth) {
597
650
  this._awaitingAuth = false;
598
651
  const tag = node && node.description;
652
+ _whaDbg('[DBG] NOISE ◀── <' + tag + '> — the first frame over the secured channel, ' +
653
+ 'and the server\'s answer on the payload');
599
654
 
600
655
  if (tag === 'success') {
601
656
  if (this._connectResolve) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whalibmob",
3
- "version": "5.14.4",
3
+ "version": "5.14.5",
4
4
  "description": "WhatsApp library for interaction with WhatsApp Mobile API and web ",
5
5
  "author": "Kunboruto20",
6
6
  "main": "index.js",