whalibmob 5.5.37 → 5.5.39
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/README.md +6 -0
- package/lib/DeviceManager.js +27 -3
- package/lib/messages/MessageSender.js +83 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
##
|
|
5
5
|
|
|
6
|
+
> [!IMPORTANT]
|
|
7
|
+
> new repository whalibmob It will be maintained at the https://github.com/Kunboruto50/whalibmob.git Since I lost the Kunboruto20 account, whalibmob will be maintained and rewritten by me soon because I know that many functions in whalibmob no longer work after the WhatsApp mobile protocol change, these days I will take care of whalibmob, all good friends Fun enjoyable for all c
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
6
12
|
> [!CAUTION]
|
|
7
13
|
> Use a dedicated phone number with this library. Connecting with a number that is already active on a real device will cause WhatsApp to log that device out.
|
|
8
14
|
|
package/lib/DeviceManager.js
CHANGED
|
@@ -43,7 +43,14 @@ function jidStrToObj(jidStr) {
|
|
|
43
43
|
if (server === 's.whatsapp.net' && device > 0) {
|
|
44
44
|
return { user, agent: 0, device, server, toString() { return self; } };
|
|
45
45
|
}
|
|
46
|
-
//
|
|
46
|
+
// @lid multi-device (e.g. "112713111982325:2@lid"): JID_PAIR with user="112713111982325:2"
|
|
47
|
+
// so the server receives the colon-device in the user string, not stripped.
|
|
48
|
+
// Without this, ":2@lid" is encoded as device-0 "@lid" and the server
|
|
49
|
+
// returns the wrong bundle (or ignores device 2 entirely).
|
|
50
|
+
if (server === 'lid' && device > 0) {
|
|
51
|
+
return { user: raw, server, toString() { return self; } };
|
|
52
|
+
}
|
|
53
|
+
// JID_PAIR: used for @lid device-0, @g.us, and primary (device-0) @s.whatsapp.net
|
|
47
54
|
return { user, server, toString() { return self; } };
|
|
48
55
|
}
|
|
49
56
|
|
|
@@ -682,8 +689,25 @@ class DeviceManager {
|
|
|
682
689
|
for (const [jid, bundle] of bundles) {
|
|
683
690
|
try {
|
|
684
691
|
await signalProto.buildSessionFromBundle(jid, bundle);
|
|
685
|
-
|
|
686
|
-
|
|
692
|
+
// ── CRITICAL: remap bundle JID back to @lid format ────────────────────
|
|
693
|
+
// fetchBundles always returns JIDs in @s.whatsapp.net format (because the
|
|
694
|
+
// WA server uses its own AD_JID / JID_PAIR encoding in responses).
|
|
695
|
+
// But the outer <message to="lidUser@lid"> requires ALL participant <to>
|
|
696
|
+
// nodes to also use @lid format — mixing @s.whatsapp.net participants with
|
|
697
|
+
// a @lid routing address causes the server to close the connection.
|
|
698
|
+
//
|
|
699
|
+
// The Signal session address is keyed only by (user, device) — the @server
|
|
700
|
+
// suffix is stripped by jidToAddress() — so the session is reachable via
|
|
701
|
+
// either @lid or @s.whatsapp.net. We push the @lid form so the participants
|
|
702
|
+
// node is consistent with the routing.
|
|
703
|
+
//
|
|
704
|
+
// Mapping: strip @s.whatsapp.net / @lid suffix from jid, re-append @lid
|
|
705
|
+
// e.g. "112713111982325@s.whatsapp.net" → "112713111982325@lid"
|
|
706
|
+
// "112713111982325:2@s.whatsapp.net" → "112713111982325:2@lid"
|
|
707
|
+
const jidBase = jid.replace(/@(?:s\.whatsapp\.net|lid)$/, '');
|
|
708
|
+
const lidJidForDevice = jidBase + '@lid';
|
|
709
|
+
readyJids.push(lidJidForDevice);
|
|
710
|
+
_whaDbg('[DBG] LID_SESSION_BUILT jid=' + jid + ' → participant=' + lidJidForDevice);
|
|
687
711
|
} catch (e) {
|
|
688
712
|
_whaDbg('[DBG] LID_SESSION_ERR jid=' + jid + ' err=' + e.message);
|
|
689
713
|
}
|
|
@@ -534,6 +534,18 @@ class MessageSender {
|
|
|
534
534
|
this._devMgr.clearCache(members.map(phoneFromJid));
|
|
535
535
|
return this._sendGroupMessage(toJid, msgId, plaintext, mediaType, options);
|
|
536
536
|
}
|
|
537
|
+
// Error 479 = stale/dead Signal session — clear all sessions for every
|
|
538
|
+
// group member, flush device cache, rebuild from fresh bundles, retry once.
|
|
539
|
+
if (err && /\b479\b/.test(err.message) && !options._479retry) {
|
|
540
|
+
_whaDbg('[DBG] 479_GROUP clearing sessions for group ' + toJid);
|
|
541
|
+
const members = this._client._getGroupMembers
|
|
542
|
+
? this._client._getGroupMembers(toJid) : [];
|
|
543
|
+
for (const memberJid of members) {
|
|
544
|
+
await this._clearSignalSessionsForRecipient(phoneFromJid(memberJid)).catch(() => {});
|
|
545
|
+
}
|
|
546
|
+
return this._sendGroupMessage(toJid, msgId, plaintext, mediaType,
|
|
547
|
+
Object.assign({}, options, { _479retry: true }));
|
|
548
|
+
}
|
|
537
549
|
throw err;
|
|
538
550
|
}
|
|
539
551
|
}
|
|
@@ -545,10 +557,81 @@ class MessageSender {
|
|
|
545
557
|
this._devMgr.clearCache([phoneFromJid(toJid)]);
|
|
546
558
|
return this._sendDMMessage(toJid, msgId, plaintext, mediaType, options);
|
|
547
559
|
}
|
|
560
|
+
// ── Error 479: stale / dead Signal session ────────────────────────────────
|
|
561
|
+
// The server rejected the ciphertext because it was encrypted with a Signal
|
|
562
|
+
// session key the server no longer recognises (recipient re-installed WA,
|
|
563
|
+
// changed device, or their prekey was exhausted / revoked).
|
|
564
|
+
//
|
|
565
|
+
// Recovery:
|
|
566
|
+
// 1. Delete all cached Signal sessions for this recipient (PN + LID).
|
|
567
|
+
// 2. Flush device-ID cache → forces a fresh usync IQ on next send.
|
|
568
|
+
// 3. Re-call _sendDMMessage → re-runs usync + fetchBundles + buildSession
|
|
569
|
+
// + re-encrypts with a fresh PreKey message (pkmsg).
|
|
570
|
+
//
|
|
571
|
+
// _479retry flag prevents infinite loops: if the fresh session also gets
|
|
572
|
+
// 479 (extremely rare — server bug or banned account) we fail cleanly.
|
|
573
|
+
if (err && /\b479\b/.test(err.message) && !options._479retry) {
|
|
574
|
+
await this._clearSignalSessionsForRecipient(phoneFromJid(toJid));
|
|
575
|
+
// CRITICAL: generate a NEW msgId — the server already ACK'd (with error=479)
|
|
576
|
+
// the original ID and will close the connection if we re-send the same ID.
|
|
577
|
+
const retryMsgId = generateMessageId();
|
|
578
|
+
_whaDbg('[DBG] 479_RETRY new msgId=' + retryMsgId);
|
|
579
|
+
return this._sendDMMessage(toJid, retryMsgId, plaintext, mediaType,
|
|
580
|
+
Object.assign({}, options, { _479retry: true }));
|
|
581
|
+
}
|
|
582
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
548
583
|
throw err;
|
|
549
584
|
}
|
|
550
585
|
}
|
|
551
586
|
|
|
587
|
+
// ─── Clear all Signal sessions for a phone-number recipient ─────────────────
|
|
588
|
+
//
|
|
589
|
+
// Called on error 479 (stale session). Deletes:
|
|
590
|
+
// • All Signal sessions keyed by phone-number device JIDs (e.g. 40756469325:0)
|
|
591
|
+
// • The corresponding LID device session if a LID mapping is known
|
|
592
|
+
//
|
|
593
|
+
// Then flushes the device-ID cache for that phone so the next send re-runs
|
|
594
|
+
// usync (gets current device list) and re-fetches fresh prekey bundles.
|
|
595
|
+
async _clearSignalSessionsForRecipient(phone) {
|
|
596
|
+
_whaDbg('[DBG] 479_RECOVERY phone=' + phone + ' — clearing sessions + device cache');
|
|
597
|
+
const signal = this._signal;
|
|
598
|
+
const devMgr = this._devMgr;
|
|
599
|
+
const client = this._client;
|
|
600
|
+
|
|
601
|
+
// ── 1. Get all known device JIDs for this phone (from cache) ──────────────
|
|
602
|
+
const devJids = devMgr._jidsFromCache([phone]);
|
|
603
|
+
for (const jid of devJids) {
|
|
604
|
+
try {
|
|
605
|
+
await signal.deleteSession(jid);
|
|
606
|
+
_whaDbg('[DBG] 479_DEL_SESSION jid=' + jid);
|
|
607
|
+
} catch (_) {}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// ── 2. Clear LID session if we have a LID mapping for this phone ──────────
|
|
611
|
+
// NOTE: LID JIDs use @lid server, NOT @s.whatsapp.net. Cannot use
|
|
612
|
+
// _jidsFromCache() (it hard-codes @s.whatsapp.net) — build JIDs manually.
|
|
613
|
+
const lidUser = client._pnToLid && client._pnToLid.get(phone);
|
|
614
|
+
if (lidUser) {
|
|
615
|
+
// Get all device IDs for this LID from cache (or assume device 0 primary)
|
|
616
|
+
const lidDeviceIds = (devMgr._dcGet && devMgr._dcGet('lid:' + lidUser)) || [0];
|
|
617
|
+
for (const devId of lidDeviceIds) {
|
|
618
|
+
const jid = (devId === 0) ? `${lidUser}@lid` : `${lidUser}:${devId}@lid`;
|
|
619
|
+
try {
|
|
620
|
+
await signal.deleteSession(jid);
|
|
621
|
+
_whaDbg('[DBG] 479_DEL_LID_SESSION jid=' + jid);
|
|
622
|
+
} catch (_) {}
|
|
623
|
+
}
|
|
624
|
+
// Always delete the bare primary JID too (in case it was stored without device suffix)
|
|
625
|
+
try { await signal.deleteSession(`${lidUser}@lid`); } catch (_) {}
|
|
626
|
+
// Flush LID device-ID cache so next send re-runs usync for LID
|
|
627
|
+
devMgr.clearCache(['lid:' + lidUser]);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// ── 3. Flush phone device cache → usync re-runs on next send ──────────────
|
|
631
|
+
devMgr.clearCache([phone]);
|
|
632
|
+
_whaDbg('[DBG] 479_CACHE_FLUSHED phone=' + phone);
|
|
633
|
+
}
|
|
634
|
+
|
|
552
635
|
// ─── 1-to-1 multi-device fanout ───────────────────────────────────────────
|
|
553
636
|
|
|
554
637
|
async _sendDMMessage(toJid, msgId, plaintext, mediaType, options) {
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
|
|
1
2
|
{
|
|
2
3
|
"name": "whalibmob",
|
|
3
|
-
"version": "5.5.
|
|
4
|
+
"version": "5.5.39",
|
|
4
5
|
"description": "WhatsApp library for interaction with WhatsApp Mobile API no web",
|
|
5
|
-
"author": "
|
|
6
|
+
"author": "Kunboruto50",
|
|
6
7
|
"main": "index.js",
|
|
7
8
|
"bin": {
|
|
8
9
|
"wa": "./cli.js"
|
|
@@ -32,11 +33,11 @@
|
|
|
32
33
|
],
|
|
33
34
|
"repository": {
|
|
34
35
|
"type": "git",
|
|
35
|
-
"url": "https://github.com/
|
|
36
|
+
"url": "https://github.com/Kunboruto50/whalibmob.git"
|
|
36
37
|
},
|
|
37
|
-
"homepage": "https://github.com/
|
|
38
|
+
"homepage": "https://github.com/Kunboruto50/whalibmob#readme",
|
|
38
39
|
"bugs": {
|
|
39
|
-
"url": "https://github.com/
|
|
40
|
+
"url": "https://github.com/Kunboruto50/whalibmob/issues"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
43
|
"@noble/hashes": "^1.7.2",
|