From aca49891e5b07f8c0f511f170016ad8fd2aeff6b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Feb 2026 03:49:15 +0000 Subject: [PATCH] feat: format session error logs cleanly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/index.ts | 89 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index 627985c3..12dd943f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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'