feat: format session error logs cleanly

Replace verbose libsignal session errors with clean, readable format.

Before:
Session error:Error: Bad MAC Error: Bad MAC
    at Object.verifyMAC (.../libsignal/src/crypto.js:87:15)
    at SessionCipher.doDecryptWhisperMessage (.../session_cipher.js:250:16)
    at async SessionCipher.decryptWithSessions (.../session_cipher.js:147:29)
    ...

After:
🔐 Bad MAC Error | JID: 4680****1027

Changes:
- Intercepts console.log and console.error from libsignal
- Detects error type (Bad MAC, Counter Error, Decryption Failed)
- Extracts and masks JID for privacy
- Avoids duplicate logs within 100ms
- Simple and direct - no configuration needed

https://claude.ai/code/session_01TvSrN9JmHZDdKMZDFWEcUS
This commit is contained in:
Claude
2026-02-12 03:49:15 +00:00
parent 36784a97ac
commit aca49891e5
+82 -7
View File
@@ -1,13 +1,17 @@
// ============================================
// Suppress verbose logs from libsignal BEFORE any imports
// This MUST be at the very top to intercept console.log before libsignal loads
// Format session error logs from libsignal BEFORE any imports
// This MUST be at the very top to intercept console before libsignal loads
// ============================================
const _origConsoleLog = console.log
const _origConsoleError = console.error
// Track last error to avoid duplicates
let _lastErrorMsg = ''
let _lastErrorTime = 0
console.log = function(...args: unknown[]) {
if (args.length > 0 && typeof args[0] === 'string') {
const msg = args[0]
// Check if this log comes from libsignal by examining the call stack
const stack = new Error().stack || ''
const isFromLibsignal = stack.includes('libsignal') || stack.includes('session_cipher')
@@ -17,14 +21,39 @@ console.log = function(...args: unknown[]) {
return
}
// Suppress transient decryption errors auto-recovered by retry logic
// Format session errors cleanly
if (
msg.includes('Session error') ||
msg.includes('Bad MAC') ||
msg.includes('MessageCounterError') ||
msg.includes('Key used already or never filled') ||
msg.includes('Failed to decrypt message with any known session')
msg.includes('Key used already') ||
msg.includes('Failed to decrypt')
) {
// Extract error type
let errorType = '⚠️ Session Error'
if (msg.includes('Bad MAC')) errorType = '🔐 Bad MAC Error'
else if (msg.includes('MessageCounterError') || msg.includes('Key used already')) errorType = '🔢 Counter Error'
else if (msg.includes('Failed to decrypt')) errorType = '🔌 Decryption Failed'
// Extract JID if present (format: 46802258641027_1.0 or similar)
const jidMatch = msg.match(/(\d{10,}(?:_\d+\.\d+)?)/);
const jid = jidMatch ? jidMatch[1] : null
const maskedJid = jid && jid.length > 8 ? `${jid.substring(0, 4)}****${jid.substring(jid.length - 4)}` : jid
// Format clean message
const cleanMsg = maskedJid
? `${errorType} | JID: ${maskedJid}`
: errorType
// Avoid duplicate logs (within 100ms)
const now = Date.now()
if (cleanMsg === _lastErrorMsg && now - _lastErrorTime < 100) {
return
}
_lastErrorMsg = cleanMsg
_lastErrorTime = now
_origConsoleError(cleanMsg)
return
}
}
@@ -33,6 +62,52 @@ console.log = function(...args: unknown[]) {
_origConsoleLog.apply(console, args)
}
console.error = function(...args: unknown[]) {
if (args.length > 0 && typeof args[0] === 'string') {
const msg = args[0]
const stack = new Error().stack || ''
const isFromLibsignal = stack.includes('libsignal') || stack.includes('session_cipher')
if (isFromLibsignal) {
// Format session errors cleanly
if (
msg.includes('Session error') ||
msg.includes('Bad MAC') ||
msg.includes('MessageCounterError') ||
msg.includes('Key used already')
) {
// Extract error type
let errorType = '⚠️ Session Error'
if (msg.includes('Bad MAC')) errorType = '🔐 Bad MAC Error'
else if (msg.includes('MessageCounterError') || msg.includes('Key used already')) errorType = '🔢 Counter Error'
// Extract JID from stack trace or message
const jidMatch = (msg + (args[1] || '')).match(/(\d{10,}(?:_\d+\.\d+)?)/);
const jid = jidMatch ? jidMatch[1] : null
const maskedJid = jid && jid.length > 8 ? `${jid.substring(0, 4)}****${jid.substring(jid.length - 4)}` : jid
// Format clean message
const cleanMsg = maskedJid
? `${errorType} | JID: ${maskedJid}`
: errorType
// Avoid duplicate logs (within 100ms)
const now = Date.now()
if (cleanMsg === _lastErrorMsg && now - _lastErrorTime < 100) {
return
}
_lastErrorMsg = cleanMsg
_lastErrorTime = now
_origConsoleError(cleanMsg)
return
}
}
}
_origConsoleError.apply(console, args)
}
import makeWASocket, { makeWASocketAutoVersion } from './Socket/index'
export * from '../WAProto/index.js'