import { SecurityError } from "./errors";
import { SecurityUtils } from "./security";
import { Validator } from "./validation";
/**
 * 配置安全工具类
 */ export class ConfigSecurity {
    /**
   * 验证配置签名
   */ static async verifySignature(config, signature, options) {
        if (!options.enabled) {
            return true;
        }
        if (!options.publicKey) {
            throw new SecurityError('签名验证需要提供公钥');
        }
        if (!signature || signature.length === 0) {
            throw new SecurityError('签名不能为空');
        }
        try {
            // 使用 Web Crypto API 验证签名
            if (typeof window === 'undefined' || !window.crypto || !window.crypto.subtle) {
                throw new SecurityError('签名验证需要浏览器支持 Web Crypto API');
            }
            // 将配置转换为字符串（用于签名验证）
            // 使用稳定的 JSON 序列化（按键排序）
            const configString = JSON.stringify(config, Object.keys(config).sort());
            const encoder = new TextEncoder();
            const data = encoder.encode(configString);
            // 将签名从 Base64 解码
            const signatureBuffer = Uint8Array.from(atob(signature), (c)=>c.charCodeAt(0));
            // 导入公钥（支持 PEM 格式）
            const algorithm = options.algorithm || 'RSASSA-PKCS1-v1_5';
            let publicKey;
            try {
                // 尝试导入 PEM 格式的公钥
                const pemHeader = '-----BEGIN PUBLIC KEY-----';
                const pemFooter = '-----END PUBLIC KEY-----';
                let pemKey = options.publicKey;
                if (!pemKey.includes(pemHeader)) {
                    pemKey = `${pemHeader}\n${pemKey}\n${pemFooter}`;
                }
                // 将 PEM 转换为 ArrayBuffer
                const pemContents = pemKey.replace(pemHeader, '').replace(pemFooter, '').replace(/\s/g, '');
                const binaryDer = Uint8Array.from(atob(pemContents), (c)=>c.charCodeAt(0));
                publicKey = await window.crypto.subtle.importKey('spki', binaryDer.buffer, {
                    name: algorithm,
                    hash: 'SHA-256'
                }, false, [
                    'verify'
                ]);
            } catch (importError) {
                throw new SecurityError('公钥导入失败', importError instanceof Error ? importError : undefined);
            }
            // 验证签名
            const isValid = await window.crypto.subtle.verify({
                name: algorithm
            }, publicKey, signatureBuffer, data);
            return isValid;
        } catch (error) {
            if (error instanceof SecurityError) {
                throw error;
            }
            throw new SecurityError('签名验证失败', error instanceof Error ? error : undefined);
        }
    }
    /**
   * 验证配置来源
   */ static verifyOrigin(options) {
        if (!options.allowedOrigins || options.allowedOrigins.length === 0) {
            return true; // 如果没有配置白名单，允许所有来源
        }
        if (typeof window === 'undefined') {
            return true; // 非浏览器环境，跳过验证
        }
        const currentOrigin = window.location.origin;
        const referer = document.referrer;
        // 验证当前来源
        if (options.allowedOrigins.includes(currentOrigin)) {
            return true;
        }
        // 验证 Referer
        if (options.verifyReferer && referer) {
            try {
                const refererOrigin = new URL(referer).origin;
                if (options.allowedOrigins.includes(refererOrigin)) {
                    return true;
                }
            } catch  {
            // Referer 解析失败
            }
        }
        return false;
    }
    /**
   * 验证配置白名单
   */ static verifyWhitelist(config, options) {
        const errors = [];
        // 检查允许的键
        if (options.allowedKeys && options.allowedKeys.length > 0) {
            const configKeys = Object.keys(config);
            const invalidKeys = configKeys.filter((key)=>!options.allowedKeys.includes(key));
            if (invalidKeys.length > 0) {
                errors.push(`配置包含不允许的键: ${invalidKeys.join(', ')}`);
            }
        }
        // 检查禁止的键
        if (options.forbiddenKeys && options.forbiddenKeys.length > 0) {
            const configKeys = Object.keys(config);
            const forbiddenFound = configKeys.filter((key)=>options.forbiddenKeys.includes(key));
            if (forbiddenFound.length > 0) {
                errors.push(`配置包含禁止的键: ${forbiddenFound.join(', ')}`);
            }
        }
        // 验证配置值
        if (options.valueSchema) {
            const result = Validator.validateObject(options.valueSchema, config);
            if (!result.valid) {
                errors.push(...result.errors);
            }
        }
        return {
            valid: errors.length === 0,
            errors
        };
    }
    /**
   * 清理配置中的危险内容
   */ static sanitizeConfig(config) {
        const sanitized = {};
        for (const [key, value] of Object.entries(config)){
            if (typeof value === 'string') {
                // 检查是否包含危险内容
                const validation = SecurityUtils.validateInput(value);
                if (validation.safe && validation.sanitized) {
                    sanitized[key] = validation.sanitized;
                } else {
                    // 包含危险内容，跳过或记录警告
                    console.warn(`配置项 ${key} 包含潜在危险内容，已跳过`);
                }
            } else if (value && typeof value === 'object' && !Array.isArray(value)) {
                // 递归清理对象
                sanitized[key] = this.sanitizeConfig(value);
            } else {
                sanitized[key] = value;
            }
        }
        return sanitized;
    }
    /**
   * 验证配置安全性
   */ static async validateConfigSecurity(config, options) {
        const errors = [];
        // 验证来源
        if (options.origin) {
            const originValid = this.verifyOrigin(options.origin);
            if (!originValid) {
                errors.push('配置来源验证失败');
            }
        }
        // 验证白名单
        if (options.whitelist) {
            const whitelistResult = this.verifyWhitelist(config, options.whitelist);
            if (!whitelistResult.valid) {
                errors.push(...whitelistResult.errors);
            }
        }
        // 清理配置（已实现但暂不使用返回值）
        // const sanitizedConfig = this.sanitizeConfig(config);
        return {
            valid: errors.length === 0,
            errors
        };
    }
}

//# sourceMappingURL=configSecurity.js.map