whalibmob 5.1.12 → 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 +67 -11
- package/lib/messages/MessageSender.js +45 -10
- package/lib/proto/MessageProto.js +9 -0
- 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
|
@@ -125,6 +125,9 @@ 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
|
|
129
|
+
this._myLid = null; // own LID JID received from <success> node
|
|
130
|
+
this._groupAddressingMode = new Map(); // groupJid → 'lid' | 'pn'
|
|
128
131
|
this._retryPending = new Map(); // msgId → {node, retryCount}
|
|
129
132
|
this._retryPreKeyIdx = 0; // rotating index for assigning unique prekeys to retries
|
|
130
133
|
this._appStateVersions = {}; // collectionName → version (int)
|
|
@@ -280,6 +283,7 @@ class WhalibmobClient extends EventEmitter {
|
|
|
280
283
|
}
|
|
281
284
|
}
|
|
282
285
|
if (attrs.platform) this._platform = attrs.platform;
|
|
286
|
+
if (attrs.lid) this._myLid = String(attrs.lid);
|
|
283
287
|
|
|
284
288
|
const devIdNode = findChild(node, 'device-identity');
|
|
285
289
|
if (devIdNode) {
|
|
@@ -523,7 +527,7 @@ class WhalibmobClient extends EventEmitter {
|
|
|
523
527
|
const participant = String(attrs.participant || from);
|
|
524
528
|
// sender_pn is the real phone-based JID when `from` is a LID (linked identity)
|
|
525
529
|
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); }
|
|
530
|
+
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
531
|
// Debug: log every incoming message node
|
|
528
532
|
process.stderr.write('[DBG] _handleMessage from=' + from + ' participant=' + participant + ' senderPn=' + senderPn + ' id=' + id + '\n');
|
|
529
533
|
// Debug: log message content structure
|
|
@@ -689,12 +693,16 @@ class WhalibmobClient extends EventEmitter {
|
|
|
689
693
|
_processSKDMDistribution(groupJid, senderJid, participantsNode) {
|
|
690
694
|
// For incoming group messages, the SKDM for us is in the participants node
|
|
691
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;
|
|
692
698
|
for (const toNode of participantsNode.content) {
|
|
693
699
|
if (!toNode || toNode.description !== 'to') continue;
|
|
694
700
|
const toJid = toNode.attrs && toNode.attrs.jid;
|
|
695
701
|
if (!toJid) continue;
|
|
696
|
-
const
|
|
697
|
-
|
|
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;
|
|
698
706
|
|
|
699
707
|
const enc = findChild(toNode, 'enc');
|
|
700
708
|
if (!enc) continue;
|
|
@@ -702,10 +710,20 @@ class WhalibmobClient extends EventEmitter {
|
|
|
702
710
|
const encType = enc.attrs && enc.attrs.type;
|
|
703
711
|
const cipherBuf = Buffer.isBuffer(enc.content) ? enc.content : Buffer.from(enc.content || '');
|
|
704
712
|
|
|
705
|
-
// Decrypt SKDM with our Signal session
|
|
713
|
+
// Decrypt SKDM with our Signal session, then parse the WA Message proto
|
|
714
|
+
// to extract the actual axolotl SKDM bytes from field 35
|
|
706
715
|
this._signal.decrypt(senderJid, encType, cipherBuf)
|
|
707
|
-
.then(
|
|
708
|
-
this.
|
|
716
|
+
.then(decrypted => {
|
|
717
|
+
const decoded = this._decodeMsg(decrypted);
|
|
718
|
+
if (decoded && decoded.type === 'senderKeyDistribution' &&
|
|
719
|
+
decoded.groupId && decoded.axolotlBytes &&
|
|
720
|
+
decoded.axolotlBytes[0] === 0x33) {
|
|
721
|
+
this._signal.processSKDM(decoded.groupId, senderJid, decoded.axolotlBytes);
|
|
722
|
+
} else if (decoded && decoded.skdm &&
|
|
723
|
+
decoded.skdm.groupId && decoded.skdm.axolotlBytes &&
|
|
724
|
+
decoded.skdm.axolotlBytes[0] === 0x33) {
|
|
725
|
+
this._signal.processSKDM(decoded.skdm.groupId, senderJid, decoded.skdm.axolotlBytes);
|
|
726
|
+
}
|
|
709
727
|
})
|
|
710
728
|
.catch(() => {});
|
|
711
729
|
}
|
|
@@ -1154,12 +1172,33 @@ class WhalibmobClient extends EventEmitter {
|
|
|
1154
1172
|
const children = Array.isArray(groupNode.content) ? groupNode.content : [];
|
|
1155
1173
|
|
|
1156
1174
|
// participants — normalize jid to string (BinaryNode may yield an object)
|
|
1175
|
+
// Also parse phone_number and lid attributes used for LID↔PN mapping
|
|
1157
1176
|
const participants = children
|
|
1158
1177
|
.filter(n => n && n.description === 'participant' && n.attrs && n.attrs.jid)
|
|
1159
|
-
.map(n =>
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
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
|
+
});
|
|
1163
1202
|
|
|
1164
1203
|
// description
|
|
1165
1204
|
const descNode = children.find(n => n && n.description === 'description');
|
|
@@ -1186,8 +1225,12 @@ class WhalibmobClient extends EventEmitter {
|
|
|
1186
1225
|
const groupId = a.id || '';
|
|
1187
1226
|
const jid = groupId.includes('@') ? groupId : groupId + '@g.us';
|
|
1188
1227
|
|
|
1189
|
-
//
|
|
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
|
|
1190
1232
|
this._groupMembers.set(jid, new Set(participants.map(p => p.jid)));
|
|
1233
|
+
this._groupAddressingMode.set(jid, addressingMode);
|
|
1191
1234
|
|
|
1192
1235
|
return {
|
|
1193
1236
|
jid,
|
|
@@ -1200,6 +1243,7 @@ class WhalibmobClient extends EventEmitter {
|
|
|
1200
1243
|
ephemeral,
|
|
1201
1244
|
onlyAdminsSend: announce,
|
|
1202
1245
|
onlyAdminsEdit: restrict,
|
|
1246
|
+
addressingMode,
|
|
1203
1247
|
participants
|
|
1204
1248
|
};
|
|
1205
1249
|
}
|
|
@@ -1266,6 +1310,18 @@ class WhalibmobClient extends EventEmitter {
|
|
|
1266
1310
|
return meta ? meta.participants : [];
|
|
1267
1311
|
}
|
|
1268
1312
|
|
|
1313
|
+
getPNForLID(lid) {
|
|
1314
|
+
const lidUser = String(lid).split('@')[0].split(':')[0];
|
|
1315
|
+
const pnUser = this._lidToPn.get(lidUser);
|
|
1316
|
+
return pnUser ? pnUser + '@s.whatsapp.net' : null;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
getLIDForPN(pn) {
|
|
1320
|
+
const pnUser = String(pn).split('@')[0].split(':')[0];
|
|
1321
|
+
const lidUser = this._pnToLid.get(pnUser);
|
|
1322
|
+
return lidUser ? lidUser + '@lid' : null;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1269
1325
|
// ─── Message ID generator ─────────────────────────────────────────────────
|
|
1270
1326
|
|
|
1271
1327
|
_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,26 @@ class MessageSender {
|
|
|
626
627
|
members = this._client._getGroupMembers(groupJid);
|
|
627
628
|
} catch (_) {}
|
|
628
629
|
}
|
|
629
|
-
|
|
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);
|
|
639
|
+
const skdmMsg = encodeSenderKeyDistributionMessage(groupJid, rawSKDM);
|
|
630
640
|
|
|
631
641
|
const memberPhones = [...new Set(
|
|
632
|
-
members.map(jid => {
|
|
642
|
+
members.map(jid => {
|
|
643
|
+
const isLid = jid.endsWith('@lid') || jid.includes('@lid:') || jid.includes(':@lid');
|
|
644
|
+
const raw = phoneFromJid(jid);
|
|
645
|
+
if (isLid && this._client._lidToPn && this._client._lidToPn.has(raw)) {
|
|
646
|
+
return this._client._lidToPn.get(raw);
|
|
647
|
+
}
|
|
648
|
+
return raw;
|
|
649
|
+
}).filter(p => p !== ownPhone)
|
|
633
650
|
)];
|
|
634
651
|
|
|
635
652
|
const [memberDevices, ownDevices] = await Promise.all([
|
|
@@ -645,18 +662,17 @@ class MessageSender {
|
|
|
645
662
|
? allTargets
|
|
646
663
|
: [ownJid, ...allTargets];
|
|
647
664
|
|
|
648
|
-
const skStore
|
|
649
|
-
skStore.
|
|
650
|
-
const
|
|
651
|
-
const skdmRecipients = allTargets;
|
|
665
|
+
const skStore = this._signal.senderKeyStore;
|
|
666
|
+
const existingSkdmMap = skStore.getSKDMMap(groupJid);
|
|
667
|
+
const skdmRecipients = allTargets.filter(jid => !existingSkdmMap[jid]);
|
|
652
668
|
|
|
653
669
|
let skdmEncrypted = [];
|
|
654
670
|
if (skdmRecipients.length > 0) {
|
|
655
|
-
skdmEncrypted = await this._signal.bulkEncryptForDevices(skdmRecipients,
|
|
671
|
+
skdmEncrypted = await this._signal.bulkEncryptForDevices(skdmRecipients, skdmMsg);
|
|
656
672
|
skStore.markSKDMSent(groupJid, skdmRecipients);
|
|
657
673
|
}
|
|
658
674
|
|
|
659
|
-
const skmsgCiphertext = this._signal.senderKeyEncrypt(groupJid,
|
|
675
|
+
const skmsgCiphertext = this._signal.senderKeyEncrypt(groupJid, senderIdentity, plaintext);
|
|
660
676
|
const phash = phashTargets.length > 0 ? computePhash(phashTargets) : null;
|
|
661
677
|
|
|
662
678
|
const skdmHasPkmsg = skdmEncrypted.some(e => e.type === 'pkmsg');
|
|
@@ -677,7 +693,7 @@ class MessageSender {
|
|
|
677
693
|
to: groupJid,
|
|
678
694
|
id: msgId,
|
|
679
695
|
type: mediaType,
|
|
680
|
-
addressing_mode:
|
|
696
|
+
addressing_mode: groupAddressingMode,
|
|
681
697
|
t: String(msNow())
|
|
682
698
|
};
|
|
683
699
|
if (phash) stanzaAttrs.phash = phash;
|
|
@@ -809,7 +825,7 @@ class MessageSender {
|
|
|
809
825
|
|
|
810
826
|
async _uploadMedia(mediaType, data) {
|
|
811
827
|
if (!this._mediaHosts.length) {
|
|
812
|
-
|
|
828
|
+
await this._fetchMediaConn();
|
|
813
829
|
}
|
|
814
830
|
let buf;
|
|
815
831
|
if (Buffer.isBuffer(data)) buf = data;
|
|
@@ -817,6 +833,25 @@ class MessageSender {
|
|
|
817
833
|
else throw new Error('Media must be a Buffer or file path');
|
|
818
834
|
return uploadMedia(mediaType, buf, this._mediaHosts, this._mediaAuth);
|
|
819
835
|
}
|
|
836
|
+
|
|
837
|
+
async _fetchMediaConn() {
|
|
838
|
+
return new Promise((resolve, reject) => {
|
|
839
|
+
const timeout = setTimeout(() => {
|
|
840
|
+
this._client.removeListener('media_conn', onConn);
|
|
841
|
+
reject(new Error('Timeout waiting for media connection'));
|
|
842
|
+
}, 15000);
|
|
843
|
+
const onConn = ({ hosts, auth }) => {
|
|
844
|
+
clearTimeout(timeout);
|
|
845
|
+
if (hosts && hosts.length) {
|
|
846
|
+
this._mediaHosts = hosts;
|
|
847
|
+
this._mediaAuth = auth;
|
|
848
|
+
}
|
|
849
|
+
resolve();
|
|
850
|
+
};
|
|
851
|
+
this._client.once('media_conn', onConn);
|
|
852
|
+
try { this._client._requestMediaConnection(); } catch (_) {}
|
|
853
|
+
});
|
|
854
|
+
}
|
|
820
855
|
}
|
|
821
856
|
|
|
822
857
|
// ─── 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,
|