whalibmob 3.0.0 → 3.3.1
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/DeviceManager.js +9 -0
- package/lib/Registration.js +1 -1
- package/lib/Store.js +3 -2
- package/lib/messages/MessageSender.js +34 -5
- package/lib/noise.js +1 -1
- package/lib/proto.js +1 -1
- package/package.json +1 -1
package/lib/DeviceManager.js
CHANGED
|
@@ -224,6 +224,15 @@ class DeviceManager {
|
|
|
224
224
|
return readyJids;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
// ─── Clear device cache (used on phash mismatch / 421 retry) ──────────────
|
|
228
|
+
clearCache(phones) {
|
|
229
|
+
if (!phones || phones.length === 0) {
|
|
230
|
+
this._deviceCache.clear();
|
|
231
|
+
} else {
|
|
232
|
+
for (const p of phones) this._deviceCache.delete(p);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
227
236
|
// ─── Build participants node ───────────────────────────────────────────────
|
|
228
237
|
static buildParticipantsNode(encryptedList) {
|
|
229
238
|
const toNodes = encryptedList.map(({ jid, type, ciphertext }) =>
|
package/lib/Registration.js
CHANGED
|
@@ -242,7 +242,7 @@ function buildPayload(store, waVersion, useToken, extraPairs) {
|
|
|
242
242
|
'rc', String(RELEASE_CHANNEL),
|
|
243
243
|
'lg', meta.lg,
|
|
244
244
|
'lc', meta.lc,
|
|
245
|
-
'authkey', store.noiseKeyPair.public.toString('base64url'),
|
|
245
|
+
'authkey', rawKey(store.noiseKeyPair.public).toString('base64url'),
|
|
246
246
|
'e_regid', intToBytes(store.registrationId, 4).toString('base64url'),
|
|
247
247
|
'e_keytype', Buffer.from([SIGNAL_KEY_TYPE]).toString('base64url'),
|
|
248
248
|
'e_ident', rawKey(store.identityKeyPair.public).toString('base64url'),
|
package/lib/Store.js
CHANGED
|
@@ -200,14 +200,15 @@ function fromSixParts(sixParts) {
|
|
|
200
200
|
private: spkPair.private,
|
|
201
201
|
signature: sig
|
|
202
202
|
},
|
|
203
|
-
registrationId: 1,
|
|
203
|
+
registrationId: (crypto.randomBytes(2).readUInt16BE(0) & 0x3fff) + 1,
|
|
204
204
|
fdid: uuidv4(),
|
|
205
205
|
deviceId: crypto.randomBytes(16),
|
|
206
206
|
identityId,
|
|
207
207
|
registered: true,
|
|
208
208
|
name: 'User',
|
|
209
209
|
version: IOS_VERSION_FALLBACK,
|
|
210
|
-
device: IOS_DEVICE
|
|
210
|
+
device: IOS_DEVICE,
|
|
211
|
+
advIdentity: null
|
|
211
212
|
};
|
|
212
213
|
}
|
|
213
214
|
|
|
@@ -281,7 +281,7 @@ class MessageSender {
|
|
|
281
281
|
isAnimated: options.isAnimated || false,
|
|
282
282
|
contextInfo: options.contextInfo
|
|
283
283
|
}));
|
|
284
|
-
return this._sendMessage(toJid, msgId, stkBuf, '
|
|
284
|
+
return this._sendMessage(toJid, msgId, stkBuf, 'media', options);
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
// ─── Reaction ─────────────────────────────────────────────────────────────
|
|
@@ -302,9 +302,31 @@ class MessageSender {
|
|
|
302
302
|
|
|
303
303
|
async _sendMessage(toJid, msgId, plaintext, mediaType, options) {
|
|
304
304
|
if (isGroupJid(toJid)) {
|
|
305
|
-
|
|
305
|
+
try {
|
|
306
|
+
return await this._sendGroupMessage(toJid, msgId, plaintext, mediaType);
|
|
307
|
+
} catch (err) {
|
|
308
|
+
// Error 421 = phash mismatch — server's participant list differs from ours.
|
|
309
|
+
// Flush device cache for group members and retry once (matches Cobalt behaviour).
|
|
310
|
+
if (err && /\b421\b/.test(err.message)) {
|
|
311
|
+
const members = this._client._getGroupMembers
|
|
312
|
+
? this._client._getGroupMembers(toJid)
|
|
313
|
+
: [];
|
|
314
|
+
this._devMgr.clearCache(members.map(phoneFromJid));
|
|
315
|
+
return this._sendGroupMessage(toJid, msgId, plaintext, mediaType);
|
|
316
|
+
}
|
|
317
|
+
throw err;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
return await this._sendDMMessage(toJid, msgId, plaintext, mediaType);
|
|
322
|
+
} catch (err) {
|
|
323
|
+
// Same phash-mismatch retry for 1-to-1 messages.
|
|
324
|
+
if (err && /\b421\b/.test(err.message)) {
|
|
325
|
+
this._devMgr.clearCache([phoneFromJid(toJid)]);
|
|
326
|
+
return this._sendDMMessage(toJid, msgId, plaintext, mediaType);
|
|
327
|
+
}
|
|
328
|
+
throw err;
|
|
306
329
|
}
|
|
307
|
-
return this._sendDMMessage(toJid, msgId, plaintext, mediaType);
|
|
308
330
|
}
|
|
309
331
|
|
|
310
332
|
// ─── 1-to-1 multi-device fanout ───────────────────────────────────────────
|
|
@@ -403,6 +425,13 @@ class MessageSender {
|
|
|
403
425
|
|
|
404
426
|
const allTargets = [...memberDevices, ...ownDevices];
|
|
405
427
|
|
|
428
|
+
// phash MUST include the sender's own primary device.
|
|
429
|
+
// Cobalt's calculateGroupPhash() explicitly adds senderDevice to the set.
|
|
430
|
+
// ownDevices contains only linked devices (device != 0); ownJid is device 0.
|
|
431
|
+
const phashTargets = allTargets.includes(ownJid)
|
|
432
|
+
? allTargets
|
|
433
|
+
: [ownJid, ...allTargets];
|
|
434
|
+
|
|
406
435
|
// senderKeyMap: only send SKDM to devices that haven't received it yet.
|
|
407
436
|
// Persisted in .sk.json so we don't re-send on every group message.
|
|
408
437
|
const skStore = this._signal.senderKeyStore;
|
|
@@ -418,8 +447,8 @@ class MessageSender {
|
|
|
418
447
|
// SenderKey encrypt the actual group message (one ciphertext for all)
|
|
419
448
|
const skmsgCiphertext = this._signal.senderKeyEncrypt(groupJid, ownJid, plaintext);
|
|
420
449
|
|
|
421
|
-
// phash over all group member devices
|
|
422
|
-
const phash =
|
|
450
|
+
// phash over all group member devices + sender primary device
|
|
451
|
+
const phash = phashTargets.length > 0 ? computePhash(phashTargets) : null;
|
|
423
452
|
|
|
424
453
|
// ── Feature 2: device_identity for pkmsg in SKDM ─────────────────────────
|
|
425
454
|
// SKDM messages sent to devices with no prior Signal session are pkmsg.
|
package/lib/noise.js
CHANGED
|
@@ -285,7 +285,7 @@ class NoiseSocket extends EventEmitter {
|
|
|
285
285
|
const payload = encodeClientPayload({
|
|
286
286
|
username: BigInt(this.store.phoneNumber),
|
|
287
287
|
passive: false,
|
|
288
|
-
pushName: this.store.name ||
|
|
288
|
+
pushName: this.store.registered ? (this.store.name || null) : null,
|
|
289
289
|
shortConnect: true,
|
|
290
290
|
connectType: 1,
|
|
291
291
|
connectReason: 1,
|
package/lib/proto.js
CHANGED
|
@@ -43,7 +43,7 @@ function encodeUserAgent({ platform, version, mcc, mnc, osVersion, manufacturer,
|
|
|
43
43
|
];
|
|
44
44
|
if (osVersion) parts.push(field(5, LEN, string(osVersion)));
|
|
45
45
|
if (manufacturer) parts.push(field(6, LEN, string(manufacturer)));
|
|
46
|
-
if (device) parts.push(field(7, LEN, string(device)));
|
|
46
|
+
if (device) parts.push(field(7, LEN, string(String(device).replace(/_/g, ' '))));
|
|
47
47
|
if (osBuildNumber) parts.push(field(8, LEN, string(osBuildNumber)));
|
|
48
48
|
if (phoneId) parts.push(field(9, LEN, string(phoneId)));
|
|
49
49
|
parts.push(field(10, VARINT, varint(releaseChannel || 0)));
|