From ed4fe0dcfbf4e6ca0dcb349cf47cdb963c137047 Mon Sep 17 00:00:00 2001 From: Lorenzo Venerandi Date: Sun, 1 Mar 2026 18:01:19 +0100 Subject: [PATCH] feat: Add IP filtering to attack types pagination and detail views --- src/database.py | 19 +++++++++++++++---- src/routes/htmx.py | 5 ++++- .../jinja2/dashboard/partials/_ip_detail.html | 13 +++++++++++++ .../partials/attack_types_table.html | 6 +++--- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/database.py b/src/database.py index 2119893..7375630 100644 --- a/src/database.py +++ b/src/database.py @@ -1955,6 +1955,7 @@ class DatabaseManager: page_size: int = 5, sort_by: str = "timestamp", sort_order: str = "desc", + ip_filter: Optional[str] = None, ) -> Dict[str, Any]: """ Retrieve paginated list of detected attack types with access logs. @@ -1964,6 +1965,7 @@ class DatabaseManager: page_size: Number of results per page sort_by: Field to sort by (timestamp, ip, attack_type) sort_order: Sort order (asc or desc) + ip_filter: Optional IP address to filter results Returns: Dictionary with attacks list and pagination info @@ -1979,18 +1981,27 @@ class DatabaseManager: sort_order.lower() if sort_order.lower() in {"asc", "desc"} else "desc" ) + # Base query filter + base_filters = [] + if ip_filter: + base_filters.append(AccessLog.ip == ip_filter) + # Count total unique access logs with attack detections - total_attacks = ( + count_query = ( session.query(AccessLog) .join(AttackDetection) - .distinct(AccessLog.id) - .count() ) + if base_filters: + count_query = count_query.filter(*base_filters) + total_attacks = count_query.distinct(AccessLog.id).count() # Get paginated access logs with attack detections query = ( - session.query(AccessLog).join(AttackDetection).distinct(AccessLog.id) + session.query(AccessLog).join(AttackDetection) ) + if base_filters: + query = query.filter(*base_filters) + query = query.distinct(AccessLog.id) if sort_by == "timestamp": query = query.order_by( diff --git a/src/routes/htmx.py b/src/routes/htmx.py index 976fc35..e4cf1a7 100644 --- a/src/routes/htmx.py +++ b/src/routes/htmx.py @@ -241,10 +241,12 @@ async def htmx_attacks( page: int = Query(1), sort_by: str = Query("timestamp"), sort_order: str = Query("desc"), + ip_filter: str = Query(None), ): db = get_db() result = db.get_attack_types_paginated( - page=max(1, page), page_size=5, sort_by=sort_by, sort_order=sort_order + page=max(1, page), page_size=5, sort_by=sort_by, sort_order=sort_order, + ip_filter=ip_filter, ) # Transform attack data for template (join attack_types list, map id to log_id) @@ -271,6 +273,7 @@ async def htmx_attacks( "pagination": result["pagination"], "sort_by": sort_by, "sort_order": sort_order, + "ip_filter": ip_filter or "", }, ) diff --git a/src/templates/jinja2/dashboard/partials/_ip_detail.html b/src/templates/jinja2/dashboard/partials/_ip_detail.html index 42bdcf1..1812b1d 100644 --- a/src/templates/jinja2/dashboard/partials/_ip_detail.html +++ b/src/templates/jinja2/dashboard/partials/_ip_detail.html @@ -185,6 +185,19 @@ {% endif %} +{# Detected Attack Types table – only for attackers #} +{% if stats.category and stats.category | lower == 'attacker' %} +
+

Detected Attack Types

+
+
Loading...
+
+
+{% endif %} + {# Access History table #}

Access History

diff --git a/src/templates/jinja2/dashboard/partials/attack_types_table.html b/src/templates/jinja2/dashboard/partials/attack_types_table.html index e149bfc..4ac3369 100644 --- a/src/templates/jinja2/dashboard/partials/attack_types_table.html +++ b/src/templates/jinja2/dashboard/partials/attack_types_table.html @@ -3,12 +3,12 @@ Page {{ pagination.page }}/{{ pagination.total_pages }} — {{ pagination.total }} total
@@ -23,7 +23,7 @@ Attack Types User-Agent Time