aunubaileys 1.0.34 → 1.0.36

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/LICENSE CHANGED
@@ -1,7 +1,12 @@
1
1
  MIT License
2
2
 
3
+ Copyright (c) 2026 AunuCore Creative Network
3
4
  Copyright (c) 2025 Rajeh Taher/WhiskeySockets
4
5
 
6
+ AunuBaileys is developed and maintained by AunuCore Creative Network and is
7
+ based on Baileys by WhiskeySockets. The original copyright notice above is
8
+ retained as required by the MIT License.
9
+
5
10
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
11
  of this software and associated documentation files (the "Software"), to deal
7
12
  in the Software without restriction, including without limitation the rights
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.36 / Baru di 1.0.36
68
+
69
+ - 📜 **The license now carries the AunuCore Creative Network copyright** — the LICENSE file previously listed only the upstream (WhiskeySockets) copyright, even though AunuBaileys is developed and maintained by AunuCore Creative Network. The primary copyright line is now AunuCore Creative Network, with the upstream attribution retained directly below it exactly as the MIT License requires, plus one line explaining the package's origin. The license itself is unchanged: still MIT, the package.json `license` field is still "MIT", and package users' rights are exactly as before. No code changes in this release.
70
+
71
+ ### 🆕 What's new in 1.0.35 / Baru di 1.0.35
72
+
73
+ - 📡 **Decrypt failures now emit a structured signal instead of a log flood** — one rotten session can fail hundreds of messages in minutes (B-01), and every failure was logged at ERROR level, drowning the logs while the bot had no programmatic way to know a Bad MAC flood was happening. Now: (1) the decrypt error log is throttled per sender address — first line immediately, then at most one line per minute per sender carrying the suppressed-failure count; (2) a new `messages.decrypt-failure` event carries the chat, sender, signal address, consecutive failure count, and whether this failure tripped the session/sender-key reset — consumers can alert and aggregate without parsing logs. The failure handling itself is unchanged. Closing release of the 1.0.14–1.0.35 fix train.
74
+
67
75
  ### 🆕 What's new in 1.0.34 / Baru di 1.0.34
68
76
 
69
77
  - 🗳️ **One person no longer counts as two poll voters across the LID/PN split** — poll aggregation keyed voters by their raw message-key identity, so someone voting first as a phone number and later as a LID (or the reverse) counted as two different voters, and a poll update arriving in the other identity form piled up as a second entry instead of replacing the old one. `getAggregateVotesInPollMessage` and `updateMessageWithPollUpdate` now accept an optional `{ lidStore }` option: voters are canonicalized to their phone-number JID and deduped per option. Without a store, legacy behaviour is unchanged.
@@ -751,6 +751,19 @@ export const makeMessagesRecvSocket = (config) => {
751
751
  else {
752
752
  decryptFailCounts.set(failKey, fails);
753
753
  }
754
+ // AunuBaileys: structured decrypt-failure event so
755
+ // consumers can alert and aggregate on Bad MAC
756
+ // floods (B-01) instead of parsing log lines.
757
+ ev.emit('messages.decrypt-failure', {
758
+ remoteJid: msg.key.remoteJid,
759
+ author,
760
+ address: addr,
761
+ isGroup: isGroupMsg,
762
+ failures: fails,
763
+ healed: fails >= DECRYPT_FAIL_SESSION_RESET_LIMIT,
764
+ messageId: node.attrs.id,
765
+ timestamp: Date.now()
766
+ });
754
767
  }
755
768
  catch (healErr) {
756
769
  logger.debug({ err: healErr }, 'aunu: session self-heal step failed, continuing with normal retry');
@@ -43,6 +43,21 @@ export type BaileysEventMap = {
43
43
  };
44
44
  'contacts.upsert': Contact[];
45
45
  'contacts.update': Partial<Contact>[];
46
+ 'messages.decrypt-failure': {
47
+ /** the chat the failed message arrived in */
48
+ remoteJid: string;
49
+ /** sender JID (participant in groups) */
50
+ author: string;
51
+ /** signal-protocol address the failure was counted against */
52
+ address: string;
53
+ isGroup: boolean;
54
+ /** consecutive failures for this address, including this one */
55
+ failures: number;
56
+ /** true when this failure tripped the session/sender-key reset */
57
+ healed: boolean;
58
+ messageId: string;
59
+ timestamp: number;
60
+ };
46
61
  'messages.delete': {
47
62
  keys: WAMessageKey[];
48
63
  } | {
@@ -109,6 +109,26 @@ export function decodeMessageNode(stanza, meId, meLid) {
109
109
  sender: msgType === 'chat' ? author : chatId
110
110
  };
111
111
  }
112
+ // AunuBaileys: per-address throttle for the per-message decrypt error log.
113
+ // One rotten session can fail hundreds of messages in minutes (B-01: every
114
+ // failure from a single LID address flooded the logs at ERROR level); the
115
+ // first failure per address logs immediately, then at most one line per
116
+ // minute, carrying how many failures were suppressed in between. Nothing
117
+ // about the failure handling itself changes — only the log volume.
118
+ const DECRYPT_ERROR_LOG_INTERVAL_MS = 60_000;
119
+ const decryptErrorLogState = new Map();
120
+ const logDecryptErrorThrottled = (logger, address, key, err) => {
121
+ const now = Date.now();
122
+ const state = decryptErrorLogState.get(address) || { lastLoggedAt: 0, suppressed: 0 };
123
+ if (now - state.lastLoggedAt >= DECRYPT_ERROR_LOG_INTERVAL_MS) {
124
+ logger.error({ key, err, suppressedFailures: state.suppressed }, 'failed to decrypt message');
125
+ decryptErrorLogState.set(address, { lastLoggedAt: now, suppressed: 0 });
126
+ }
127
+ else {
128
+ decryptErrorLogState.set(address, { ...state, suppressed: state.suppressed + 1 });
129
+ }
130
+ };
131
+
112
132
  export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
113
133
  const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid);
114
134
  return {
@@ -171,7 +191,7 @@ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
171
191
  });
172
192
  }
173
193
  catch (err) {
174
- logger.error({ key: fullMessage.key, err }, 'failed to decrypt message');
194
+ logDecryptErrorThrottled(logger, author, fullMessage.key, err);
175
195
  }
176
196
  }
177
197
  if (fullMessage.message) {
@@ -182,7 +202,7 @@ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
182
202
  }
183
203
  }
184
204
  catch (err) {
185
- logger.error({ key: fullMessage.key, err }, 'failed to decrypt message');
205
+ logDecryptErrorThrottled(logger, author, fullMessage.key, err);
186
206
  fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT;
187
207
  fullMessage.messageStubParameters = [err.message];
188
208
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aunubaileys",
3
3
  "type": "module",
4
- "version": "1.0.34",
4
+ "version": "1.0.36",
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",