"use strict";
/**
 * Security Configuration Management
 * Centralised security settings and policy management
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.SecurityProfiles = exports.SecurityPolicyBuilder = exports.SecurityConfigManager = exports.DEFAULT_SECURITY_POLICY = void 0;
exports.getSecurityConfig = getSecurityConfig;
const logger_1 = require("../utils/logger");
const types_1 = require("../core/types");
/**
 * Default security policy with secure defaults
 */
exports.DEFAULT_SECURITY_POLICY = {
    inputValidation: {
        maxFileSize: 1024 * 1024 * 1024, // 1GB
        allowedExtensions: ['.csv', '.tsv', '.txt'],
        allowedMimeTypes: ['text/csv', 'text/plain', 'text/tab-separated-values'],
        allowSymlinks: false,
        maxPathDepth: 10,
        rateLimit: 10, // operations per second
    },
    fileAccess: {
        defaultOperations: ['read', 'metadata'],
        requireIntegrityCheck: true,
        tempFileTimeout: 300000, // 5 minutes
        maxConcurrentHandles: 100,
        auditLogRetention: 86400000, // 24 hours
    },
    errorHandling: {
        hideSystemPaths: true,
        sanitiseErrorMessages: true,
        maxStackTraceDepth: 3,
        logSecurityEvents: true,
    },
    cryptography: {
        hashAlgorithm: 'sha256',
        encryptSensitiveData: true,
        keyDerivationIterations: 100000,
        saltLength: 32,
    },
    network: {
        allowExternalConnections: false,
        allowedDomains: [],
        requestTimeout: 30000, // 30 seconds
        maxRequestSize: 10 * 1024 * 1024, // 10MB
    },
    process: {
        restrictFileSystemAccess: true,
        disableShellExecution: true,
        memoryLimit: 2 * 1024 * 1024 * 1024, // 2GB
        cpuLimit: 80, // 80% CPU usage
    },
};
/**
 * Security Configuration Manager
 */
