UNPKG

syntropylog

Version:

An instance manager with observability for Node.js applications

87 lines 3.13 kB
/** * FILE: src/utils/sanitizeConfig.ts * DESCRIPTION: Utilities for sanitizing the SyntropyLog configuration object. */ import { Transport } from '../logger/transports/Transport'; const MASK = '[CONFIG_MASKED]'; const SENSITIVE_KEYS = [ 'password', 'token', 'secret', 'apikey', 'credential', 'pass', 'key', 'accesstoken', 'refreshtoken', 'clientsecret', 'sentinelpassword', 'sasl', ]; /** * @private * A helper function to detect if a value is a special class instance * (like a Transport or an Adapter) that should not be deeply cloned or sanitized. * This is crucial to preserve methods and internal state of user-provided instances. * @param {any} value - The value to check. * @returns {value is Transport | IHttpClientAdapter | IBrokerAdapter} True if the value is a special instance. */ function isSpecialInstance(value) { if (value instanceof Transport) { return true; } // Duck-typing for adapters: if it has the core method, we treat it as an adapter. if (typeof value === 'object' && value !== null && (typeof value.request === 'function' || typeof value.publish === 'function')) { return true; } return false; } /** * Recursively sanitizes a configuration object for safe logging. * It masks values for keys that are known to be sensitive and redacts credentials from URLs. * It intelligently skips special class instances (Transports, Adapters) to preserve their methods. * @param {T} config - The configuration object to sanitize. * @returns {T} A new, sanitized configuration object. */ export function sanitizeConfig(config) { // If the object is a special instance (like a Transport or Adapter), return it without processing. if (isSpecialInstance(config)) { return config; } if (config === null || typeof config !== 'object') { return config; } if (Array.isArray(config)) { return config.map((item) => sanitizeConfig(item)); } const sanitized = {}; const sensitiveLower = SENSITIVE_KEYS.map((k) => k.toLowerCase()); for (const key in config) { if (Object.prototype.hasOwnProperty.call(config, key)) { const lowerKey = key.toLowerCase(); const value = config[key]; if (sensitiveLower.includes(lowerKey)) { sanitized[key] = MASK; } else if ((lowerKey.includes('url') || lowerKey.includes('uri')) && typeof value === 'string') { // Redact user:pass from connection strings. sanitized[key] = value.replace(/(?<=:\/\/)[^:]+:[^@]+@/, `${MASK}@`); } else if (typeof value === 'object' && value !== null && !(value instanceof RegExp)) { // The recursive call will also respect special instances. sanitized[key] = sanitizeConfig(value); } else { sanitized[key] = value; } } } return sanitized; } //# sourceMappingURL=sanitizeConfig.js.map