"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InjectionDetector = void 0;
const DEFAULT_CONFIG = {
    enabled: true,
    sensitivity: 'high',
    patterns: [
        'ignore previous instructions',
        'ignore all previous instructions',
        'you are now',
        'you have become',
        'forget everything',
        'disregard',
        'ignore the above',
        'ignore what I said before',
        'new instructions:',
        'system:',
        'assistant:',
        'user:',
        'human:',
        'ignore safety',
        'bypass',
        'override'
    ],
    action: 'block'
};
class InjectionDetector {
    constructor(config) {
        this.config = { ...DEFAULT_CONFIG, ...config };
    }
    detect(input) {
        if (!this.config.enabled) {
            return null;
        }
        const inputText = this.extractText(input);
        if (!inputText) {
            return null;
        }
        const patterns = this.config.patterns;
        const detectedPatterns = [];
        const details = {};
        const lowerText = inputText.toLowerCase();
        for (const pattern of patterns) {
            if (lowerText.includes(pattern.toLowerCase())) {
                detectedPatterns.push(pattern);
            }
        }
        const encodedContent = this.checkForEncodedContent(inputText);
        if (encodedContent.detected) {
            detectedPatterns.push(...encodedContent.patterns);
            details['encodedContent'] = encodedContent;
        }
        const hiddenText = this.checkForHiddenText(inputText);
        if (hiddenText.detected) {
            detectedPatterns.push(...hiddenText.patterns);
            details['hiddenText'] = hiddenText;
        }
        const roleManipulation = this.checkForRoleManipulation(inputText);
        if (roleManipulation.detected) {
            detectedPatterns.push(...roleManipulation.patterns);
            details['roleManipulation'] = roleManipulation;
        }
        if (detectedPatterns.length === 0) {
            return null;
        }
        const severity = this.calculateSeverity(detectedPatterns, encodedContent, hiddenText, roleManipulation);
        const confidence = this.calculateConfidence(detectedPatterns, encodedContent, hiddenText, roleManipulation);
        const action = this.determineAction(severity, confidence);
        let sanitizedInput = input;
        if (action === 'mask' || action === 'block') {
            sanitizedInput = this.sanitizeInput(input, detectedPatterns);
        }
        return {
            detected: true,
            severity,
            patterns: detectedPatterns,
            confidence,
            details,
            action,
            sanitizedInput: action !== 'flag' ? sanitizedInput : undefined
        };
    }
    checkForEncodedContent(text) {
        const patterns = [];
        const details = {};
        const base64Pattern = /[A-Za-z0-9+/]{20,}={0,2}/g;
        const base64Matches = text.match(base64Pattern);
        if (base64Matches && base64Matches.length > 0) {
            patterns.push('Base64 encoded content');
            details['base64Matches'] = base64Matches.length;
            details['base64Samples'] = base64Matches.slice(0, 3);
        }
        const hexPattern = /[0-9a-fA-F]{16,}/g;
        const hexMatches = text.match(hexPattern);
        if (hexMatches && hexMatches.length > 0) {
            patterns.push('Hex encoded content');
            details['hexMatches'] = hexMatches.length;
            details['hexSamples'] = hexMatches.slice(0, 3);
        }
        const urlEncodedPattern = /%[0-9a-fA-F]{2}/g;
        const urlEncodedMatches = text.match(urlEncodedPattern);
        if (urlEncodedMatches && urlEncodedMatches.length > 5) {
            patterns.push('URL encoded content');
            details['urlEncodedMatches'] = urlEncodedMatches.length;
        }
        return {
            detected: patterns.length > 0,
            patterns,
            details
        };
    }
    checkForHiddenText(text) {
        const patterns = [];
        const details = {};
        const zeroWidthPattern = /[\u200B-\u200D\uFEFF]/g;
        const zeroWidthMatches = text.match(zeroWidthPattern);
        if (zeroWidthMatches && zeroWidthMatches.length > 0) {
            patterns.push('Zero-width characters');
            details['zeroWidthCount'] = zeroWidthMatches.length;
        }
        const invisiblePattern = /[\u2060-\u206F]/g;
        const invisibleMatches = text.match(invisiblePattern);
        if (invisibleMatches && invisibleMatches.length > 0) {
            patterns.push('Invisible Unicode characters');
            details['invisibleCount'] = invisibleMatches.length;
        }
        return {
            detected: patterns.length > 0,
            patterns,
            details
        };
    }
    checkForRoleManipulation(text) {
        const patterns = [];
        const details = {};
        const lowerText = text.toLowerCase();
        const rolePatterns = [
            /you are (now|currently) (a|an) (.+)/i,
            /act as (a|an) (.+)/i,
            /pretend to be (a|an) (.+)/i,
            /roleplay as (a|an) (.+)/i
        ];
        for (const pattern of rolePatterns) {
            const match = lowerText.match(pattern);
            if (match) {
                patterns.push('Role manipulation attempt');
                details['roleMatch'] = match[0];
                break;
            }
        }
        return {
            detected: patterns.length > 0,
            patterns,
            details
        };
    }
    calculateSeverity(patterns, encodedContent, hiddenText, roleManipulation) {
        let score = 0;
        score += patterns.length;
        if (encodedContent.detected) {
            score += 2;
        }
        if (hiddenText.detected) {
            score += 2;
        }
        if (roleManipulation.detected) {
            score += 3;
        }
        if (score >= 5)
            return 'critical';
        if (score >= 3)
            return 'high';
        if (score >= 2)
            return 'medium';
        return 'low';
    }
    calculateConfidence(patterns, encodedContent, hiddenText, roleManipulation) {
        let confidence = 0.5;
        confidence += Math.min(patterns.length * 0.1, 0.3);
        if (encodedContent.detected || hiddenText.detected) {
            confidence += 0.2;
        }
        if (roleManipulation.detected) {
            confidence += 0.2;
        }
        return Math.min(confidence, 1.0);
    }
    determineAction(severity, confidence) {
        if (this.config.action !== 'flag' && severity !== 'critical') {
            return this.config.action;
        }
        if (severity === 'critical') {
            return 'block';
        }
        if (severity === 'high' && confidence > 0.7) {
            return 'block';
        }
        if (severity === 'high') {
            return 'require_approval';
        }
        if (severity === 'medium') {
            return 'flag';
        }
        return 'flag';
    }
    sanitizeInput(input, patterns) {
        if (typeof input === 'string') {
            let sanitized = input;
            for (const pattern of patterns) {
                const regex = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
                sanitized = sanitized.replace(regex, '[REDACTED]');
            }
            return sanitized;
        }
        if (typeof input === 'object' && input !== null) {
            const sanitized = Array.isArray(input) ? [] : {};
            for (const [key, value] of Object.entries(input)) {
                sanitized[key] = this.sanitizeInput(value, patterns);
            }
            return sanitized;
        }
        return input;
    }
    extractText(input) {
        if (typeof input === 'string') {
            return input;
        }
        if (typeof input === 'object' && input !== null) {
            if (input.text)
                return String(input.text);
            if (input.content)
                return String(input.content);
            if (input.message)
                return String(input.message);
            if (input.prompt)
                return String(input.prompt);
            if (input.input)
                return String(input.input);
            try {
                return JSON.stringify(input);
            }
            catch {
                return null;
            }
        }
        return String(input);
    }
    updateConfig(config) {
        this.config = { ...this.config, ...config };
    }
    getConfig() {
        return { ...this.config };
    }
}
exports.InjectionDetector = InjectionDetector;
//# sourceMappingURL=injection-detector.js.map