class SecurityConfigManager {
    static instance;
    config;
    configValidators = new Map();
    sensitiveKeys = new Set();
    constructor() {
        this.config = {
            policy: { ...exports.DEFAULT_SECURITY_POLICY },
            environmentOverrides: new Map(),
            features: {
                enableAdvancedThreatDetection: false,
                enableRealTimeMonitoring: true,
                enableBehaviouralAnalysis: false,
                enableIntrusionDetection: true,
            },
            compliance: {
                enableGDPRMode: false,
                enableSOXCompliance: false,
                enableHIPAAMode: false,
                dataRetentionDays: 30,
            },
        };
        this.initializeValidators();
        this.initializeSensitiveKeys();
        this.loadEnvironmentOverrides();
    }
    static getInstance() {
        if (!SecurityConfigManager.instance) {
            SecurityConfigManager.instance = new SecurityConfigManager();
        }
        return SecurityConfigManager.instance;
    }
    /**
     * Get current security policy
     */
    getSecurityPolicy() {
        return JSON.parse(JSON.stringify(this.config.policy));
    }
    /**
     * Update security policy with validation
     */
    updateSecurityPolicy(updates, context) {
        try {
            // Validate updates
            const validation = this.validatePolicyUpdates(updates);
            if (!validation.isValid) {
                throw types_1.DataPilotError.security(`Security policy validation failed: ${validation.errors.join(', ')}`, 'INVALID_SECURITY_POLICY', context);
            }
            // Apply updates with deep merge
            this.config.policy = this.deepMergePolicy(this.config.policy, updates);
            // Log security policy change
            this.logSecurityEvent('SECURITY_POLICY_UPDATED', {
                updates: this.sanitiseForLogging(updates),
                timestamp: new Date(),
            }, context);
            logger_1.logger.info('Security policy updated', {
                updatedKeys: Object.keys(updates),
                ...context,
            });
        }
        catch (error) {
            logger_1.logger.error('Failed to update security policy', {
                error: error instanceof Error ? error.message : 'Unknown error',
                ...context,
            });
            throw error;
        }
    }
    /**
     * Apply environment-specific security overrides
     */
    applyEnvironmentOverrides(environment) {
        const overrides = this.config.environmentOverrides.get(environment);
        if (overrides) {
            this.config.policy = this.deepMergePolicy(this.config.policy, overrides);
            logger_1.logger.info('Applied security environment overrides', {
                environment,
                overriddenKeys: Object.keys(overrides),
            });
        }
    }
    /**
     * Get security features configuration
     */
    getSecurityFeatures() {
        return { ...this.config.features };
    }
    /**
     * Enable or disable security features
     */
    updateSecurityFeatures(features, context) {
        const previousFeatures = { ...this.config.features };
        Object.assign(this.config.features, features);
        this.logSecurityEvent('SECURITY_FEATURES_UPDATED', {
            previous: previousFeatures,
            current: this.config.features,
            changes: features,
        }, context);
        logger_1.logger.info('Security features updated', {
            features: Object.keys(features),
            ...context,
        });
    }
    /**
     * Get compliance settings
     */
    getComplianceSettings() {
        return { ...this.config.compliance };
    }
    /**
     * Check if a specific security feature is enabled
     */
    isFeatureEnabled(feature) {
        return this.config.features[feature] || false;
    }
    /**
     * Get effective security policy for environment
     */
    getEffectivePolicy(environment) {
        let policy = { ...this.config.policy };
        if (environment) {
            const overrides = this.config.environmentOverrides.get(environment);
            if (overrides) {
                policy = this.deepMergePolicy(policy, overrides);
            }
        }
        return policy;
    }
    /**
     * Validate current security configuration
     */
    validateConfiguration() {
        const errors = [];
        const warnings = [];
        const recommendations = [];
        const policy = this.config.policy;
        // Validate input validation settings
        if (policy.inputValidation.maxFileSize > 10 * 1024 * 1024 * 1024) {
            warnings.push('Very large maximum file size may pose security risks');
        }
        if (policy.inputValidation.allowSymlinks) {
            warnings.push('Allowing symbolic links may enable path traversal attacks');
        }
        if (policy.inputValidation.rateLimit > 100) {
            warnings.push('High rate limit may allow abuse');
        }
        // Validate file access settings
        if (!policy.fileAccess.requireIntegrityCheck) {
            warnings.push('Disabling integrity checks reduces security');
        }
        if (policy.fileAccess.maxConcurrentHandles > 1000) {
            warnings.push('Very high concurrent handle limit may enable resource exhaustion');
        }
        // Validate error handling
        if (!policy.errorHandling.hideSystemPaths) {
            errors.push('System paths should be hidden in error messages');
        }
        if (!policy.errorHandling.sanitiseErrorMessages) {
            errors.push('Error messages should be sanitised');
        }
        // Validate cryptography settings
        if (policy.cryptography.hashAlgorithm === 'sha256') {
            recommendations.push('Consider upgrading to SHA-512 for enhanced security');
        }
        if (policy.cryptography.keyDerivationIterations < 50000) {
            warnings.push('Low key derivation iterations may be vulnerable to brute force');
        }
        // Validate network settings
        if (policy.network.allowExternalConnections && policy.network.allowedDomains.length === 0) {
            errors.push('External connections allowed but no domains whitelisted');
        }
        // Validate process settings
        if (!policy.process.restrictFileSystemAccess) {
            warnings.push('Unrestricted file system access increases attack surface');
        }
        if (!policy.process.disableShellExecution) {
            errors.push('Shell execution should be disabled for security');
        }
        return {
            isValid: errors.length === 0,
            errors,
            warnings,
            recommendations,
        };
    }
    /**
     * Export security configuration (with sensitive data redacted)
     */
    exportConfiguration(includeSensitive = false) {
        const exported = JSON.parse(JSON.stringify(this.config));
        if (!includeSensitive) {
            // Redact sensitive information
            exported.policy = this.sanitiseForLogging(exported.policy);
        }
        return exported;
    }
    /**
     * Import security configuration with validation
     */
    importConfiguration(configData, context) {
        try {
            // Validate imported configuration
            const validation = this.validateImportedConfig(configData);
            if (!validation.isValid) {
                throw types_1.DataPilotError.security(`Configuration import validation failed: ${validation.errors.join(', ')}`, 'INVALID_IMPORTED_CONFIG', context);
            }
            // Backup current configuration
            const backup = JSON.parse(JSON.stringify(this.config));
            try {
                // Apply imported configuration
                // First validate the structure, then merge with existing config
                const updatedConfig = {
                    ...this.config,
                    ...configData,
                };
                this.config = updatedConfig;
                this.logSecurityEvent('SECURITY_CONFIG_IMPORTED', {
                    timestamp: new Date(),
                }, context);
                logger_1.logger.info('Security configuration imported successfully', context);
            }
            catch (error) {
                // Restore backup on failure
                this.config = backup;
                throw error;
            }
        }
        catch (error) {
            logger_1.logger.error('Failed to import security configuration', {
                error: error instanceof Error ? error.message : 'Unknown error',
                ...context,
            });
            throw error;
        }
    }
    // Private helper methods
    initializeValidators() {
        this.configValidators.set('maxFileSize', (value) => typeof value === 'number' && value > 0 && value <= 100 * 1024 * 1024 * 1024);
        this.configValidators.set('allowedExtensions', (value) => Array.isArray(value) &&
            value.every((ext) => typeof ext === 'string' && ext.startsWith('.')));
        this.configValidators.set('rateLimit', (value) => typeof value === 'number' && value > 0 && value <= 1000);
        this.configValidators.set('hashAlgorithm', (value) => typeof value === 'string' && ['sha256', 'sha512'].includes(value));
    }
    initializeSensitiveKeys() {
        this.sensitiveKeys.add('cryptography.keyDerivationIterations');
        this.sensitiveKeys.add('cryptography.saltLength');
        this.sensitiveKeys.add('network.allowedDomains');
        this.sensitiveKeys.add('process.memoryLimit');
        this.sensitiveKeys.add('process.cpuLimit');
    }
    loadEnvironmentOverrides() {
        // Development environment - more permissive for debugging
        this.config.environmentOverrides.set('development', {
            errorHandling: {
                hideSystemPaths: false,
                sanitiseErrorMessages: false,
                maxStackTraceDepth: 10,
                logSecurityEvents: true,
            },
            inputValidation: {
                maxFileSize: 100 * 1024 * 1024, // 100MB
                allowedExtensions: ['.csv', '.tsv', '.txt', '.json'],
                allowedMimeTypes: ['text/csv', 'text/plain', 'application/json'],
                allowSymlinks: false,
                maxPathDepth: 10,
                rateLimit: 50,
            },
        });
        // Production environment - maximum security
        this.config.environmentOverrides.set('production', {
            errorHandling: {
                hideSystemPaths: true,
                sanitiseErrorMessages: true,
                maxStackTraceDepth: 1,
                logSecurityEvents: true,
            },
            inputValidation: {
                maxFileSize: 50 * 1024 * 1024, // 50MB
                allowedExtensions: ['.csv', '.tsv', '.txt'],
                allowedMimeTypes: ['text/csv', 'text/plain'],
                allowSymlinks: false,
                maxPathDepth: 5,
                rateLimit: 5,
            },
            network: {
                allowExternalConnections: false,
                allowedDomains: [],
                requestTimeout: 5000,
                maxRequestSize: 1024 * 1024,
            },
            process: {
                restrictFileSystemAccess: true,
                disableShellExecution: true,
                memoryLimit: 512 * 1024 * 1024,
                cpuLimit: 1000,
            },
        });
        // CI environment - optimised for testing
        this.config.environmentOverrides.set('ci', {
            inputValidation: {
                maxFileSize: 10 * 1024 * 1024, // 10MB
                allowedExtensions: ['.csv', '.tsv', '.txt'],
                allowedMimeTypes: ['text/csv', 'text/plain'],
                allowSymlinks: false,
                maxPathDepth: 5,
                rateLimit: 100,
            },
            fileAccess: {
                defaultOperations: ['read', 'metadata'],
                requireIntegrityCheck: false,
                tempFileTimeout: 60000, // 1 minute
                maxConcurrentHandles: 10,
                auditLogRetention: 24 * 60 * 60 * 1000, // 24 hours
            },
        });
    }
    validatePolicyUpdates(updates) {
        const errors = [];
        // Recursive validation of nested objects
        const validateObject = (obj, path = '') => {
            for (const [key, value] of Object.entries(obj)) {
                const fullPath = path ? `${path}.${key}` : key;
                const validator = this.configValidators.get(key);
                if (validator && !validator(value)) {
                    errors.push(`Invalid value for ${fullPath}: ${value}`);
                }
                if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
                    validateObject(value, fullPath);
                }
            }
        };
        validateObject(updates);
        return {
            isValid: errors.length === 0,
            errors,
        };
    }
    validateImportedConfig(configData) {
        const errors = [];
        // Check required structure
        if (!configData.policy || typeof configData.policy !== 'object') {
            errors.push('Missing or invalid policy section');
        }
        if (!configData.features || typeof configData.features !== 'object') {
            errors.push('Missing or invalid features section');
        }
        // Validate policy if present
        if (configData.policy) {
            const policyValidation = this.validatePolicyUpdates(configData.policy);
            errors.push(...policyValidation.errors);
        }
        return {
            isValid: errors.length === 0,
            errors,
        };
    }
    deepMergePolicy(target, source) {
        const result = JSON.parse(JSON.stringify(target));
        const merge = (targetObj, sourceObj) => {
            // Use Object.keys() instead of for...in to avoid inherited properties
            for (const key of Object.keys(sourceObj)) {
                // Explicitly check for prototype pollution attempts
                if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
                    continue; // Skip dangerous property names
                }
                if (sourceObj[key] &&
                    typeof sourceObj[key] === 'object' &&
                    !Array.isArray(sourceObj[key])) {
                    if (!targetObj[key])
                        targetObj[key] = {};
                    merge(targetObj[key], sourceObj[key]);
                }
                else {
                    // Safe assignment - key is guaranteed to be a safe property name
                    targetObj[key] = sourceObj[key];
                }
            }
        };
        merge(result, source);
        return result;
    }
    sanitiseForLogging(data) {
        const sanitised = JSON.parse(JSON.stringify(data));
        const sanitise = (obj, path = '') => {
            for (const key in obj) {
                const fullPath = path ? `${path}.${key}` : key;
                if (this.sensitiveKeys.has(fullPath)) {
                    obj[key] = '[REDACTED]';
                }
                else if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
                    sanitise(obj[key], fullPath);
                }
            }
        };
        sanitise(sanitised);
        return sanitised;
    }
    logSecurityEvent(event, data, context) {
        logger_1.logger.info(`Security Configuration Event: ${event}`, {
            ...context,
            securityEvent: event,
            eventData: data,
            timestamp: new Date(),
        });
    }
}
exports.SecurityConfigManager = SecurityConfigManager;
/**
 * Factory function for easy access
 */
