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.

198 lines (194 loc) 7.18 kB
'use strict'; var secureMemory = require('../../secure-memory.js'); var secureStringCore = require('../../secure-string/core/secure-string-core.js'); require('crypto'); require('../../secure-string/advanced/entropy-analyzer.js'); require('../../secure-string/advanced/quantum-safe.js'); require('../../secure-string/advanced/performance-monitor.js'); /** * Serialization Handler Module * Handles object serialization and format conversion */ /** * Handles serialization operations for SecureObject */ class SerializationHandler { constructor(cryptoHandler, metadataManager) { this.cryptoHandler = cryptoHandler; this.metadataManager = metadataManager; } /** * Converts SecureObject data to a regular object */ toObject(data, sensitiveKeys, options = {}) { const result = {}; for (const [key, value] of data.entries()) { const metadata = this.metadataManager.get(key); const isUserDefinedSensitive = typeof sensitiveKeys === "function" ? sensitiveKeys(key) : sensitiveKeys.has(key); // Handle sensitive keys if (isUserDefinedSensitive) { if (options.encryptSensitive) { // Encrypt user-defined sensitive data let valueToEncrypt; if (value instanceof secureMemory.SecureBuffer) { const buffer = value.getBuffer(); if (metadata?.type === "Uint8Array") { valueToEncrypt = Array.from(new Uint8Array(buffer)); } else { valueToEncrypt = new TextDecoder().decode(buffer); } } else if (value instanceof secureStringCore.SecureString) { valueToEncrypt = value.toString(); } else { valueToEncrypt = value; } result[key] = this.cryptoHandler.encryptValue(valueToEncrypt); } // If encryptSensitive is false, skip sensitive keys (filter them out) // This is the fix for the nested password filtering bug } else { // Normal processing - show actual values for non-sensitive keys result[key] = this.processValue(value, metadata, options, sensitiveKeys); } } if (options.includeMetadata) { result._metadata = this.metadataManager.toObject(); } return this.applyFormat(result, options); } /** * Processes a single value for serialization */ processValue(value, metadata, options, sensitiveKeys) { if (value instanceof secureMemory.SecureBuffer) { const buffer = value.getBuffer(); if (metadata?.type === "Uint8Array") { // Return as Uint8Array for binary data return new Uint8Array(buffer); } else { // Return as string for text data return new TextDecoder().decode(buffer); } } else if (value instanceof secureStringCore.SecureString) { return value.toString(); } else if (value && typeof value === "object" && typeof value.toObject === "function") { // For nested SecureObjects, recursively process with the same options // Pass through the strictSensitiveKeys option to maintain consistency return value.toObject(options); } else if (typeof value === "object" && value !== null) { // For regular nested objects, recursively check for sensitive keys // FIXED: Pass the actual sensitive keys instead of empty Set return this.cryptoHandler.processNestedObject(value, options, sensitiveKeys); } else { return value; } } /** * Applies format transformation to the result */ applyFormat(result, options) { if (options.format === "binary") { // Convert to binary format (Uint8Array) const jsonString = JSON.stringify(result); return new TextEncoder().encode(jsonString); } else if (options.format === "json") { // Return as JSON string return JSON.stringify(result); } // Default: return as regular object return result; } /** * Converts to JSON string */ toJSON(data, sensitiveKeys, options = {}) { const obj = this.toObject(data, sensitiveKeys, options); return JSON.stringify(obj); } /** * Creates a deterministic representation for hashing */ createHashableRepresentation(entries) { const sortedEntries = entries.sort(([a], [b]) => String(a).localeCompare(String(b))); return JSON.stringify(sortedEntries.map(([key, value]) => [ String(key), typeof value === "object" && value instanceof Uint8Array ? Array.from(value) : value, ])); } /** * Processes nested objects recursively for sensitive key detection */ processNestedObject(obj, options, sensitiveKeys) { return this.cryptoHandler.processNestedObject(obj, options, sensitiveKeys); } /** * Validates serialization options */ validateOptions(options) { if (options.format && !["json", "binary"].includes(options.format)) { throw new Error(`Invalid format option: ${options.format}. Must be 'json' or 'binary'.`); } } /** * Gets serialization statistics */ getSerializationStats(data) { let secureBufferCount = 0; let secureStringCount = 0; let nestedObjectCount = 0; let primitiveCount = 0; for (const value of data.values()) { if (value instanceof secureMemory.SecureBuffer) { secureBufferCount++; } else if (value instanceof secureStringCore.SecureString) { secureStringCount++; } else if (typeof value === "object" && value !== null) { nestedObjectCount++; } else { primitiveCount++; } } return { totalKeys: data.size, secureBufferCount, secureStringCount, nestedObjectCount, primitiveCount, }; } /** * Estimates serialized size */ estimateSerializedSize(data, options = {}) { try { const serialized = this.toJSON(data, new Set(), options); return new TextEncoder().encode(serialized).length; } catch (error) { // Fallback estimation return data.size * 50; // Rough estimate } } } exports.SerializationHandler = SerializationHandler; //# sourceMappingURL=serialization-handler.js.map