feat: Implement SQLite schema and migrations for intrusion detection system

- Added schema definition and migration logic in app/db/schema.py.
- Created tables for log sources, requests, IP stats, scans, blocklist, whitelist, and firewall rules.
- Introduced functions to apply migrations and ensure database integrity.

feat: Enhance scan functionality with database integration

- Added _sync_blocklist_to_db function to synchronize blocklist with SQLite.
- Updated run_scan function to handle database connections and scan records.
- Implemented error handling for database operations during scans.

feat: Introduce log analysis page and API endpoints

- Created analysis.html template for displaying log analysis results.
- Added routes for fetching top IPs, IP request timelines, and cross-source IPs.
- Integrated analysis data into the dashboard and status endpoints.

fix: Ensure whitelists are synchronized with the database

- Implemented sync_whitelists_to_db function to persist in-memory whitelists.
- Updated constants.py to define the path for the SQLite database.

refactor: Modularize analysis helpers for better maintainability

- Created _analysis_helpers function to encapsulate SQLite query logic.
- Updated routes.py to utilize new analysis helper functions for API responses.
This commit is contained in:
zwitschi committed 2026-10-24 19:48:20 +02:00
1 parent 0137264fe4
commit 6036fa8b1e
17 files changed
+1292 -5

No files matched your search

+36
View File
@@ -131,6 +131,41 @@ def _sync_firewall(dry_run: bool):
return _with_router(_sync)
def _analysis_helpers():
"""SQLite-backed log-analysis query helpers (None when DB unavailable).
Functions take the shared DB connection each call so routes stay stateless
across the background scan thread.
"""
try:
from ..db import get_connection
from ..db import repositories as repo
except Exception:
return None
def top_ips(since: str | None = None, limit: int = 50) -> list:
return repo.top_ips(get_connection(), since=since, limit=limit)
def ip_timeline(ip: str) -> list:
return repo.ip_timeline(get_connection(), ip=ip)
def cross_source(limit: int = 100) -> list:
return repo.correlate_across_sources(get_connection(), limit=limit)
def conn():
return get_connection()
def request_count(conn) -> int:
return repo.count_requests(conn)
def scan_count(conn) -> int:
return repo.count_scans(conn)
return {"top_ips": top_ips, "ip_timeline": ip_timeline,
"cross_source": cross_source, "conn": conn,
"request_count": request_count, "scan_count": scan_count}
# ---------------------------------------------------------------------------
# app factory
# ---------------------------------------------------------------------------
@@ -155,6 +190,7 @@ def create_app() -> Flask:
"_params_from_request": _params_from_request,
"_with_router": _with_router,
"_sync_firewall": _sync_firewall,
"_analysis": _analysis_helpers(),
}
register_routes(app, REPORT_SOURCES, SCAN_KINDS, web_scan, helpers)
return app