<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Minecraft Protector IDE</title>

        <style>
            @font-face {
                font-family: 'Montserrat';
                font-style: normal;
                font-weight: 400;
                src: url('/static/fonts/montserrat/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2') format('woff2');
            }
            @font-face {
                font-family: 'Montserrat';
                font-style: normal;
                font-weight: 600;
                src: url('/static/fonts/montserrat/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2') format('woff2');
            }
            @font-face {
                font-family: 'Roboto Mono';
                font-style: normal;
                font-weight: 400;
                src: url('/static/fonts/roboto-mono/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_SeW4Ep0.woff2') format('woff2');
            }
        </style>

        <link href="/static/css/bootstrap.min.css" rel="stylesheet">
        <link href="/static/css/codemirror.min.css" rel="stylesheet">
        <link href="/static/style.css" rel="stylesheet">
    </head>
<body>
    <nav class="navbar navbar-dark bg-primary mb-4">
        <div class="container">
            <span class="navbar-brand mb-0 h1">Minecraft Protector IDE</span>
        </div>
    </nav>

    <div class="container">
        <div id="validation-error-container" style="display: none;"></div>

        <div class="row">
            <div class="col-md-8">
                <div class="card mb-4">
                    <div class="card-header bg-light">
                        <h5 class="mb-0">Редактор</h5>
                    </div>
                    <div class="card-body">
                        <textarea id="rules-editor" class="form-control"></textarea>
                    </div>
                    <div class="card-footer">
                        <button class="btn btn-warning" onclick="testRules()" id="test-btn">
                            <i class="bi bi-play-circle"></i> Отправить на проверку
                        </button>
                    </div>
                </div>

                <div class="card mb-4">
                    <div class="card-header bg-light d-flex justify-content-between align-items-center"
                         style="cursor: pointer;" onclick="toggleExampleRules()">
                        <h5 class="mb-0">Инструкция</h5>
                        <span id="example-rules-toggle">▼</span>
                    </div>
                    <div class="card-body" id="example-rules-content" style="display: none;">
                        <div id="example-rules-text">
# Инструкция
Для успешного выполнения задания, вам необходимо написать одно или несколько правил для IDS Suricata
Система обрабатывает не более 3 правил.

# Структура правила
действие протокол IP-источник порт-источник -> IP-назначение порт-назначение (ключевое слово: значение;)

# В данном задании используйте следующую структуру для корректной работы:
alert http any any -> any any (ключевое слово: значение; ...)

