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 +27 -4
- package/lib/messages/MessageSender.js +35 -8
- package/lib/proto/MessageProto.js +9 -0
- package/package.json +1 -1
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(
|
|
708
|
-
this.
|
|
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
|
|
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 => {
|
|
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
|
|
649
|
-
skStore.
|
|
650
|
-
const
|
|
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,
|
|
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
|
-
|
|
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,
|