function getSecurityConfig() {
    return SecurityConfigManager.getInstance();
}
/**
 * Security policy builder for fluent configuration
 */
class SecurityPolicyBuilder {
    policy = {};
    static create() {
        return new SecurityPolicyBuilder();
    }
    inputValidation(config) {
        this.policy.inputValidation = { ...this.policy.inputValidation, ...config };
        return this;
    }
    fileAccess(config) {
        this.policy.fileAccess = { ...this.policy.fileAccess, ...config };
        return this;
    }
    errorHandling(config) {
        this.policy.errorHandling = { ...this.policy.errorHandling, ...config };
        return this;
    }
    cryptography(config) {
        this.policy.cryptography = { ...this.policy.cryptography, ...config };
        return this;
    }
    network(config) {
        this.policy.network = { ...this.policy.network, ...config };
        return this;
    }
    process(config) {
        this.policy.process = { ...this.policy.process, ...config };
        return this;
    }
    build() {
        return JSON.parse(JSON.stringify(this.policy));
    }
}
exports.SecurityPolicyBuilder = SecurityPolicyBuilder;
/**
 * Pre-defined security profiles
 */
exports.SecurityProfiles = {
    /** High security profile for production environments */
    HIGH_SECURITY: SecurityPolicyBuilder.create()
        .inputValidation({
        maxFileSize: 100 * 1024 * 1024, // 100MB
        allowSymlinks: false,
        rateLimit: 5,
    })
        .fileAccess({
        requireIntegrityCheck: true,
        maxConcurrentHandles: 50,
    })
        .errorHandling({
        hideSystemPaths: true,
        sanitiseErrorMessages: true,
        maxStackTraceDepth: 1,
    })
        .network({
        allowExternalConnections: false,
    })
        .process({
        restrictFileSystemAccess: true,
        disableShellExecution: true,
    })
        .build(),
    /** Balanced security profile for general use */
    BALANCED: SecurityPolicyBuilder.create()
        .inputValidation({
        maxFileSize: 500 * 1024 * 1024, // 500MB
        rateLimit: 10,
    })
        .fileAccess({
        requireIntegrityCheck: true,
    })
        .errorHandling({
        hideSystemPaths: true,
        sanitiseErrorMessages: true,
    })
        .build(),
    /** Development profile with relaxed security for debugging */
    DEVELOPMENT: SecurityPolicyBuilder.create()
        .inputValidation({
        rateLimit: 50,
    })
        .errorHandling({
        hideSystemPaths: false,
        sanitiseErrorMessages: false,
        maxStackTraceDepth: 10,
    })
        .build(),
};
//# sourceMappingURL=security-config.js.map