whalibmob 5.5.72 → 5.5.73

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/lib/BinaryNode.js CHANGED
@@ -310,9 +310,15 @@ class NodeDecoder {
310
310
  // that does not exist, so device queries for it came back empty, no Signal
311
311
  // session was ever built, and group sends were rejected with ack 479.
312
312
  const server = _serverForAgent(agent);
313
+ // The device must survive stringification. Everything downstream keys off
314
+ // the string form: fetchBundles maps bundles by it, so five devices all
315
+ // rendering as "user@server" collapsed into one entry and left the rest
316
+ // without a session; and jidToAddress parses the ":device" out of it, so
317
+ // dropping it addressed every Signal session as device 0 — which is why a
318
+ // message from a linked device could not be decrypted either.
313
319
  return {
314
320
  user, agent, device, server,
315
- toString() { return `${user}@${server}`; }
321
+ toString() { return device ? `${user}:${device}@${server}` : `${user}@${server}`; }
316
322
  };
317
323
  }
318
324
  }
@@ -554,6 +554,21 @@ class MessageSender {
554
554
  return this._sendGroupMessage(toJid, msgId, plaintext, mediaType,
555
555
  Object.assign({}, options, { _479retry: true }));
556
556
  }
557
+ // No session could be built for a single member — usually a prekey IQ
558
+ // that timed out, leaving the device list cached with nothing behind
559
+ // it. Purge the cached devices and sessions so the retry re-fetches
560
+ // bundles and opens fresh pkmsg sessions instead of failing again.
561
+ if (err && /NO_OPEN_SESSION/.test(err.message) && !options._noSessionRetry) {
562
+ _whaDbg('[DBG] NO_OPEN_SESSION group ' + toJid + ' — forcing fresh pkmsg\n');
563
+ await this._forceSessionRebuild(
564
+ (this._client._getGroupMembers ? this._client._getGroupMembers(toJid) : [])
565
+ );
566
+ if (this._signal && this._signal.senderKeyStore) {
567
+ this._signal.senderKeyStore.invalidateSKDM(toJid);
568
+ }
569
+ return this._sendGroupMessage(toJid, msgId, plaintext, mediaType,
570
+ Object.assign({}, options, { _noSessionRetry: true }));
571
+ }
557
572
  throw err;
558
573
  }
559
574
  }
@@ -587,11 +602,41 @@ class MessageSender {
587
602
  return this._sendDMMessage(toJid, retryMsgId, plaintext, mediaType,
588
603
  Object.assign({}, options, { _479retry: true }));
589
604
  }
605
+ // ── No session at all ────────────────────────────────────────────────────
606
+ // Nothing could be encrypted for any device, so there is no ciphertext to
607
+ // send. This is what a timed-out prekey IQ leaves behind: the device list
608
+ // is cached but no session sits behind it, and every later send fails the
609
+ // same way because the cache hides the gap. Purge both and retry once, so
610
+ // the next attempt re-fetches bundles and opens fresh pkmsg sessions.
611
+ if (err && /NO_OPEN_SESSION/.test(err.message) && !options._noSessionRetry) {
612
+ _whaDbg('[DBG] NO_OPEN_SESSION dm ' + toJid + ' — forcing fresh pkmsg\n');
613
+ await this._forceSessionRebuild([toJid]);
614
+ return this._sendDMMessage(toJid, generateMessageId(), plaintext, mediaType,
615
+ Object.assign({}, options, { _noSessionRetry: true }));
616
+ }
590
617
  // ─────────────────────────────────────────────────────────────────────────
591
618
  throw err;
592
619
  }
593
620
  }
594
621
 
622
+ // Drop every cached device list and Signal session for these JIDs so the next
623
+ // send is forced to re-query devices, re-fetch prekey bundles and open new
624
+ // pkmsg sessions from scratch.
625
+ async _forceSessionRebuild(jids) {
626
+ const phones = [...new Set((jids || []).map(phoneFromJid).filter(Boolean))];
627
+ for (const phone of phones) {
628
+ await this._clearSignalSessionsForRecipient(phone).catch(() => {});
629
+ }
630
+ if (this._devMgr && phones.length) {
631
+ this._devMgr.clearCache(phones);
632
+ // LID device lists are cached under a separate key.
633
+ if (typeof this._devMgr._dcDel === 'function') {
634
+ this._devMgr._dcDel(phones.map(p => 'lid:' + p));
635
+ }
636
+ }
637
+ _whaDbg('[DBG] FORCE_SESSION_REBUILD purged ' + phones.join(', ') + '\n');
638
+ }
639
+
595
640
  // ─── Clear all Signal sessions for a phone-number recipient ─────────────────
596
641
  //
597
642
  // Called on error 479 (stale session). Deletes:
@@ -320,6 +320,14 @@ function jidToAddress(jid) {
320
320
  } else if (jid && jid.user) {
321
321
  user = jid.user;
322
322
  deviceId = jid.device || 0;
323
+ // A @lid JID is encoded as JID_PAIR with the device kept inside the user
324
+ // part ("112713111982325:49"), so an object can carry its device there
325
+ // rather than in .device. Without this the address came out as device 0.
326
+ const colonIdx = String(user).indexOf(':');
327
+ if (colonIdx >= 0) {
328
+ if (!deviceId) deviceId = parseInt(String(user).slice(colonIdx + 1), 10) || 0;
329
+ user = String(user).slice(0, colonIdx);
330
+ }
323
331
  } else {
324
332
  user = String(jid);
325
333
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whalibmob",
3
- "version": "5.5.72",
3
+ "version": "5.5.73",
4
4
  "description": "WhatsApp library for interaction with WhatsApp Mobile API no web",
5
5
  "author": "Kunboruto50",
6
6
  "main": "index.js",