"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isUnsafeZipEntryPath = isUnsafeZipEntryPath;
exports.validateZipArchiveSecurity = validateZipArchiveSecurity;
const bundleSecurityLimits_1 = require("./bundleSecurityLimits");
const validateCustomAIBundle_1 = require("./validateCustomAIBundle");
function getExtension(filePath) {
    const base = filePath.split('/').pop() ?? filePath;
    const dot = base.lastIndexOf('.');
    if (dot <= 0) {
        return '';
    }
    return base.slice(dot).toLowerCase();
}
function isBlockedMacOsMetadata(entryPath) {
    const normalized = (0, validateCustomAIBundle_1.normalizeZipEntryPath)(entryPath);
    return (normalized.startsWith('__MACOSX/') ||
        normalized.includes('/__MACOSX/') ||
        normalized.endsWith('.DS_Store'));
}
function isUnsafeZipEntryPath(entryPath) {
    const slashNormalized = entryPath.replace(/\\/g, '/');
    if (slashNormalized.includes('\0')) {
        return `Unsafe zip entry: ${entryPath}`;
    }
    if (slashNormalized.startsWith('/') || /^[a-zA-Z]:/.test(slashNormalized)) {
        return `Zip entry must be relative (no absolute paths): ${entryPath}`;
    }
    const normalized = (0, validateCustomAIBundle_1.normalizeZipEntryPath)(entryPath);
    if (!normalized) {
        return 'Zip contains an empty entry path';
    }
    if (normalized.includes('../') || normalized.includes('..\\')) {
        return `Zip entry must not use parent paths: ${entryPath}`;
    }
    const segments = normalized.split('/');
    if (segments.some((segment) => segment === '..')) {
        return `Zip entry must not traverse directories: ${entryPath}`;
    }
    return null;
}
function isUnderNodeModules(entryPath) {
    const normalized = (0, validateCustomAIBundle_1.normalizeZipEntryPath)(entryPath);
    if (normalized === 'node_modules' || normalized.startsWith('node_modules/')) {
        return true;
    }
    const slash = normalized.indexOf('/');
    if (slash > 0) {
        const rest = normalized.slice(slash + 1);
        return rest === 'node_modules' || rest.startsWith('node_modules/');
    }
    return false;
}
function isAllowedSourceFile(entryPath) {
    if (isUnderNodeModules(entryPath)) {
        const ext = getExtension(entryPath);
        if (ext && bundleSecurityLimits_1.CUSTOM_AI_BLOCKED_EXTENSIONS.has(ext)) {
            return false;
        }
        return true;
    }
    const ext = getExtension(entryPath);
    if (!ext) {
        return false;
    }
    if (bundleSecurityLimits_1.CUSTOM_AI_BLOCKED_EXTENSIONS.has(ext)) {
        return false;
    }
    //return CUSTOM_AI_ALLOWED_EXTENSIONS.has(ext);
    return true;
}
function validateZipArchiveSecurity(zip, compressedSize) {
    const errors = [];
    const fileEntries = zip.getEntries().filter((entry) => !entry.isDirectory);
    if (fileEntries.length === 0) {
        return ['Zip file does not contain any files'];
    }
    let sourceFileCount = 0;
    let nodeModulesFileCount = 0;
    let uncompressedTotal = 0;
    for (const entry of fileEntries) {
        const entryPath = entry.entryName;
        const unsafeReason = isUnsafeZipEntryPath(entryPath);
        if (unsafeReason) {
            errors.push(unsafeReason);
            continue;
        }
        if (isBlockedMacOsMetadata(entryPath)) {
            continue;
        }
        const normalized = (0, validateCustomAIBundle_1.normalizeZipEntryPath)(entryPath);
        if (!isAllowedSourceFile(normalized)) {
            errors.push(`Disallowed file type in zip: ${normalized}`);
        }
        if (isUnderNodeModules(normalized)) {
            nodeModulesFileCount += 1;
        }
        else {
            sourceFileCount += 1;
        }
        const headerSize = entry.header?.size ?? 0;
        uncompressedTotal += headerSize;
        if (uncompressedTotal > bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_UNCOMPRESSED_BYTES) {
            errors.push(`Zip uncompressed size exceeds limit (${bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_UNCOMPRESSED_BYTES} bytes)`);
            break;
        }
    }
    if (sourceFileCount > bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_FILE_COUNT) {
        errors.push(`Zip contains too many non-node_modules files (max ${bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_FILE_COUNT})`);
    }
    if (nodeModulesFileCount > bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_NODE_MODULES_FILE_COUNT) {
        errors.push(`Zip node_modules contains too many files (max ${bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_NODE_MODULES_FILE_COUNT})`);
    }
    if (compressedSize > 0 && uncompressedTotal > 0) {
        const ratio = uncompressedTotal / compressedSize;
        if (ratio > bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_COMPRESSION_RATIO) {
            errors.push(`Zip compression ratio too high (${ratio.toFixed(1)}:1, max ${bundleSecurityLimits_1.CUSTOM_AI_BUNDLE_MAX_COMPRESSION_RATIO}:1)`);
        }
    }
    return errors;
}
//# sourceMappingURL=validateZipArchiveSecurity.js.map