UNPKG

ailock

Version:

AI-Proof File Guard - Protect sensitive files from accidental AI modifications

148 lines 6.09 kB
/** * Error message sanitization to prevent information disclosure */ export class ErrorSanitizer { sensitivePatterns = [ /\/Users\/[^\/\s]+/g, // macOS user directories /\/home\/[^\/\s]+/g, // Linux home directories /C:\\Users\\[^\\\/\s]+/g, // Windows user directories /password[:\s]*[^\s]+/gi, // Password values /token[:\s]*[^\s]+/gi, // Token values /bearer[:\s]+[^\s]+/gi, // Bearer tokens /authorization[:\s]*[^\s]+/gi, // Authorization headers /api[_-]?key[:\s]*[^\s]+/gi, // API keys /secret[:\s]*[^\s]+/gi, // Secret values /private[_-]?key[:\s]*[^\s]+/gi, // Private keys /ssh[_-]?key[:\s]*[^\s]+/gi, // SSH keys /cert[:\s]*[^\s]+/gi, // Certificate data /x-[a-z-]+[:\s]*[^\s]+/gi, // Custom headers /[a-f0-9]{32,}/g, // Potential hashes (MD5, SHA, etc.) /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, // UUIDs /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, // IP addresses /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, // Email addresses /(?:https?|ftp):\/\/[^\s]+/g, // URLs /-----BEGIN[^-]+-----[\s\S]+?-----END[^-]+-----/g, // PEM certificates/keys /\$[A-Z_][A-Z0-9_]*/g, // Environment variables /"[^"]*"/g, // Quoted strings (potential secrets) /'[^']*'/g, // Single-quoted strings /`[^`]*`/g // Backticked strings ]; replacements = [ [/\/Users\/[^\/\s]+/g, '/Users/[user]'], [/\/home\/[^\/\s]+/g, '/home/[user]'], [/C:\\Users\\[^\\\/\s]+/g, 'C:\\Users\\[user]'], [/password[:\s]*[^\s]+/gi, 'password: [REDACTED]'], [/token[:\s]*[^\s]+/gi, 'token: [REDACTED]'], [/bearer[:\s]+[^\s]+/gi, 'bearer [REDACTED]'], [/authorization[:\s]*[^\s]+/gi, 'authorization: [REDACTED]'], [/api[_-]?key[:\s]*[^\s]+/gi, 'api_key: [REDACTED]'], [/secret[:\s]*[^\s]+/gi, 'secret: [REDACTED]'], [/private[_-]?key[:\s]*[^\s]+/gi, 'private_key: [REDACTED]'], [/ssh[_-]?key[:\s]*[^\s]+/gi, 'ssh_key: [REDACTED]'], [/cert[:\s]*[^\s]+/gi, 'cert: [REDACTED]'], [/x-[a-z-]+[:\s]*[^\s]+/gi, 'x-header: [REDACTED]'], [/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, '[IP_ADDRESS]'], [/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, '[EMAIL]'], [/(?:https?|ftp):\/\/[^\s]+/g, '[URL]'], [/-----BEGIN[^-]+-----[\s\S]+?-----END[^-]+-----/g, '[CERTIFICATE/KEY]'], [/\$[A-Z_][A-Z0-9_]*/g, '$[ENV_VAR]'], [/"[^"]*"/g, '"[REDACTED]"'], [/'[^']*'/g, "'[REDACTED]'"], [/`[^`]*`/g, '`[REDACTED]`'] ]; /** * Sanitize error message to remove sensitive information */ sanitizeMessage(message) { if (!message || typeof message !== 'string') { return '[INVALID_MESSAGE]'; } let sanitized = message; // Apply all replacement patterns for (const [pattern, replacement] of this.replacements) { sanitized = sanitized.replace(pattern, replacement); } // Additional cleanup for potential hash values sanitized = sanitized.replace(/[a-f0-9]{16,}/g, '[HASH]'); // Clean up UUID-like patterns sanitized = sanitized.replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, '[UUID]'); return this.limitMessageLength(sanitized); } /** * Sanitize context object by removing sensitive keys and values */ sanitizeContext(context, maxSize = 1000) { if (!context || typeof context !== 'object') { return {}; } const sensitiveKeys = [ 'password', 'secret', 'token', 'key', 'auth', 'credential', 'private', 'certificate', 'cert', 'passphrase', 'pin' ]; const sanitized = {}; let currentSize = 0; for (const [key, value] of Object.entries(context)) { if (currentSize >= maxSize) { sanitized['...'] = '[TRUNCATED]'; break; } const lowerKey = key.toLowerCase(); const isSensitiveKey = sensitiveKeys.some(sk => lowerKey.includes(sk)); if (isSensitiveKey) { sanitized[key] = '[REDACTED]'; currentSize += 20; } else { const sanitizedValue = this.sanitizeValue(value); const serialized = JSON.stringify(sanitizedValue); if (currentSize + serialized.length <= maxSize) { sanitized[key] = sanitizedValue; currentSize += serialized.length; } else { sanitized['...'] = '[TRUNCATED]'; break; } } } return sanitized; } /** * Check if a message contains sensitive patterns */ containsSensitiveData(message) { if (!message || typeof message !== 'string') { return false; } return this.sensitivePatterns.some(pattern => pattern.test(message)); } sanitizeValue(value) { if (typeof value === 'string') { return this.sanitizeMessage(value); } if (Array.isArray(value)) { return value.slice(0, 10).map(v => this.sanitizeValue(v)); } if (value && typeof value === 'object') { const result = {}; let count = 0; for (const [k, v] of Object.entries(value)) { if (count >= 10) { result['...'] = '[TRUNCATED]'; break; } result[k] = this.sanitizeValue(v); count++; } return result; } return value; } limitMessageLength(message, maxLength = 500) { if (message.length <= maxLength) { return message; } return message.substring(0, maxLength - 15) + '... [TRUNCATED]'; } } //# sourceMappingURL=ErrorSanitizer.js.map