diff --git a/static/js/logs.js b/static/js/logs.js index 5fe277c..23045ec 100644 --- a/static/js/logs.js +++ b/static/js/logs.js @@ -1,22 +1,92 @@ -document.getElementById('filter_status')?.addEventListener('change', filterLogs); -document.getElementById('filter_threat')?.addEventListener('change', filterLogs); -document.getElementById('filter_method')?.addEventListener('change', filterLogs); -document.getElementById('filter_threats_only')?.addEventListener('change', filterLogs); - -function filterLogs() { - const statusFilter = document.getElementById('filter_status')?.value; - const threatFilter = document.getElementById('filter_threat')?.value; - const methodFilter = document.getElementById('filter_method')?.value; - const threatsOnly = document.getElementById('filter_threats_only')?.checked; +document.addEventListener('DOMContentLoaded', function() { + const filterIp = document.getElementById('filter_ip'); + const filterStatus = document.getElementById('filter_status'); + const filterMethod = document.getElementById('filter_method'); + const filterThreats = document.getElementById('filter_threats'); + const resetBtn = document.getElementById('reset_filters'); - document.querySelectorAll('.log-row').forEach(row => { - let show = true; + const logsTable = document.getElementById('logs_table'); + const allRows = Array.from(document.querySelectorAll('.log-row')); + + // Filter function + function applyFilters() { + const ipValue = filterIp.value.toLowerCase(); + const statusValue = filterStatus.value; + const methodValue = filterMethod.value; + const showThreats = filterThreats.checked; - if (statusFilter && row.dataset.status !== statusFilter) show = false; - if (threatFilter && row.dataset.threat !== threatFilter) show = false; - if (methodFilter && row.dataset.method !== methodFilter) show = false; - if (threatsOnly && row.dataset.threatCount === '0') show = false; + let visibleCount = 0; + let threatCount = 0; + let count2xx = 0, count4xx = 0, count5xx = 0; + const uniqueIps = new Set(); - row.style.display = show ? '' : 'none'; + allRows.forEach(row => { + const ip = row.dataset.ip; + const status = row.dataset.status; + const method = row.dataset.method; + const hasThreat = row.dataset.threats === '1'; + + let show = true; + + // IP filter + if (ipValue && !ip.includes(ipValue)) { + show = false; + } + + // Status filter + if (statusValue) { + const statusStart = statusValue; + if (!status.startsWith(statusStart)) { + show = false; + } + } + + // Method filter + if (methodValue && method !== methodValue) { + show = false; + } + + // Threats filter + if (!showThreats && hasThreat) { + show = false; + } + + row.style.display = show ? '' : 'none'; + + if (show) { + visibleCount++; + if (hasThreat) threatCount++; + if (status.startsWith('2')) count2xx++; + if (status.startsWith('4')) count4xx++; + if (status.startsWith('5')) count5xx++; + uniqueIps.add(ip); + } + }); + + // Update stats + document.getElementById('stat_total').textContent = visibleCount; + document.getElementById('stat_threats').textContent = threatCount; + document.getElementById('stat_2xx').textContent = count2xx; + document.getElementById('stat_4xx').textContent = count4xx; + document.getElementById('stat_5xx').textContent = count5xx; + document.getElementById('stat_ips').textContent = uniqueIps.size; + } + + // Event listeners + filterIp.addEventListener('input', applyFilters); + filterStatus.addEventListener('change', applyFilters); + filterMethod.addEventListener('change', applyFilters); + filterThreats.addEventListener('change', applyFilters); + + // Reset button + resetBtn.addEventListener('click', function() { + filterIp.value = ''; + filterStatus.value = ''; + filterMethod.value = ''; + filterThreats.checked = true; + applyFilters(); }); -} \ No newline at end of file + + // Initial stats + applyFilters(); +}); \ No newline at end of file diff --git a/templates/logs.html b/templates/logs.html index 47a26e0..546f4ae 100644 --- a/templates/logs.html +++ b/templates/logs.html @@ -2,151 +2,165 @@ {% set active_page = "logs" %} -{% block title %}HAProxy • Access Logs{% endblock %} +{% block title %}HAProxy • Logs{% endblock %} -{% block breadcrumb %}Access Logs{% endblock %} +{% block breadcrumb %}Logs{% endblock %} {% block content %}
-
HAProxy Access Logs & Security Analysis
+
HAProxy Access Logs
+ {% if logs %} - -
-
-
-
-
Total Requests
-
{{ logs|length }}
-
-
-
-
-
-
-
Threats Detected
-
- {{ logs|selectattr('is_threat')|list|length }} -
-
-
-
-
-
-
-
Unique IPs
-
- {{ logs|map(attribute='ip_address')|unique|list|length }} -
-
-
-
-
-
-
-
Success Rate
-
- {% set success_count = logs|selectattr('status_code')|selectattr('status_code', 'ge', 200)|selectattr('status_code', 'lt', 300)|list|length %} - {{ ((success_count / logs|length * 100)|round(1)) if logs else 0 }}% -
-
-
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+ +
+
- -
-
-
Filters
-
-
- - -
-
- - -
-
- - -
-
- -
- - -
-
+ +
+
+
+
+
Total
+ {{ logs|length }}
- - -
- - - - - - - - - - - - - {% for log in logs %} - - - - - - - - - {% endfor %} - -
TimestampIP AddressMethodURLStatusThreats
{{ log.timestamp }} - {{ log.ip_address }} - - {{ log.http_method }} - - {{ log.requested_url }} - - {{ log.status_code }} - - {% if log.is_threat %} - {% for threat in log.threats %} - {{ threat }} - {% endfor %} - {% else %} - - {% endif %} -
+
+
+
+
Threats
+ 0 +
+
+
+
+
+
2xx
+ 0 +
+
+
+
+
+
+
4xx
+ 0 +
+
+
+
+
+
+
5xx
+ 0 +
+
+
+
+
+
+
Unique IPs
+ 0 +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + {% for entry in logs %} + + + + + + + + + {% endfor %} + +
TimestampIP AddressHTTP MethodRequested URLStatus CodeAlerts
{{ entry['timestamp'] }} + {{ entry['ip_address'] }} + + {{ entry['http_method'] }} + + {{ entry['requested_url'] }} + + + {{ entry['status_code'] }} + + + {% if entry['xss_alert'] %} + XSS + {% endif %} + {% if entry['sql_alert'] %} + SQL + {% endif %} + {% if entry['put_method'] %} + PUT + {% endif %} + {% if entry['webshell_alert'] %} + Webshell + {% endif %} + {% if entry['illegal_resource'] %} + 403 + {% endif %} +
+
{% else %}
@@ -158,5 +172,4 @@
- {% endblock %}