Add ban management features and update documentation

- Implement ban model, service, and router endpoints in backend
- Add ban table component and dashboard integration in frontend
- Update ban-related types and API endpoints
- Add comprehensive tests for ban service and dashboard router
- Update documentation (Features, Tasks, Architecture, Web-Design)
- Clean up old fail2ban configuration files
- Update Makefile with new commands
This commit is contained in:
2026-03-06 20:33:42 +01:00
parent 06738dbfa5
commit cbad4ea706
20 changed files with 58 additions and 760 deletions

View File

@@ -4,8 +4,7 @@ Provides the ``GET /api/dashboard/status`` endpoint that returns the cached
fail2ban server health snapshot. The snapshot is maintained by the
background health-check task and refreshed every 30 seconds.
Also provides ``GET /api/dashboard/bans`` and ``GET /api/dashboard/accesses``
for the dashboard ban-list and access-list tables.
Also provides ``GET /api/dashboard/bans`` for the dashboard ban-list table.
"""
from __future__ import annotations
@@ -19,7 +18,6 @@ from fastapi import APIRouter, Query, Request
from app.dependencies import AuthDep
from app.models.ban import (
AccessListResponse,
BansByCountryResponse,
DashboardBanListResponse,
TimeRange,
@@ -113,51 +111,6 @@ async def get_dashboard_bans(
)
@router.get(
"/accesses",
response_model=AccessListResponse,
summary="Return a paginated list of individual access events",
)
async def get_dashboard_accesses(
request: Request,
_auth: AuthDep,
range: TimeRange = Query(default=_DEFAULT_RANGE, description="Time-range preset."),
page: int = Query(default=1, ge=1, description="1-based page number."),
page_size: int = Query(default=_DEFAULT_PAGE_SIZE, ge=1, le=500, description="Items per page."),
) -> AccessListResponse:
"""Return a paginated list of individual access events (matched log lines).
Expands the ``data.matches`` JSON stored inside each ban record so that
every matched log line is returned as a separate row. Useful for
the "Access List" tab which shows all recorded access attempts — not
just the aggregate bans.
Args:
request: The incoming request.
_auth: Validated session dependency.
range: Time-range preset.
page: 1-based page number.
page_size: Maximum items per page (1500).
Returns:
:class:`~app.models.ban.AccessListResponse` with individual access
items expanded from ``data.matches``.
"""
socket_path: str = request.app.state.settings.fail2ban_socket
http_session: aiohttp.ClientSession = request.app.state.http_session
async def _enricher(ip: str) -> geo_service.GeoInfo | None:
return await geo_service.lookup(ip, http_session)
return await ban_service.list_accesses(
socket_path,
range,
page=page,
page_size=page_size,
geo_enricher=_enricher,
)
@router.get(
"/bans/by-country",
response_model=BansByCountryResponse,