UNPKG

fortify2-js

Version:

MOST POWERFUL JavaScript Security Library! Military-grade cryptography + 19 enhanced object methods + quantum-resistant algorithms + perfect TypeScript support. More powerful than Lodash with built-in security.

209 lines (206 loc) 7.21 kB
'use strict'; /** * Safe Serialization Utility for FortifiedFunction * Handles cyclic structures, Express objects, and performance optimization */ class SafeSerializer { /** * **ULTRA-FAST: Primary serialization method with performance optimization** */ static stringify(obj, options = {}) { const opts = { ...this.DEFAULT_OPTIONS, ...options }; // **ULTRA-FAST PATH: Try simple JSON.stringify first** if (opts.fastMode) { try { const result = JSON.stringify(obj); if (result.length <= opts.maxLength) { return result; } } catch { // Fall through to safe serialization } } // **SAFE PATH: Handle complex objects with cyclic references** return this.safeStringify(obj, opts); } /** * **SAFE SERIALIZATION: Handles all edge cases** */ static safeStringify(obj, options) { const seen = new WeakSet(); let depth = 0; const replacer = (_key, value) => { // Handle primitive values if (value === null || typeof value !== "object") { if (typeof value === "string" && value.length > options.truncateStrings) { return value.substring(0, options.truncateStrings) + "...[truncated]"; } return value; } // Check depth limit depth++; if (depth > options.maxDepth) { depth--; return "[Max Depth Exceeded]"; } // Handle cyclic references if (seen.has(value)) { return `[Circular:${value.constructor?.name || 'Object'}]`; } seen.add(value); // Handle special Express objects if (value.constructor) { const constructorName = value.constructor.name; // Express Request object if (constructorName === 'IncomingMessage' || constructorName === 'Request') { const result = { method: value.method, url: value.url, headers: this.sanitizeHeaders(value.headers), params: value.params, query: value.query, body: value.body ? "[Request Body]" : undefined }; depth--; return result; } // Express Response object if (constructorName === 'ServerResponse' || constructorName === 'Response') { const result = { statusCode: value.statusCode, statusMessage: value.statusMessage, headersSent: value.headersSent }; depth--; return result; } // Other problematic objects if (['Socket', 'Server', 'Agent', 'TLSSocket'].includes(constructorName)) { depth--; return `[${constructorName}:${value.constructor.name}]`; } } // Handle functions if (typeof value === 'function') { depth--; return `[Function:${value.name || 'anonymous'}]`; } // Handle Buffers if (Buffer.isBuffer(value)) { depth--; return `[Buffer:${value.length}bytes]`; } // Handle large arrays if (Array.isArray(value) && value.length > 100) { depth--; return `[Array:${value.length}items]`; } // Handle Error objects if (value instanceof Error) { depth--; return { name: value.name, message: value.message, stack: value.stack ? "[Stack Trace]" : undefined }; } depth--; return value; }; try { const result = JSON.stringify(obj, replacer); // Check length limit if (result.length > options.maxLength) { return result.substring(0, options.maxLength) + "...[truncated]"; } return result; } catch (error) { // Ultimate fallback return `[Serialization Error: ${error instanceof Error ? error.message : 'Unknown'}]`; } } /** * **UTILITY: Sanitize HTTP headers for safe logging** */ static sanitizeHeaders(headers) { if (!headers || typeof headers !== 'object') { return headers; } const sanitized = {}; const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-auth-token']; for (const [key, value] of Object.entries(headers)) { const lowerKey = key.toLowerCase(); if (sensitiveHeaders.includes(lowerKey)) { sanitized[key] = '[REDACTED]'; } else { sanitized[key] = value; } } return sanitized; } /** * **ULTRA-FAST: Generate cache key with safe serialization** */ static generateCacheKey(args, prefix = 'cache') { try { // **ULTRA-FAST PATH: Try simple approach first** const simple = JSON.stringify(args); if (simple.length <= 500) { return `${prefix}:${simple}`; } } catch { // Fall through to safe approach } // **SAFE PATH: Use safe serialization** const safe = this.stringify(args, { fastMode: false, maxDepth: 5, maxLength: 500, truncateStrings: 100 }); return `${prefix}:${safe}`; } /** * **DEBUG: Safe debug logging** */ static debugLog(label, obj, maxLength = 200) { const serialized = this.stringify(obj, { fastMode: true, maxLength, maxDepth: 3, truncateStrings: 50 }); console.log(`[DEBUG] ${label}: ${serialized}`); } /** * **AUDIT: Safe audit logging with full details** */ static auditLog(obj) { return this.stringify(obj, { fastMode: false, maxDepth: 8, maxLength: 5000, truncateStrings: 500, includeNonEnumerable: false }); } } SafeSerializer.DEFAULT_OPTIONS = { maxDepth: 10, maxLength: 10000, includeNonEnumerable: false, truncateStrings: 1000, fastMode: false }; // Cache key generation const generateSafeCacheKey = (args, prefix) => SafeSerializer.generateCacheKey(args, prefix); // Debug logging const debugLog = (label, obj) => SafeSerializer.debugLog(label, obj); exports.SafeSerializer = SafeSerializer; exports.debugLog = debugLog; exports.generateSafeCacheKey = generateSafeCacheKey; //# sourceMappingURL=safe-serializer.js.map