whalibmob 5.1.13 → 5.1.14
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/cli.js +27 -18
- package/lib/Client.js +40 -7
- package/lib/messages/MessageSender.js +11 -3
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -481,8 +481,9 @@ async function handleLine(line) {
|
|
|
481
481
|
const jid = normalizeJid(jR);
|
|
482
482
|
if (!jid || !file) { fail('usage: /image <jid> <file> [caption]'); break; }
|
|
483
483
|
out('uploading...');
|
|
484
|
-
|
|
485
|
-
|
|
484
|
+
_client.sendImage(jid, file, { caption: cap.join(' ') || undefined })
|
|
485
|
+
.then(r => out('sent ' + (r && r.id ? r.id : r)))
|
|
486
|
+
.catch(e => fail('image error: ' + e.message));
|
|
486
487
|
break;
|
|
487
488
|
}
|
|
488
489
|
|
|
@@ -492,8 +493,9 @@ async function handleLine(line) {
|
|
|
492
493
|
const jid = normalizeJid(jR);
|
|
493
494
|
if (!jid || !file) { fail('usage: /video <jid> <file> [caption]'); break; }
|
|
494
495
|
out('uploading...');
|
|
495
|
-
|
|
496
|
-
|
|
496
|
+
_client.sendVideo(jid, file, { caption: cap.join(' ') || undefined })
|
|
497
|
+
.then(r => out('sent ' + (r && r.id ? r.id : r)))
|
|
498
|
+
.catch(e => fail('video error: ' + e.message));
|
|
497
499
|
break;
|
|
498
500
|
}
|
|
499
501
|
|
|
@@ -503,8 +505,9 @@ async function handleLine(line) {
|
|
|
503
505
|
const jid = normalizeJid(jR);
|
|
504
506
|
if (!jid || !file) { fail('usage: /audio <jid> <file>'); break; }
|
|
505
507
|
out('uploading...');
|
|
506
|
-
|
|
507
|
-
|
|
508
|
+
_client.sendAudio(jid, file, {})
|
|
509
|
+
.then(r => out('sent ' + (r && r.id ? r.id : r)))
|
|
510
|
+
.catch(e => fail('audio error: ' + e.message));
|
|
508
511
|
break;
|
|
509
512
|
}
|
|
510
513
|
|
|
@@ -514,8 +517,9 @@ async function handleLine(line) {
|
|
|
514
517
|
const jid = normalizeJid(jR);
|
|
515
518
|
if (!jid || !file) { fail('usage: /ptt <jid> <file>'); break; }
|
|
516
519
|
out('uploading...');
|
|
517
|
-
|
|
518
|
-
|
|
520
|
+
_client.sendAudio(jid, file, { ptt: true })
|
|
521
|
+
.then(r => out('sent ' + (r && r.id ? r.id : r)))
|
|
522
|
+
.catch(e => fail('ptt error: ' + e.message));
|
|
519
523
|
break;
|
|
520
524
|
}
|
|
521
525
|
|
|
@@ -525,8 +529,9 @@ async function handleLine(line) {
|
|
|
525
529
|
const jid = normalizeJid(jR);
|
|
526
530
|
if (!jid || !file) { fail('usage: /doc <jid> <file> [name]'); break; }
|
|
527
531
|
out('uploading...');
|
|
528
|
-
|
|
529
|
-
|
|
532
|
+
_client.sendDocument(jid, file, { fileName: fname || path.basename(file) })
|
|
533
|
+
.then(r => out('sent ' + (r && r.id ? r.id : r)))
|
|
534
|
+
.catch(e => fail('document error: ' + e.message));
|
|
530
535
|
break;
|
|
531
536
|
}
|
|
532
537
|
|
|
@@ -536,8 +541,9 @@ async function handleLine(line) {
|
|
|
536
541
|
const jid = normalizeJid(jR);
|
|
537
542
|
if (!jid || !file) { fail('usage: /sticker <jid> <file>'); break; }
|
|
538
543
|
out('uploading...');
|
|
539
|
-
|
|
540
|
-
|
|
544
|
+
_client.sendSticker(jid, file, {})
|
|
545
|
+
.then(r => out('sent ' + (r && r.id ? r.id : r)))
|
|
546
|
+
.catch(e => fail('sticker error: ' + e.message));
|
|
541
547
|
break;
|
|
542
548
|
}
|
|
543
549
|
|
|
@@ -546,8 +552,9 @@ async function handleLine(line) {
|
|
|
546
552
|
const [, jR, msgId, emoji] = p;
|
|
547
553
|
const jid = normalizeJid(jR);
|
|
548
554
|
if (!jid || !msgId || !emoji) { fail('usage: /react <jid> <msgId> <emoji>'); break; }
|
|
549
|
-
|
|
550
|
-
|
|
555
|
+
_client.sendReaction(jid, msgId, emoji)
|
|
556
|
+
.then(r => out('sent ' + (r && r.id ? r.id : r)))
|
|
557
|
+
.catch(e => fail('react error: ' + e.message));
|
|
551
558
|
break;
|
|
552
559
|
}
|
|
553
560
|
|
|
@@ -556,8 +563,9 @@ async function handleLine(line) {
|
|
|
556
563
|
const [, jR, msgId, ...rest] = p;
|
|
557
564
|
const jid = normalizeJid(jR);
|
|
558
565
|
if (!jid || !msgId || !rest.length) { fail('usage: /edit <jid> <msgId> <text>'); break; }
|
|
559
|
-
|
|
560
|
-
|
|
566
|
+
_client.editMessage(msgId, jid, rest.join(' '))
|
|
567
|
+
.then(r => out('edited ' + (r && r.id ? r.id : r)))
|
|
568
|
+
.catch(e => fail('edit error: ' + e.message));
|
|
561
569
|
break;
|
|
562
570
|
}
|
|
563
571
|
|
|
@@ -566,8 +574,9 @@ async function handleLine(line) {
|
|
|
566
574
|
const [, jR, msgId, scope] = p;
|
|
567
575
|
const jid = normalizeJid(jR);
|
|
568
576
|
if (!jid || !msgId) { fail('usage: /delete <jid> <msgId> [all]'); break; }
|
|
569
|
-
|
|
570
|
-
|
|
577
|
+
_client.deleteMessage(msgId, jid, true, scope === 'all')
|
|
578
|
+
.then(() => out('deleted ' + (scope === 'all' ? 'for everyone' : 'for me')))
|
|
579
|
+
.catch(e => fail('delete error: ' + e.message));
|
|
571
580
|
break;
|
|
572
581
|
}
|
|
573
582
|
|
package/lib/Client.js
CHANGED
|
@@ -126,6 +126,8 @@ class WhalibmobClient extends EventEmitter {
|
|
|
126
126
|
this._groupMembers = new Map(); // groupJid → Set<memberJid>
|
|
127
127
|
this._lidToPn = new Map(); // LID user → phone number
|
|
128
128
|
this._pnToLid = new Map(); // phone number → LID user
|
|
129
|
+
this._myLid = null; // own LID JID received from <success> node
|
|
130
|
+
this._groupAddressingMode = new Map(); // groupJid → 'lid' | 'pn'
|
|
129
131
|
this._retryPending = new Map(); // msgId → {node, retryCount}
|
|
130
132
|
this._retryPreKeyIdx = 0; // rotating index for assigning unique prekeys to retries
|
|
131
133
|
this._appStateVersions = {}; // collectionName → version (int)
|
|
@@ -281,6 +283,7 @@ class WhalibmobClient extends EventEmitter {
|
|
|
281
283
|
}
|
|
282
284
|
}
|
|
283
285
|
if (attrs.platform) this._platform = attrs.platform;
|
|
286
|
+
if (attrs.lid) this._myLid = String(attrs.lid);
|
|
284
287
|
|
|
285
288
|
const devIdNode = findChild(node, 'device-identity');
|
|
286
289
|
if (devIdNode) {
|
|
@@ -690,12 +693,16 @@ class WhalibmobClient extends EventEmitter {
|
|
|
690
693
|
_processSKDMDistribution(groupJid, senderJid, participantsNode) {
|
|
691
694
|
// For incoming group messages, the SKDM for us is in the participants node
|
|
692
695
|
if (!Array.isArray(participantsNode.content)) return;
|
|
696
|
+
const ownPhone = String(this._store.phoneNumber);
|
|
697
|
+
const ownLidUser = this._myLid ? this._myLid.split('@')[0].split(':')[0] : null;
|
|
693
698
|
for (const toNode of participantsNode.content) {
|
|
694
699
|
if (!toNode || toNode.description !== 'to') continue;
|
|
695
700
|
const toJid = toNode.attrs && toNode.attrs.jid;
|
|
696
701
|
if (!toJid) continue;
|
|
697
|
-
const
|
|
698
|
-
|
|
702
|
+
const toUser = String(toJid).split('@')[0].split(':')[0];
|
|
703
|
+
// Match by phone number (PN-mode groups) OR by own LID user (LID-mode groups)
|
|
704
|
+
const isForUs = (toUser === ownPhone) || (ownLidUser && toUser === ownLidUser);
|
|
705
|
+
if (!isForUs) continue;
|
|
699
706
|
|
|
700
707
|
const enc = findChild(toNode, 'enc');
|
|
701
708
|
if (!enc) continue;
|
|
@@ -1165,12 +1172,33 @@ class WhalibmobClient extends EventEmitter {
|
|
|
1165
1172
|
const children = Array.isArray(groupNode.content) ? groupNode.content : [];
|
|
1166
1173
|
|
|
1167
1174
|
// participants — normalize jid to string (BinaryNode may yield an object)
|
|
1175
|
+
// Also parse phone_number and lid attributes used for LID↔PN mapping
|
|
1168
1176
|
const participants = children
|
|
1169
1177
|
.filter(n => n && n.description === 'participant' && n.attrs && n.attrs.jid)
|
|
1170
|
-
.map(n =>
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1178
|
+
.map(n => {
|
|
1179
|
+
const pJid = String(n.attrs.jid);
|
|
1180
|
+
const pRole = n.attrs.type || 'member';
|
|
1181
|
+
const pPhone = n.attrs.phone_number ? String(n.attrs.phone_number) : null;
|
|
1182
|
+
const pLid = n.attrs.lid ? String(n.attrs.lid) : null;
|
|
1183
|
+
// Populate LID↔PN maps from participant attributes
|
|
1184
|
+
// Case A: participant JID is a LID, phone_number is their PN
|
|
1185
|
+
if (pJid.endsWith('@lid') || pJid.includes('@lid:')) {
|
|
1186
|
+
const lidUser = pJid.split('@')[0].split(':')[0];
|
|
1187
|
+
if (pPhone) {
|
|
1188
|
+
const pnUser = pPhone.split('@')[0].split(':')[0];
|
|
1189
|
+
this._lidToPn.set(lidUser, pnUser);
|
|
1190
|
+
this._pnToLid.set(pnUser, lidUser);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
// Case B: participant JID is a PN, lid attribute is their LID
|
|
1194
|
+
if (pLid && (pLid.endsWith('@lid') || pLid.includes('@lid:'))) {
|
|
1195
|
+
const pnUser = pJid.split('@')[0].split(':')[0];
|
|
1196
|
+
const lidUser = pLid.split('@')[0].split(':')[0];
|
|
1197
|
+
this._lidToPn.set(lidUser, pnUser);
|
|
1198
|
+
this._pnToLid.set(pnUser, lidUser);
|
|
1199
|
+
}
|
|
1200
|
+
return { jid: pJid, role: pRole };
|
|
1201
|
+
});
|
|
1174
1202
|
|
|
1175
1203
|
// description
|
|
1176
1204
|
const descNode = children.find(n => n && n.description === 'description');
|
|
@@ -1197,8 +1225,12 @@ class WhalibmobClient extends EventEmitter {
|
|
|
1197
1225
|
const groupId = a.id || '';
|
|
1198
1226
|
const jid = groupId.includes('@') ? groupId : groupId + '@g.us';
|
|
1199
1227
|
|
|
1200
|
-
//
|
|
1228
|
+
// addressing_mode: 'lid' (modern groups) or 'pn' (legacy groups)
|
|
1229
|
+
const addressingMode = (a.addressing_mode === 'pn') ? 'pn' : 'lid';
|
|
1230
|
+
|
|
1231
|
+
// update member cache and addressing mode
|
|
1201
1232
|
this._groupMembers.set(jid, new Set(participants.map(p => p.jid)));
|
|
1233
|
+
this._groupAddressingMode.set(jid, addressingMode);
|
|
1202
1234
|
|
|
1203
1235
|
return {
|
|
1204
1236
|
jid,
|
|
@@ -1211,6 +1243,7 @@ class WhalibmobClient extends EventEmitter {
|
|
|
1211
1243
|
ephemeral,
|
|
1212
1244
|
onlyAdminsSend: announce,
|
|
1213
1245
|
onlyAdminsEdit: restrict,
|
|
1246
|
+
addressingMode,
|
|
1214
1247
|
participants
|
|
1215
1248
|
};
|
|
1216
1249
|
}
|
|
@@ -627,7 +627,15 @@ class MessageSender {
|
|
|
627
627
|
members = this._client._getGroupMembers(groupJid);
|
|
628
628
|
} catch (_) {}
|
|
629
629
|
}
|
|
630
|
-
|
|
630
|
+
|
|
631
|
+
// Determine addressing mode for this group (lid = modern groups, pn = legacy)
|
|
632
|
+
const groupAddressingMode = this._client._groupAddressingMode.get(groupJid) || 'lid';
|
|
633
|
+
// For LID-mode groups, sender identity is own LID JID; otherwise own PN JID
|
|
634
|
+
const senderIdentity = (groupAddressingMode === 'lid' && this._client._myLid)
|
|
635
|
+
? this._client._myLid
|
|
636
|
+
: ownJid;
|
|
637
|
+
|
|
638
|
+
const rawSKDM = this._signal.buildSKDM(groupJid, senderIdentity);
|
|
631
639
|
const skdmMsg = encodeSenderKeyDistributionMessage(groupJid, rawSKDM);
|
|
632
640
|
|
|
633
641
|
const memberPhones = [...new Set(
|
|
@@ -664,7 +672,7 @@ class MessageSender {
|
|
|
664
672
|
skStore.markSKDMSent(groupJid, skdmRecipients);
|
|
665
673
|
}
|
|
666
674
|
|
|
667
|
-
const skmsgCiphertext = this._signal.senderKeyEncrypt(groupJid,
|
|
675
|
+
const skmsgCiphertext = this._signal.senderKeyEncrypt(groupJid, senderIdentity, plaintext);
|
|
668
676
|
const phash = phashTargets.length > 0 ? computePhash(phashTargets) : null;
|
|
669
677
|
|
|
670
678
|
const skdmHasPkmsg = skdmEncrypted.some(e => e.type === 'pkmsg');
|
|
@@ -685,7 +693,7 @@ class MessageSender {
|
|
|
685
693
|
to: groupJid,
|
|
686
694
|
id: msgId,
|
|
687
695
|
type: mediaType,
|
|
688
|
-
addressing_mode:
|
|
696
|
+
addressing_mode: groupAddressingMode,
|
|
689
697
|
t: String(msNow())
|
|
690
698
|
};
|
|
691
699
|
if (phash) stanzaAttrs.phash = phash;
|