# Параметры тела правила
msg - сообщение, описывающее правило
content - шаблон для поиска в трафике
sid - уникальный идентификатор правила
rev - версия правила
classtype - тип атаки
priority - приоритет правила
flow - направление потока данных (to_client, to_server, from_client, from_server, established, stateless)
pcre - регулярные выражения для поиска в трафике
threshold - пороговое значение сработки
nocase - флаг, чтобы не учитывать регистр
depth - глубина поиска от начала
offset - смещение от начала
distance - расстояние от предыдущего content
http_method - флаг, метод запроса
http_uri - флаг, uri запроса
http_header - флаг, заголовки http
http_cookie - флаг, cookie
http_client_body - флаг, тело запроса
http_server_body - флаг, тело ответа
http_user_agent - флаг, user-agent
http_host - флаг, заголовок host
http_raw_uri - флаг, необработанный uri
http_stat_code - флаг, статус код ответа
http_stat_msg - флаг, сообщение статуса
                        </div>
                    </div>
                </div>
            </div>

            <div class="col-md-4">
                <div class="card mb-4">
                    <div class="card-header bg-info text-white">
                        <h5 class="mb-0">Результаты тестов</h5>
                    </div>
                    <div class="card-body">
                        <div id="stats">
                            <div class="mb-3">
                                <h6>False Positives</h6>
                                <p></p>
                                <div class="d-flex justify-content-between">
                                    <span>Обнаружено:</span>
                                    <span class="badge bg-danger" id="fp-count">0</span>
                                </div>
                                <div class="d-flex justify-content-between">
                                    <span>Всего:</span>
                                    <span class="badge bg-secondary" id="fp-total">0</span>
                                </div>
                                <small class="text-muted">Должно быть 0</small>
                            </div>

                            <div class="mb-3">
                                <h6>True Positives</h6>
                                <p></p>
                                <div class="d-flex justify-content-between">
                                    <span>Обнаружено:</span>
                                    <span class="badge bg-success" id="tp-count">0</span>
                                </div>
                                <div class="d-flex justify-content-between">
                                    <span>Всего:</span>
                                    <span class="badge bg-secondary" id="tp-total">0</span>
                                </div>
                                <small class="text-muted">Должны быть все</small>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="card mb-4">
                    <div class="card-body text-center">
                        <button class="btn btn-secondary" onclick="downloadLog()">
                            <i class="bi bi-download"></i> Скачать логи атаки на Minecraft сервер
                        </button>
                    </div>
                </div>
            </div>
        </div>

        <div class="row results-panel">
            <div class="col-md-6">
                <div class="card results-card">
                    <div class="card-header bg-danger text-white">
                        <h5 class="mb-0">False Positives</h5>
                    </div>
                    <div class="card-body" style="display: flex; flex-direction: column; overflow: hidden; padding: 15px;">
                        <div class="results-header" style="flex-shrink: 0; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid #dee2e6;">
                            <p>Нормальный трафик, на который НЕ должны срабатывать правила</p>
                            <p><strong>Алерты: <span id="fp-alerts-count">0</span></strong></p>
                        </div>
                        <div id="fp-results" style="flex: 1; overflow-y: auto; max-height: none;">
                            <p class="text-muted text-center">Событий не найдено</p>
                        </div>
                    </div>
                </div>
            </div>

            <div class="col-md-6">
                <div class="card results-card">
                    <div class="card-header bg-success text-white">
                        <h5 class="mb-0">True Positives</h5>
                    </div>
                    <div class="card-body" style="display: flex; flex-direction: column; overflow: hidden; padding: 15px;">
                        <div class="results-header" style="flex-shrink: 0; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid #dee2e6;">
                            <p>Вредоносный трафик, на который ДОЛЖНЫ срабатывать правила</p>
                            <p><strong>Алерты: <span id="tp-alerts-count">0</span></strong></p>
                        </div>
                        <div id="tp-results" style="flex: 1; overflow-y: auto; max-height: none;">
                            <p class="text-muted text-center">Событий не найдено</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="alertModal" tabindex="-1">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Детали события</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <pre id="alert-json" class="bg-dark text-light p-3 rounded"></pre>
                </div>
            </div>
        </div>
    </div>

    <script src="/static/js/bootstrap.bundle.min.js"></script>

    <script src="/static/js/codemirror.min.js"></script>
    <script src="/static/js/yaml.min.js"></script>

    <script>
        const editor = CodeMirror.fromTextArea(document.getElementById('rules-editor'), {
            lineNumbers: true,
            mode: 'yaml',
            theme: 'default',
            lineWrapping: true,
            autofocus: true,
            styleActiveLine: false,
            matchBrackets: false,
            autoCloseBrackets: false,
            highlightSelectionMatches: false,
            showCursorWhenSelecting: false,
            styleSelectedText: false
        });
        editor.setOption('highlightFormatting', false);
        editor.setOption('highlightSelectionMatches', false);

        function toggleExampleRules() {
            const content = document.getElementById('example-rules-content');
            const toggle = document.getElementById('example-rules-toggle');

            if (content.style.display === 'none') {
                content.style.display = 'block';
                toggle.textContent = '▲';
            } else {
                content.style.display = 'none';
                toggle.textContent = '▼';
            }
        }

        function loadRules() {
            fetch('/api/rules')
                .then(r => r.json())
                .then(data => {
                    editor.setValue(data.rules);
                });
        }

        function saveRules() {
            fetch('/api/rules', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({rules: editor.getValue()})
            });
        }

        function downloadLog() {
            window.open('/static/suricata.log', '_blank');
        }

        function clearValidationError() {
            const container = document.getElementById('validation-error-container');
            container.style.display = 'none';
            container.innerHTML = '';
        }

        function showValidationError(errorMessage) {
            const container = document.getElementById('validation-error-container');
            container.innerHTML = `
                <div class="alert alert-danger">
                    <h5>Ошибка валидации правил</h5>
                    <pre style="max-height: 300px; overflow-y: auto; white-space: pre-wrap;" class="mt-3">${errorMessage}</pre>
                </div>
            `;
            container.style.display = 'block';

            container.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }

        function testRules() {
            const btn = document.getElementById('test-btn');
            const originalText = btn.innerHTML;
            btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
            btn.disabled = true;

            clearValidationError();
            document.getElementById('fp-results').innerHTML = '';
            document.getElementById('tp-results').innerHTML = '';

            document.getElementById('fp-results').innerHTML = '<div class="text-center"><div class="spinner-border text-danger"></div></div>';
            document.getElementById('tp-results').innerHTML = '<div class="text-center"><div class="spinner-border text-success"></div></div>';

            // Получаем правила из редактора и отправляем на сервер
            const rulesText = editor.getValue();

            fetch('/api/test', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({rules: rulesText})
            })
            .then(r => r.json())
            .then(data => {
                btn.innerHTML = originalText;
                btn.disabled = false;

                document.getElementById('fp-results').innerHTML = '';
                document.getElementById('tp-results').innerHTML = '';

                if (data.validation_error) {
                    showValidationError(data.validation_error);
                    return;
                }

                if (data.error) {
                    alert('Error: ' + data.error);
                    return;
                }

                document.getElementById('tp-total').textContent = data.tp_total;
                document.getElementById('tp-count').textContent = data.tp_count;
                document.getElementById('fp-total').textContent = data.fp_total;
                document.getElementById('fp-count').textContent = data.fp_count;

                document.getElementById('tp-alerts-count').textContent = data.tp_count;
                document.getElementById('fp-alerts-count').textContent = data.fp_count;

                const fpResults = document.getElementById('fp-results');
                if (data.fp_alerts && data.fp_alerts.length > 0) {
                    let html = '<div style="display: flex; flex-direction: column; gap: 8px;">';
                    data.fp_alerts.forEach((alert, index) => {
                        const id = alert.detected_request_id || '?';
                        html += `
                            <div class="card">
                                <div class="card-body p-2">
                                    <div class="d-flex justify-content-between align-items-start">
                                        <div style="min-width: 0; flex: 1;">
                                            <strong class="text-danger">ID ${id}</strong><br>
                                            <small style="word-break: break-word;">${alert.alert?.signature || 'Alert'}</small>
                                        </div>
                                        <button class="btn btn-sm btn-outline-primary" style="flex-shrink: 0;" onclick="showAlertDetails(${index}, 'fp')">
                                            Детали
                                        </button>
                                    </div>
                                </div>
                            </div>
                        `;
                    });
                    html += '</div>';
                    fpResults.innerHTML = html;
                } else {
                    fpResults.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%;"><p class="text-muted">False Positive не найдено</p></div>';
                }

                const tpResults = document.getElementById('tp-results');
                if (data.tp_alerts && data.tp_alerts.length > 0) {
                    let html = '<div style="display: flex; flex-direction: column; gap: 8px;">';
                    data.tp_alerts.forEach((alert, index) => {
                        const id = alert.detected_request_id || '?';
                        html += `
                            <div class="card">
                                <div class="card-body p-2">
                                    <div class="d-flex justify-content-between align-items-start">
                                        <div style="min-width: 0; flex: 1;">
                                            <strong class="text-success">ID ${id}</strong><br>
                                            <small style="word-break: break-word;">${alert.alert?.signature || 'Alert'}</small>
                                        </div>
                                        <button class="btn btn-sm btn-outline-primary" style="flex-shrink: 0;" onclick="showAlertDetails(${index}, 'tp')">
                                            Детали
                                        </button>
                                    </div>
                                </div>
                            </div>
                        `;
                    });
                    html += '</div>';
                    tpResults.innerHTML = html;
                } else {
                    tpResults.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%;"><p class="text-muted">True Positive не найдено</p></div>';
                }

                window.tpAlerts = data.tp_alerts || [];
                window.fpAlerts = data.fp_alerts || [];

                if (data.perfect_detection && data.flag) {
                    alert(`FLAG: ${data.flag}`);
                }
            })
            .catch(error => {
                btn.innerHTML = originalText;
                btn.disabled = false;
                showValidationError('Ошибка сети: ' + error);
            });
        }

        function showAlertDetails(index, type) {
            let alert;
            if (type === 'tp' && window.tpAlerts && window.tpAlerts[index]) {
                alert = window.tpAlerts[index];
            } else if (type === 'fp' && window.fpAlerts && window.fpAlerts[index]) {
                alert = window.fpAlerts[index];
            } else {
                return;
            }

            const modal = new bootstrap.Modal(document.getElementById('alertModal'));
            document.getElementById('alert-json').textContent =
                JSON.stringify(alert, null, 2);
            modal.show();
        }

        window.onload = loadRules;
    </script>
</body>
</html>