From 335f89c5543cdb72e8d55b58605251c74515c94d Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 22 Mar 2026 10:06:00 +0100 Subject: [PATCH] Docs: mark Task 8/9 completed and update architecture docs --- Docs/Architekture.md | 64 +++++++++++++++++++++++++++++++++----------- Docs/Tasks.md | 8 +++--- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/Docs/Architekture.md b/Docs/Architekture.md index 1560c2b..af79b86 100644 --- a/Docs/Architekture.md +++ b/Docs/Architekture.md @@ -82,10 +82,12 @@ The backend follows a **layered architecture** with strict separation of concern backend/ ├── app/ │ ├── __init__.py -│ ├── main.py # FastAPI app factory, lifespan, exception handlers -│ ├── config.py # Pydantic settings (env vars, .env loading) -│ ├── dependencies.py # FastAPI Depends() providers (DB, services, auth) -│ ├── models/ # Pydantic schemas +│ ├── `main.py` # FastAPI app factory, lifespan, exception handlers +│ ├── `config.py` # Pydantic settings (env vars, .env loading) +│ ├── `db.py` # Database connection and initialization +│ ├── `exceptions.py` # Shared domain exception classes +│ ├── `dependencies.py` # FastAPI Depends() providers (DB, services, auth) +│ ├── `models/` # Pydantic schemas │ │ ├── auth.py # Login request/response, session models │ │ ├── ban.py # Ban request/response/domain models │ │ ├── jail.py # Jail request/response/domain models @@ -111,6 +113,12 @@ backend/ │ │ ├── jail_service.py # Jail listing, start/stop/reload, status aggregation │ │ ├── ban_service.py # Ban/unban execution, currently-banned queries │ │ ├── config_service.py # Read/write fail2ban config, regex validation +│ │ ├── config_file_service.py # Shared config parsing and file-level operations +│ │ ├── raw_config_io_service.py # Raw config file I/O wrapper +│ │ ├── jail_config_service.py # jail config activation/deactivation logic +│ │ ├── filter_config_service.py # filter config lifecycle management +│ │ ├── action_config_service.py # action config lifecycle management +│ │ ├── log_service.py # Log preview and regex test operations │ │ ├── history_service.py # Historical ban queries, per-IP timeline │ │ ├── blocklist_service.py # Download, validate, apply blocklists │ │ ├── geo_service.py # IP-to-country resolution, ASN/RIR lookup @@ -119,17 +127,18 @@ backend/ │ ├── repositories/ # Data access layer (raw queries only) │ │ ├── settings_repo.py # App configuration CRUD in SQLite │ │ ├── session_repo.py # Session storage and lookup -│ │ ├── blocklist_repo.py # Blocklist sources and import log persistence -│ │ └── import_log_repo.py # Import run history records +│ │ ├── blocklist_repo.py # Blocklist sources and import log persistence│ │ ├── fail2ban_db_repo.py # fail2ban SQLite ban history read operations +│ │ ├── geo_cache_repo.py # IP geolocation cache persistence│ │ └── import_log_repo.py # Import run history records │ ├── tasks/ # APScheduler background jobs │ │ ├── blocklist_import.py# Scheduled blocklist download and application -│ │ ├── geo_cache_flush.py # Periodic geo cache persistence (dirty-set flush to SQLite) -│ │ └── health_check.py # Periodic fail2ban connectivity probe +│ │ ├── geo_cache_flush.py # Periodic geo cache persistence (dirty-set flush to SQLite)│ │ ├── geo_re_resolve.py # Periodic re-resolution of stale geo cache records│ │ └── health_check.py # Periodic fail2ban connectivity probe │ └── utils/ # Helpers, constants, shared types │ ├── fail2ban_client.py # Async wrapper around the fail2ban socket protocol │ ├── ip_utils.py # IP/CIDR validation and normalisation -│ ├── time_utils.py # Timezone-aware datetime helpers -│ └── constants.py # Shared constants (default paths, limits, etc.) +│ ├── time_utils.py # Timezone-aware datetime helpers│ ├── jail_config.py # Jail config parser/serializer helper +│ ├── conffile_parser.py # Fail2ban config file parser/serializer +│ ├── config_parser.py # Structured config object parser +│ ├── config_writer.py # Atomic config file write operations│ └── constants.py # Shared constants (default paths, limits, etc.) ├── tests/ │ ├── conftest.py # Shared fixtures (test app, client, mock DB) │ ├── test_routers/ # One test file per router @@ -158,8 +167,9 @@ The HTTP interface layer. Each router maps URL paths to handler functions. Route | `blocklist.py` | `/api/blocklists` | CRUD blocklist sources, trigger import, view import logs | | `geo.py` | `/api/geo` | IP geolocation lookup, ASN and RIR data | | `server.py` | `/api/server` | Log level, log target, DB path, purge age, flush logs | +| `health.py` | `/api/health` | fail2ban connectivity health check and status | -#### Services (`app/services/`) +#### Services (`app/services`) The business logic layer. Services orchestrate operations, enforce rules, and coordinate between repositories, the fail2ban client, and external APIs. Each service covers a single domain. @@ -175,7 +185,8 @@ The business logic layer. Services orchestrate operations, enforce rules, and co | `filter_config_service.py` | Discovers available filters by scanning filter.d/; reads, creates, updates, and deletes filter definitions; assigns filters to jails | | `action_config_service.py` | Discovers available actions by scanning action.d/; reads, creates, updates, and deletes action definitions; assigns actions to jails | | `config_file_service.py` | Shared utilities for configuration parsing and manipulation: parses config files, validates names/IPs, manages atomic file writes, probes fail2ban socket | -| `conffile_parser.py` | Parses fail2ban `.conf` files into structured Python types (jail config, filter config, action config); also serialises back to text | +| `raw_config_io_service.py` | Low-level file I/O for raw fail2ban config files | +| `log_service.py` | Log preview and regex test operations (extracted from config_service) | | `history_service.py` | Queries the fail2ban database for historical ban records, builds per-IP timelines, computes ban counts and repeat-offender flags | | `blocklist_service.py` | Downloads blocklists via aiohttp, validates IPs/CIDRs, applies bans through fail2ban or iptables, logs import results | | `geo_service.py` | Resolves IP addresses to country, ASN, and RIR using external APIs or a local database, caches results | @@ -191,15 +202,26 @@ The data access layer. Repositories execute raw SQL queries against the applicat | `settings_repo.py` | CRUD operations for application settings (master password hash, DB path, fail2ban socket path, preferences) | | `session_repo.py` | Store, retrieve, and delete session records for authentication | | `blocklist_repo.py` | Persist blocklist source definitions (name, URL, enabled/disabled) | +| `fail2ban_db_repo.py` | Read historical ban records from the fail2ban SQLite database | +| `geo_cache_repo.py` | Persist and query IP geo resolution cache | | `import_log_repo.py` | Record import run results (timestamp, source, IPs imported, errors) for the import log view | #### Models (`app/models/`) -Pydantic schemas that define data shapes and validation. Models are split into three categories per domain: +Pydantic schemas that define data shapes and validation. Models are split into three categories per domain. -- **Request models** — validate incoming API data (e.g., `BanRequest`, `LoginRequest`) -- **Response models** — shape outgoing API data (e.g., `JailResponse`, `BanListResponse`) -- **Domain models** — internal representations used between services and repositories (e.g., `Ban`, `Jail`) +| Model file | Purpose | +|---|---| +| `auth.py` | Login/request and session models | +| `ban.py` | Ban creation and lookup models | +| `blocklist.py` | Blocklist source and import log models | +| `config.py` | Fail2ban config view/edit models | +| `file_config.py` | Raw config file read/write models | +| `geo.py` | Geo and ASN lookup models | +| `history.py` | Historical ban query and timeline models | +| `jail.py` | Jail listing and status models | +| `server.py` | Server status and settings models | +| `setup.py` | First-run setup wizard models | #### Tasks (`app/tasks/`) @@ -209,6 +231,7 @@ APScheduler background jobs that run on a schedule without user interaction. |---|---| | `blocklist_import.py` | Downloads all enabled blocklist sources, validates entries, applies bans, records results in the import log | | `geo_cache_flush.py` | Periodically flushes newly resolved IPs from the in-memory dirty set to the `geo_cache` SQLite table (default: every 60 seconds). GET requests populate only the in-memory cache; this task persists them without blocking any request. | +| `geo_re_resolve.py` | Periodically re-resolves stale entries in `geo_cache` to keep geolocation data fresh | | `health_check.py` | Periodically pings the fail2ban socket and updates the cached server status so the frontend always has fresh data | #### Utils (`app/utils/`) @@ -219,7 +242,16 @@ Pure helper modules with no framework dependencies. |---|---| | `fail2ban_client.py` | Async client that communicates with fail2ban via its Unix domain socket — sends commands and parses responses using the fail2ban protocol. Modelled after [`./fail2ban-master/fail2ban/client/csocket.py`](../fail2ban-master/fail2ban/client/csocket.py) and [`./fail2ban-master/fail2ban/client/fail2banclient.py`](../fail2ban-master/fail2ban/client/fail2banclient.py). | | `ip_utils.py` | Validates IPv4/IPv6 addresses and CIDR ranges using the `ipaddress` stdlib module, normalises formats | +| `jail_utils.py` | Jail helper functions for configuration and status inference | +| `jail_config.py` | Jail config parser and serializer for fail2ban config manipulation | | `time_utils.py` | Timezone-aware datetime construction, formatting helpers, time-range calculations | +| `log_utils.py` | Structured log formatting and enrichment helpers | +| `conffile_parser.py` | Parses Fail2ban `.conf` files into structured objects and serialises back to text | +| `config_parser.py` | Builds structured config objects from file content tokens | +| `config_writer.py` | Atomic config file writes, backups, and safe replace semantics | +| `config_file_utils.py` | Common file-level config utility helpers | +| `fail2ban_db_utils.py` | Fail2ban DB path discovery and ban-history parsing helpers | +| `setup_utils.py` | Setup wizard helper utilities | | `constants.py` | Shared constants: default socket path, default database path, time-range presets, limits | #### Configuration (`app/config.py`) diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 109210f..355889f 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -150,7 +150,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue. --- -### Task 7 — Remove remaining service-to-service coupling +### Task 7 — Remove remaining service-to-service coupling (✅ completed) **Priority**: Medium **Refactoring ref**: Refactoring.md §1 @@ -172,7 +172,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue. --- -### Task 8 — Update Architecture documentation +### Task 8 — Update Architecture documentation (✅ completed) **Priority**: Medium **Refactoring ref**: Refactoring.md §4 @@ -194,7 +194,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue. --- -### Task 9 — Add React Error Boundary to the frontend +### Task 9 — Add React Error Boundary to the frontend (✅ completed) **Priority**: Medium **Refactoring ref**: Refactoring.md §6 @@ -238,7 +238,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue. --- -### Task 11 — Create generic `useConfigItem` hook (frontend) +### Task 11 — Create generic `useConfigItem` hook (frontend) (✅ completed) **Priority**: Low **Refactoring ref**: Refactoring.md §8