whalibmob 5.1.12 → 5.1.13

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/Client.js CHANGED
@@ -125,6 +125,7 @@ class WhalibmobClient extends EventEmitter {
125
125
  this._pendingAcks = new Map(); // msgId → resolve fn
126
126
  this._groupMembers = new Map(); // groupJid → Set<memberJid>
127
127
  this._lidToPn = new Map(); // LID user → phone number
128
+ this._pnToLid = new Map(); // phone number → LID user
128
129
  this._retryPending = new Map(); // msgId → {node, retryCount}
129
130
  this._retryPreKeyIdx = 0; // rotating index for assigning unique prekeys to retries
130
131
  this._appStateVersions = {}; // collectionName → version (int)
@@ -523,7 +524,7 @@ class WhalibmobClient extends EventEmitter {
523
524
  const participant = String(attrs.participant || from);
524
525
  // sender_pn is the real phone-based JID when `from` is a LID (linked identity)
525
526
  const senderPn = attrs.sender_pn ? String(attrs.sender_pn) : null;
526
- if (senderPn) { const lidUser = from.split('@')[0].split(':')[0]; const pnUser = senderPn.split('@')[0].split(':')[0]; if (lidUser && pnUser && lidUser !== pnUser) this._lidToPn.set(lidUser, pnUser); }
527
+ if (senderPn) { const lidUser = from.split('@')[0].split(':')[0]; const pnUser = senderPn.split('@')[0].split(':')[0]; if (lidUser && pnUser && lidUser !== pnUser) { this._lidToPn.set(lidUser, pnUser); this._pnToLid.set(pnUser, lidUser); } }
527
528
  // Debug: log every incoming message node
528
529
  process.stderr.write('[DBG] _handleMessage from=' + from + ' participant=' + participant + ' senderPn=' + senderPn + ' id=' + id + '\n');
529
530
  // Debug: log message content structure
@@ -702,10 +703,20 @@ class WhalibmobClient extends EventEmitter {
702
703
  const encType = enc.attrs && enc.attrs.type;
703
704
  const cipherBuf = Buffer.isBuffer(enc.content) ? enc.content : Buffer.from(enc.content || '');
704
705
 
705
- // Decrypt SKDM with our Signal session
706
+ // Decrypt SKDM with our Signal session, then parse the WA Message proto
707
+ // to extract the actual axolotl SKDM bytes from field 35
706
708
  this._signal.decrypt(senderJid, encType, cipherBuf)
707
- .then(skdmBytes => {
708
- this._signal.processSKDM(groupJid, senderJid, skdmBytes);
709
+ .then(decrypted => {
710
+ const decoded = this._decodeMsg(decrypted);
711
+ if (decoded && decoded.type === 'senderKeyDistribution' &&
712
+ decoded.groupId && decoded.axolotlBytes &&
713
+ decoded.axolotlBytes[0] === 0x33) {
714
+ this._signal.processSKDM(decoded.groupId, senderJid, decoded.axolotlBytes);
715
+ } else if (decoded && decoded.skdm &&
716
+ decoded.skdm.groupId && decoded.skdm.axolotlBytes &&
717
+ decoded.skdm.axolotlBytes[0] === 0x33) {
718
+ this._signal.processSKDM(decoded.skdm.groupId, senderJid, decoded.skdm.axolotlBytes);
719
+ }
709
720
  })
710
721
  .catch(() => {});
711
722
  }
@@ -1266,6 +1277,18 @@ class WhalibmobClient extends EventEmitter {
1266
1277
  return meta ? meta.participants : [];
1267
1278
  }
1268
1279
 
1280
+ getPNForLID(lid) {
1281
+ const lidUser = String(lid).split('@')[0].split(':')[0];
1282
+ const pnUser = this._lidToPn.get(lidUser);
1283
+ return pnUser ? pnUser + '@s.whatsapp.net' : null;
1284
+ }
1285
+
1286
+ getLIDForPN(pn) {
1287
+ const pnUser = String(pn).split('@')[0].split(':')[0];
1288
+ const lidUser = this._pnToLid.get(pnUser);
1289
+ return lidUser ? lidUser + '@lid' : null;
1290
+ }
1291
+
1269
1292
  // ─── Message ID generator ─────────────────────────────────────────────────
1270
1293
 
1271
1294
  _genMsgId() {
@@ -14,6 +14,7 @@ const {
14
14
  encodeLocationMessage, encodeContactMessage,
15
15
  encodeDeviceSentMessage, encodeProtocolMessage,
16
16
  encodeExtendedText,
17
+ encodeSenderKeyDistributionMessage,
17
18
  PROTOCOL_MSG_REVOKE, PROTOCOL_MSG_EPHEMERAL
18
19
  } = require('../proto/MessageProto');
19
20
  const { uploadMedia } = require('../MediaService');
@@ -626,10 +627,18 @@ class MessageSender {
626
627
  members = this._client._getGroupMembers(groupJid);
627
628
  } catch (_) {}
628
629
  }
629
- const skdmBytes = this._signal.buildSKDM(groupJid, ownJid);
630
+ const rawSKDM = this._signal.buildSKDM(groupJid, ownJid);
631
+ const skdmMsg = encodeSenderKeyDistributionMessage(groupJid, rawSKDM);
630
632
 
631
633
  const memberPhones = [...new Set(
632
- members.map(jid => { const raw = phoneFromJid(jid); if (raw.length >= 15 && this._client._lidToPn && this._client._lidToPn.has(raw)) return this._client._lidToPn.get(raw); return raw; }).filter(p => p !== ownPhone)
634
+ members.map(jid => {
635
+ const isLid = jid.endsWith('@lid') || jid.includes('@lid:') || jid.includes(':@lid');
636
+ const raw = phoneFromJid(jid);
637
+ if (isLid && this._client._lidToPn && this._client._lidToPn.has(raw)) {
638
+ return this._client._lidToPn.get(raw);
639
+ }
640
+ return raw;
641
+ }).filter(p => p !== ownPhone)
633
642
  )];
634
643
 
635
644
  const [memberDevices, ownDevices] = await Promise.all([
@@ -645,14 +654,13 @@ class MessageSender {
645
654
  ? allTargets
646
655
  : [ownJid, ...allTargets];
647
656
 
648
- const skStore = this._signal.senderKeyStore;
649
- skStore.setSKDMMap(groupJid, {});
650
- const skdmMap = skStore.getSKDMMap(groupJid);
651
- const skdmRecipients = allTargets;
657
+ const skStore = this._signal.senderKeyStore;
658
+ const existingSkdmMap = skStore.getSKDMMap(groupJid);
659
+ const skdmRecipients = allTargets.filter(jid => !existingSkdmMap[jid]);
652
660
 
653
661
  let skdmEncrypted = [];
654
662
  if (skdmRecipients.length > 0) {
655
- skdmEncrypted = await this._signal.bulkEncryptForDevices(skdmRecipients, skdmBytes);
663
+ skdmEncrypted = await this._signal.bulkEncryptForDevices(skdmRecipients, skdmMsg);
656
664
  skStore.markSKDMSent(groupJid, skdmRecipients);
657
665
  }
658
666
 
@@ -809,7 +817,7 @@ class MessageSender {
809
817
 
810
818
  async _uploadMedia(mediaType, data) {
811
819
  if (!this._mediaHosts.length) {
812
- throw new Error('No media hosts — wait for media connection before sending media');
820
+ await this._fetchMediaConn();
813
821
  }
814
822
  let buf;
815
823
  if (Buffer.isBuffer(data)) buf = data;
@@ -817,6 +825,25 @@ class MessageSender {
817
825
  else throw new Error('Media must be a Buffer or file path');
818
826
  return uploadMedia(mediaType, buf, this._mediaHosts, this._mediaAuth);
819
827
  }
828
+
829
+ async _fetchMediaConn() {
830
+ return new Promise((resolve, reject) => {
831
+ const timeout = setTimeout(() => {
832
+ this._client.removeListener('media_conn', onConn);
833
+ reject(new Error('Timeout waiting for media connection'));
834
+ }, 15000);
835
+ const onConn = ({ hosts, auth }) => {
836
+ clearTimeout(timeout);
837
+ if (hosts && hosts.length) {
838
+ this._mediaHosts = hosts;
839
+ this._mediaAuth = auth;
840
+ }
841
+ resolve();
842
+ };
843
+ this._client.once('media_conn', onConn);
844
+ try { this._client._requestMediaConnection(); } catch (_) {}
845
+ });
846
+ }
820
847
  }
821
848
 
822
849
  // ─── Helpers ──────────────────────────────────────────────────────────────────
@@ -566,6 +566,14 @@ function decodeMessageContainer(buf) {
566
566
  }
567
567
  }
568
568
 
569
+ function encodeSenderKeyDistributionMessage(groupId, axolotlBytes) {
570
+ const inner = Buffer.concat([
571
+ field(1, WIRE_LEN, str(groupId)),
572
+ field(2, WIRE_LEN, bytes(axolotlBytes))
573
+ ]);
574
+ return field(35, WIRE_LEN, inner);
575
+ }
576
+
569
577
  module.exports = {
570
578
  encodeText,
571
579
  encodeImageMessage,
@@ -583,6 +591,7 @@ module.exports = {
583
591
  encodeProtocolMessage,
584
592
  encodeExtendedText,
585
593
  encodeContextInfo,
594
+ encodeSenderKeyDistributionMessage,
586
595
  encodeVarint,
587
596
  field,
588
597
  varint,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whalibmob",
3
- "version": "5.1.12",
3
+ "version": "5.1.13",
4
4
  "description": "WhatsApp library for interaction with WhatsApp Mobile API no web",
5
5
  "author": "Kunboruto20",
6
6
  "main": "index.js",