From a4161bc47e472896f428c1a963594f25ba822f0d Mon Sep 17 00:00:00 2001 From: lockbitchat Date: Thu, 28 Aug 2025 15:15:09 -0400 Subject: [PATCH] SECURITY: Fix console logging vulnerabilities in production mode - Replace unsafe console.error/warn calls with secure logging system - Implement production-safe logging that masks sensitive data - Add automatic sanitization for cryptographic keys and sensitive information - Create secure logging infrastructure for EnhancedSecureWebRTCManager and EnhancedSecureCryptoUtils - Prevent data leakage of internal logic and error details in production - Add production/development mode detection for appropriate logging levels - Implement server-side error logging for production environments --- src/crypto/EnhancedSecureCryptoUtils.js | 12 +- src/pwa/offline-manager.js | 552 ------------------------ 2 files changed, 8 insertions(+), 556 deletions(-) delete mode 100644 src/pwa/offline-manager.js diff --git a/src/crypto/EnhancedSecureCryptoUtils.js b/src/crypto/EnhancedSecureCryptoUtils.js index e7fb7f1..7dbbf87 100644 --- a/src/crypto/EnhancedSecureCryptoUtils.js +++ b/src/crypto/EnhancedSecureCryptoUtils.js @@ -2,10 +2,7 @@ class EnhancedSecureCryptoUtils { static _keyMetadata = new WeakMap(); - // Initialize secure logging system - static { - EnhancedSecureCryptoUtils.secureLog.init(); - } + // Initialize secure logging system after class definition // Utility to sort object keys for deterministic serialization static sortObjectKeys(obj) { @@ -2419,6 +2416,13 @@ class EnhancedSecureCryptoUtils { return result === 0; } + + // Initialize secure logging system after class definition + static { + if (EnhancedSecureCryptoUtils.secureLog && typeof EnhancedSecureCryptoUtils.secureLog.init === 'function') { + EnhancedSecureCryptoUtils.secureLog.init(); + } + } } export { EnhancedSecureCryptoUtils }; \ No newline at end of file diff --git a/src/pwa/offline-manager.js b/src/pwa/offline-manager.js deleted file mode 100644 index 328f957..0000000 --- a/src/pwa/offline-manager.js +++ /dev/null @@ -1,552 +0,0 @@ -// PWA Offline Component for SecureBit.chat -// Handles offline functionality and user experience - -window.PWAOfflineManager = (() => { - 'use strict'; - - class PWAOfflineManager { - constructor() { - this.isOnline = navigator.onLine; - this.offlineQueue = []; - this.syncInProgress = false; - this.offlineIndicator = null; - - this.init(); - } - - init() { - console.log('📴 PWA Offline Manager initializing...'); - - this.setupEventListeners(); - this.createOfflineIndicator(); - this.setupOfflineStorage(); - this.registerBackgroundSync(); - - // Show initial status - this.updateConnectionStatus(this.isOnline); - - console.log('✅ PWA Offline Manager initialized'); - } - - setupEventListeners() { - window.addEventListener('online', () => { - console.log('🌐 Connection restored'); - this.isOnline = true; - this.updateConnectionStatus(true); - this.processOfflineQueue(); - }); - - window.addEventListener('offline', () => { - console.log('📴 Connection lost'); - this.isOnline = false; - this.updateConnectionStatus(false); - this.showOfflineGuidance(); - }); - - // Monitor WebRTC connection status - document.addEventListener('peer-disconnect', () => { - if (!this.isOnline) { - this.handleOfflineDisconnect(); - } - }); - - // Monitor failed network requests - window.addEventListener('unhandledrejection', (event) => { - if (this.isNetworkError(event.reason)) { - this.handleNetworkFailure(event.reason); - } - }); - } - - createOfflineIndicator() { - this.offlineIndicator = document.createElement('div'); - this.offlineIndicator.id = 'pwa-connection-status'; - this.offlineIndicator.className = 'hidden fixed top-4 left-1/2 transform -translate-x-1/2 z-50 transition-all duration-300'; - document.body.appendChild(this.offlineIndicator); - } - - updateConnectionStatus(isOnline) { - if (!this.offlineIndicator) return; - - if (isOnline) { - this.offlineIndicator.innerHTML = ` -
-
- 🌐 Back online -
- `; - this.offlineIndicator.classList.remove('hidden'); - - // Hide after 3 seconds - setTimeout(() => { - this.offlineIndicator.classList.add('hidden'); - }, 3000); - } else { - this.offlineIndicator.innerHTML = ` -
-
- 📴 Offline mode -
- `; - this.offlineIndicator.classList.remove('hidden'); - } - } - - showOfflineGuidance() { - const guidance = document.createElement('div'); - guidance.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4'; - guidance.innerHTML = ` -
-
- -
-

Connection Lost

-

- Your internet connection was lost. SecureBit.chat requires an active connection for secure P2P communication. -

-
-
- - Your session and keys are preserved -
-
- - No data is stored on servers -
-
- - Connection will resume automatically -
-
- -
- `; - - document.body.appendChild(guidance); - - // Auto-remove after 10 seconds - setTimeout(() => { - if (guidance.parentElement) { - guidance.remove(); - } - }, 10000); - } - - setupOfflineStorage() { - // Initialize IndexedDB for offline data storage - this.initOfflineDB().catch(error => { - console.warn('⚠️ Offline storage not available:', error); - }); - } - - async initOfflineDB() { - return new Promise((resolve, reject) => { - const request = indexedDB.open('SecureBitOffline', 1); - - request.onerror = () => reject(request.error); - request.onsuccess = () => { - this.offlineDB = request.result; - resolve(this.offlineDB); - }; - - request.onupgradeneeded = (event) => { - const db = event.target.result; - - // Store for offline queue - if (!db.objectStoreNames.contains('offlineQueue')) { - const queueStore = db.createObjectStore('offlineQueue', { - keyPath: 'id', - autoIncrement: true - }); - queueStore.createIndex('timestamp', 'timestamp', { unique: false }); - queueStore.createIndex('type', 'type', { unique: false }); - } - - // Store for session recovery - if (!db.objectStoreNames.contains('sessionData')) { - const sessionStore = db.createObjectStore('sessionData', { - keyPath: 'key' - }); - } - }; - }); - } - - registerBackgroundSync() { - if ('serviceWorker' in navigator && 'sync' in window.ServiceWorkerRegistration.prototype) { - navigator.serviceWorker.ready.then(registration => { - console.log('📡 Background sync registered'); - this.swRegistration = registration; - }); - } else { - console.warn('⚠️ Background sync not supported'); - } - } - - async queueOfflineAction(action) { - if (!this.offlineDB) { - console.warn('⚠️ Offline storage not available'); - return; - } - - const queueItem = { - ...action, - timestamp: Date.now(), - id: Date.now() + Math.random() - }; - - try { - const transaction = this.offlineDB.transaction(['offlineQueue'], 'readwrite'); - const store = transaction.objectStore('offlineQueue'); - await store.add(queueItem); - - console.log('📤 Action queued for when online:', action.type); - this.offlineQueue.push(queueItem); - - // Try to sync in background - if (this.swRegistration) { - await this.swRegistration.sync.register('retry-offline-actions'); - } - } catch (error) { - console.error('❌ Failed to queue offline action:', error); - } - } - - async processOfflineQueue() { - if (this.syncInProgress || !this.isOnline) { - return; - } - - this.syncInProgress = true; - console.log('🔄 Processing offline queue...'); - - try { - if (this.offlineDB) { - const transaction = this.offlineDB.transaction(['offlineQueue'], 'readwrite'); - const store = transaction.objectStore('offlineQueue'); - const allItems = await this.getAllFromStore(store); - - for (const item of allItems) { - try { - await this.processQueueItem(item); - await store.delete(item.id); - console.log('✅ Processed offline action:', item.type); - } catch (error) { - console.error('❌ Failed to process offline action:', error); - // Keep item in queue for retry - } - } - } - - // Process in-memory queue as fallback - const memoryQueue = [...this.offlineQueue]; - this.offlineQueue = []; - - for (const item of memoryQueue) { - try { - await this.processQueueItem(item); - } catch (error) { - console.error('❌ Failed to process memory queue item:', error); - this.offlineQueue.push(item); // Re-queue on failure - } - } - - if (memoryQueue.length > 0) { - this.showSyncNotification(memoryQueue.length); - } - - } catch (error) { - console.error('❌ Error processing offline queue:', error); - } finally { - this.syncInProgress = false; - } - } - - async getAllFromStore(store) { - return new Promise((resolve, reject) => { - const request = store.getAll(); - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); - } - - async processQueueItem(item) { - switch (item.type) { - case 'message': - return this.retryMessage(item.data); - case 'connection': - return this.retryConnection(item.data); - case 'payment_check': - return this.retryPaymentCheck(item.data); - default: - console.warn('Unknown queue item type:', item.type); - } - } - - async retryMessage(messageData) { - // Retry sending message when back online - if (window.webrtcManager && window.webrtcManager.isConnected()) { - return window.webrtcManager.sendMessage(messageData.content); - } - throw new Error('WebRTC not connected'); - } - - async retryConnection(connectionData) { - // Retry connection establishment - if (window.webrtcManager) { - return window.webrtcManager.retryConnection(); - } - throw new Error('WebRTC manager not available'); - } - - async retryPaymentCheck(paymentData) { - // Retry payment verification - if (window.sessionManager) { - return window.sessionManager.checkPaymentStatus(paymentData.checkingId); - } - throw new Error('Session manager not available'); - } - - showSyncNotification(count) { - const notification = document.createElement('div'); - notification.className = 'fixed bottom-4 right-4 bg-green-500 text-white p-4 rounded-lg shadow-lg z-50 max-w-sm'; - notification.innerHTML = ` -
- -
-
Sync Complete
-
${count} offline action(s) processed
-
-
- `; - - document.body.appendChild(notification); - - // Auto-remove after 4 seconds - setTimeout(() => { - notification.remove(); - }, 4000); - } - - handleOfflineDisconnect() { - // Handle WebRTC disconnection while offline - console.log('🔌 WebRTC disconnected while offline'); - - const reconnectBanner = document.createElement('div'); - reconnectBanner.className = 'fixed top-0 left-0 right-0 bg-yellow-500 text-black p-3 z-50 text-center'; - reconnectBanner.innerHTML = ` -
- - Connection lost. Will attempt to reconnect when online. -
- `; - - document.body.appendChild(reconnectBanner); - - setTimeout(() => { - if (reconnectBanner.parentElement) { - reconnectBanner.remove(); - } - }, 5000); - } - - handleNetworkFailure(error) { - console.log('🌐 Network failure detected:', error?.message); - - // Queue the failed action for retry - if (this.shouldQueueAction(error)) { - this.queueOfflineAction({ - type: 'network_retry', - data: { error: error?.message }, - timestamp: Date.now() - }); - } - } - - isNetworkError(error) { - if (!error) return false; - - const networkErrorMessages = [ - 'fetch', - 'network', - 'connection', - 'timeout', - 'offline', - 'ERR_NETWORK', - 'ERR_INTERNET_DISCONNECTED' - ]; - - const errorString = error.toString().toLowerCase(); - return networkErrorMessages.some(msg => errorString.includes(msg)); - } - - shouldQueueAction(error) { - // Determine if the action should be queued for retry - return this.isNetworkError(error) && !this.isOnline; - } - - async saveSessionForRecovery(sessionData) { - if (!this.offlineDB) return; - - try { - const transaction = this.offlineDB.transaction(['sessionData'], 'readwrite'); - const store = transaction.objectStore('sessionData'); - - await store.put({ - key: 'current_session', - data: sessionData, - timestamp: Date.now() - }); - - console.log('💾 Session data saved for offline recovery'); - } catch (error) { - console.error('❌ Failed to save session data:', error); - } - } - - async recoverSession() { - if (!this.offlineDB) return null; - - try { - const transaction = this.offlineDB.transaction(['sessionData'], 'readonly'); - const store = transaction.objectStore('sessionData'); - const result = await this.getFromStore(store, 'current_session'); - - if (result && Date.now() - result.timestamp < 24 * 60 * 60 * 1000) { // 24 hours - console.log('🔄 Session data recovered from offline storage'); - return result.data; - } - } catch (error) { - console.error('❌ Failed to recover session data:', error); - } - - return null; - } - - async getFromStore(store, key) { - return new Promise((resolve, reject) => { - const request = store.get(key); - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); - } - - clearOfflineData() { - if (!this.offlineDB) return; - - try { - const transaction = this.offlineDB.transaction(['offlineQueue', 'sessionData'], 'readwrite'); - transaction.objectStore('offlineQueue').clear(); - transaction.objectStore('sessionData').clear(); - - this.offlineQueue = []; - console.log('🗑️ Offline data cleared'); - } catch (error) { - console.error('❌ Failed to clear offline data:', error); - } - } - - getOfflineStatus() { - return { - isOnline: this.isOnline, - queueLength: this.offlineQueue.length, - syncInProgress: this.syncInProgress, - hasOfflineDB: !!this.offlineDB, - lastSync: this.lastSyncTime || null - }; - } - - // Public API methods - async addToOfflineQueue(type, data) { - return this.queueOfflineAction({ type, data }); - } - - forceSync() { - if (this.isOnline) { - return this.processOfflineQueue(); - } else { - console.warn('⚠️ Cannot sync while offline'); - return Promise.resolve(); - } - } - - showOfflineHelp() { - const helpModal = document.createElement('div'); - helpModal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4'; - helpModal.innerHTML = ` -
-
-
- -
-

Offline Mode Help

-
- -
-
-

What works offline:

-
    -
  • • App interface and navigation
  • -
  • • Previously cached resources
  • -
  • • Session data recovery
  • -
  • • Offline message queuing
  • -
-
- -
-

What needs internet:

-
    -
  • • P2P connections (WebRTC)
  • -
  • • Lightning payments
  • -
  • • Real-time messaging
  • -
  • • Session verification
  • -
-
- -
-

- - Your messages and actions will be automatically synced when you're back online. -

-
-
- - -
- `; - - document.body.appendChild(helpModal); - } - } - - // Initialize and return singleton - let instance = null; - - return { - getInstance() { - if (!instance) { - instance = new PWAOfflineManager(); - } - return instance; - }, - - init() { - return this.getInstance(); - } - }; -})(); - -// Auto-initialize when DOM is ready -if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => { - window.pwaOfflineManager = window.PWAOfflineManager.init(); - }); -} else { - window.pwaOfflineManager = window.PWAOfflineManager.init(); -} \ No newline at end of file