aunubaileys 1.0.12 → 1.0.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/README.md
CHANGED
|
@@ -64,6 +64,14 @@ Everything else is pure upstream. When upstream moves, we rebase the patch layer
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
### 🆕 What's new in 1.0.14 / Baru di 1.0.14
|
|
68
|
+
|
|
69
|
+
- 💊 **Bad MAC self-heal** — when a contact's E2E session rots (classic after re-pairing: every message from that one contact fails with “Bad MAC” forever), upstream Baileys just retries against the same stale session endlessly. AunuBaileys now counts consecutive decrypt failures per identity; at the 3rd, it **deletes the stale session** (new `signalRepository.deleteSession`) and forces the next retry receipt to carry fresh keys, so the peer re-initiates a clean session — the same reset dance official clients use. A successful decrypt zeroes the counter. Groups are excluded (sender-key class, handled separately).
|
|
70
|
+
|
|
71
|
+
### 🆕 What's new in 1.0.13 / Baru di 1.0.13
|
|
72
|
+
|
|
73
|
+
- 📵 **Bundled WhatsApp version corrected** — the previously bundled version `2.3000.1035194821` is now **rejected by WhatsApp's servers** (connection closed with code 405 at login; proven by a field probe on a real VPS deploy — handshake completes, the login node is sent, the server closes 405). The bundled default is now `2.3000.1043857760`, the version the official version endpoint currently reports as accepted — and the same deploy paired successfully with it. If your pairing suddenly fails with a 405 while your network is fine, this was it. Consumers who override `version` in their socket config are unaffected.
|
|
74
|
+
|
|
67
75
|
### 🆕 What's new in 1.0.12 / Baru di 1.0.12
|
|
68
76
|
|
|
69
77
|
- 🔑 **Pairing waits for the socket — and explains itself when it can't.** Field report from a real VPS deploy: `requestPairingCode` threw a bare Boom 428 "Connection Closed" every time, leaving consumers unable to tell an unready socket from a server rejection. Now `requestPairingCode` **waits internally (up to 30s) for the transport to open** before sending the pairing IQ, fails fast if the connection dies while waiting, and **every pairing failure carries the last disconnect reason** (status code + message) instead of the generic text. The 1.0.10 single-flight guard is kept and covers the wait.
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -66,6 +66,10 @@ export function makeLibSignalRepository(auth) {
|
|
|
66
66
|
senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
|
|
67
67
|
};
|
|
68
68
|
},
|
|
69
|
+
async deleteSession(jid) {
|
|
70
|
+
const addr = jidToSignalProtocolAddress(jid).toString();
|
|
71
|
+
await auth.keys.set({ session: { [addr]: null } });
|
|
72
|
+
},
|
|
69
73
|
async injectE2ESession({ jid, session }) {
|
|
70
74
|
const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
|
|
71
75
|
await cipher.initOutgoing(session);
|
|
@@ -15,6 +15,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
15
15
|
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
|
|
16
16
|
const sock = makeMessagesSocket(config);
|
|
17
17
|
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage } = sock;
|
|
18
|
+
/** AunuBaileys: consecutive decrypt failures per signal address.
|
|
19
|
+
* WhatsApp clients heal a rotten (Bad MAC) session by dropping it and
|
|
20
|
+
* letting the peer re-initiate from the key bundle in our retry receipt;
|
|
21
|
+
* upstream Baileys retries forever against the same stale session. */
|
|
22
|
+
const decryptFailCounts = new Map();
|
|
23
|
+
const DECRYPT_FAIL_SESSION_RESET_LIMIT = 3;
|
|
18
24
|
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
|
|
19
25
|
const retryMutex = makeMutex();
|
|
20
26
|
const msgRetryCache = config.msgRetryCounterCache ||
|
|
@@ -659,7 +665,26 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
659
665
|
return;
|
|
660
666
|
}
|
|
661
667
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
662
|
-
|
|
668
|
+
let forceIncludeKeys = !encNode;
|
|
669
|
+
if (!isJidGroup(msg.key.remoteJid) && author) {
|
|
670
|
+
try {
|
|
671
|
+
const addr = signalRepository.jidToSignalProtocolAddress(author);
|
|
672
|
+
const fails = (decryptFailCounts.get(addr) || 0) + 1;
|
|
673
|
+
if (fails >= DECRYPT_FAIL_SESSION_RESET_LIMIT) {
|
|
674
|
+
await signalRepository.deleteSession(author);
|
|
675
|
+
decryptFailCounts.delete(addr);
|
|
676
|
+
forceIncludeKeys = true;
|
|
677
|
+
logger.warn({ author, addr }, 'aunu: deleted stale E2E session after repeated decrypt failures (Bad MAC self-heal); retry receipt carries fresh keys');
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
decryptFailCounts.set(addr, fails);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
catch (healErr) {
|
|
684
|
+
logger.debug({ err: healErr }, 'aunu: session self-heal step failed, continuing with normal retry');
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
await sendRetryRequest(node, forceIncludeKeys);
|
|
663
688
|
if (retryRequestDelayMs) {
|
|
664
689
|
await delay(retryRequestDelayMs);
|
|
665
690
|
}
|
|
@@ -670,6 +695,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
670
695
|
});
|
|
671
696
|
}
|
|
672
697
|
else {
|
|
698
|
+
if (author) {
|
|
699
|
+
try {
|
|
700
|
+
decryptFailCounts.delete(signalRepository.jidToSignalProtocolAddress(author));
|
|
701
|
+
}
|
|
702
|
+
catch { }
|
|
703
|
+
}
|
|
673
704
|
// no type in the receipt => message delivered
|
|
674
705
|
let type = undefined;
|
|
675
706
|
let participant = msg.key.participant;
|
package/lib/Types/Signal.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export type SignalRepository = {
|
|
|
52
52
|
ciphertext: Uint8Array;
|
|
53
53
|
}>;
|
|
54
54
|
injectE2ESession(opts: E2ESessionOpts): Promise<void>;
|
|
55
|
+
/** AunuBaileys: delete the stored E2E session for a JID (used by the Bad MAC self-heal). */
|
|
56
|
+
deleteSession(jid: string): Promise<void>;
|
|
55
57
|
jidToSignalProtocolAddress(jid: string): string;
|
|
56
58
|
};
|
|
57
59
|
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aunubaileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.14",
|
|
5
5
|
"description": "AunuBaileys \u2014 a WhatsApp Web API for bots that never sleep. Full upstream power with the beloved in-memory store restored and pairing that just works. Forged by AunuCore.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|