Task 13: wire geo_batch_lookup through dependency injection and mark task completed

This commit is contained in:
2026-04-14 09:51:23 +02:00
parent 88715ab07f
commit 56ade7fb08
6 changed files with 52 additions and 37 deletions

View File

@@ -20,6 +20,7 @@ from fastapi import Depends, FastAPI, HTTPException, Request, status
from app.config import Settings
from app.models.auth import Session
from app.models.config import PendingRecovery
from app.models.geo import GeoBatchLookup
from app.models.server import ServerStatus
from app.repositories.protocols import SessionRepository
from app.services.protocols import AuthService, JailService
@@ -195,6 +196,13 @@ async def get_fail2ban_start_command(settings: Settings = Depends(get_settings))
return settings.fail2ban_start_command
async def get_geo_batch_lookup() -> GeoBatchLookup:
"""Provide the concrete geo batch lookup callable used by routers."""
from app.services import geo_service # noqa: PLC0415
return geo_service.lookup_batch
async def get_session_cache(app_context: Annotated[ApplicationContext, Depends(get_app_context)]) -> SessionCache:
"""Provide the configured session cache backend from application context."""
if app_context.session_cache is None:
@@ -326,6 +334,7 @@ SchedulerDep = Annotated[AsyncIOScheduler, Depends(get_scheduler)]
Fail2BanSocketDep = Annotated[str, Depends(get_fail2ban_socket)]
Fail2BanConfigDirDep = Annotated[str, Depends(get_fail2ban_config_dir)]
Fail2BanStartCommandDep = Annotated[str, Depends(get_fail2ban_start_command)]
GeoBatchLookupDep = Annotated[GeoBatchLookup, Depends(get_geo_batch_lookup)]
ServerStatusDep = Annotated[ServerStatus, Depends(get_server_status)]
PendingRecoveryDep = Annotated[PendingRecovery | None, Depends(get_pending_recovery)]
SessionCacheDep = Annotated[SessionCache, Depends(get_session_cache)]

View File

@@ -10,23 +10,19 @@ Manual ban and unban operations and the active-bans overview:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import aiohttp
from fastapi import APIRouter, HTTPException, Request, status
from app.dependencies import (
AuthDep,
DbDep,
Fail2BanSocketDep,
GeoBatchLookupDep,
HttpSessionDep,
)
from app.exceptions import JailNotFoundError, JailOperationError
from app.models.ban import ActiveBanListResponse, BanRequest, UnbanAllResponse, UnbanRequest
from app.models.jail import JailCommandResponse
from app.services import geo_service, jail_service
from app.exceptions import JailNotFoundError, JailOperationError
from app.services import jail_service
from app.utils.fail2ban_client import Fail2BanConnectionError
router: APIRouter = APIRouter(prefix="/api/bans", tags=["Bans"])
@@ -58,6 +54,7 @@ async def get_active_bans(
db: DbDep,
socket_path: Fail2BanSocketDep,
http_session: HttpSessionDep,
geo_batch_lookup: GeoBatchLookupDep,
) -> ActiveBanListResponse:
"""Return every IP that is currently banned across all fail2ban jails.
@@ -77,7 +74,7 @@ async def get_active_bans(
try:
return await jail_service.get_active_bans(
socket_path,
geo_batch_lookup=geo_service.lookup_batch,
geo_batch_lookup=geo_batch_lookup,
http_session=http_session,
app_db=db,
)

View File

@@ -31,6 +31,7 @@ from app.dependencies import (
AppDep,
AuthDep,
Fail2BanSocketDep,
GeoBatchLookupDep,
HttpSessionDep,
SchedulerDep,
get_db,
@@ -122,6 +123,7 @@ async def run_import_now(
db: DbDep,
_auth: AuthDep,
socket_path: Fail2BanSocketDep,
geo_batch_lookup: GeoBatchLookupDep,
) -> ImportRunResult:
"""Download and apply all enabled blocklist sources immediately.
@@ -140,7 +142,7 @@ async def run_import_now(
http_session,
socket_path,
geo_is_cached=geo_service.is_cached,
geo_batch_lookup=geo_service.lookup_batch,
geo_batch_lookup=geo_batch_lookup,
ban_ip=jail_service.ban_ip,
)

View File

@@ -21,6 +21,7 @@ from app.dependencies import (
AuthDep,
DbDep,
Fail2BanSocketDep,
GeoBatchLookupDep,
HttpSessionDep,
ServerStatusDep,
)
@@ -83,6 +84,7 @@ async def get_dashboard_bans(
db: DbDep,
socket_path: Fail2BanSocketDep,
http_session: HttpSessionDep,
geo_batch_lookup: GeoBatchLookupDep,
range: TimeRange = Query(default=_DEFAULT_RANGE, description="Time-range preset."),
source: Literal["fail2ban", "archive"] = Query(
default="fail2ban",
@@ -123,7 +125,7 @@ async def get_dashboard_bans(
page_size=page_size,
http_session=http_session,
app_db=db,
geo_batch_lookup=geo_service.lookup_batch,
geo_batch_lookup=geo_batch_lookup,
origin=origin,
)
@@ -138,6 +140,7 @@ async def get_bans_by_country(
db: DbDep,
socket_path: Fail2BanSocketDep,
http_session: HttpSessionDep,
geo_batch_lookup: GeoBatchLookupDep,
range: TimeRange = Query(default=_DEFAULT_RANGE, description="Time-range preset."),
source: Literal["fail2ban", "archive"] = Query(
default="fail2ban",
@@ -175,7 +178,7 @@ async def get_bans_by_country(
source=source,
http_session=http_session,
geo_cache_lookup=geo_service.lookup_cached_only,
geo_batch_lookup=geo_service.lookup_batch,
geo_batch_lookup=geo_batch_lookup,
app_db=db,
origin=origin,
country_code=country_code,

View File

@@ -27,6 +27,7 @@ from app.dependencies import (
AuthDep,
DbDep,
Fail2BanSocketDep,
GeoBatchLookupDep,
HttpSessionDep,
JailServiceDep,
)
@@ -38,7 +39,7 @@ from app.models.jail import (
JailDetailResponse,
JailListResponse,
)
from app.services import geo_service, jail_service
from app.services import jail_service
from app.utils.fail2ban_client import Fail2BanConnectionError
router: APIRouter = APIRouter(prefix="/api/jails", tags=["Jails"])
@@ -108,7 +109,7 @@ def _conflict(message: str) -> HTTPException:
async def get_jails(
_auth: AuthDep,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailListResponse:
"""Return a summary of every active fail2ban jail.
@@ -123,7 +124,7 @@ async def get_jails(
:class:`~app.models.jail.JailListResponse` with all active jails.
"""
try:
return await jail_service.list_jails(socket_path)
return await jail_service_dep.list_jails(socket_path)
except Fail2BanConnectionError as exc:
raise _bad_gateway(exc) from exc
@@ -137,7 +138,7 @@ async def get_jail(
_auth: AuthDep,
name: _NamePath,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailDetailResponse:
"""Return the complete configuration and runtime state for one jail.
@@ -157,7 +158,7 @@ async def get_jail(
HTTPException: 502 when fail2ban is unreachable.
"""
try:
return await jail_service.get_jail(socket_path, name)
return await jail_service_dep.get_jail(socket_path, name)
except JailNotFoundError:
raise _not_found(name) from None
except Fail2BanConnectionError as exc:
@@ -177,7 +178,7 @@ async def get_jail(
async def reload_all_jails(
_auth: AuthDep,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailCommandResponse:
"""Reload every fail2ban jail to apply configuration changes.
@@ -195,7 +196,7 @@ async def reload_all_jails(
HTTPException: 409 when fail2ban reports the operation failed.
"""
try:
await jail_service.reload_all(socket_path)
await jail_service_dep.reload_all(socket_path)
return JailCommandResponse(message="All jails reloaded successfully.", jail="*")
except JailOperationError as exc:
raise _conflict(str(exc)) from exc
@@ -212,7 +213,7 @@ async def start_jail(
_auth: AuthDep,
name: _NamePath,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailCommandResponse:
"""Start a fail2ban jail that is currently stopped.
@@ -229,7 +230,7 @@ async def start_jail(
HTTPException: 502 when fail2ban is unreachable.
"""
try:
await jail_service.start_jail(socket_path, name)
await jail_service_dep.start_jail(socket_path, name)
return JailCommandResponse(message=f"Jail {name!r} started.", jail=name)
except JailNotFoundError:
raise _not_found(name) from None
@@ -248,7 +249,7 @@ async def stop_jail(
_auth: AuthDep,
name: _NamePath,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailCommandResponse:
"""Stop a running fail2ban jail.
@@ -268,7 +269,7 @@ async def stop_jail(
HTTPException: 502 when fail2ban is unreachable.
"""
try:
await jail_service.stop_jail(socket_path, name)
await jail_service_dep.stop_jail(socket_path, name)
return JailCommandResponse(message=f"Jail {name!r} stopped.", jail=name)
except JailOperationError as exc:
raise _conflict(str(exc)) from exc
@@ -285,7 +286,7 @@ async def toggle_idle(
_auth: AuthDep,
name: _NamePath,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
on: bool = Body(..., description="``true`` to enable idle, ``false`` to disable."),
) -> JailCommandResponse:
"""Enable or disable idle mode for a fail2ban jail.
@@ -308,7 +309,7 @@ async def toggle_idle(
"""
state_str = "on" if on else "off"
try:
await jail_service.set_idle(socket_path, name, on=on)
await jail_service_dep.set_idle(socket_path, name, on=on)
return JailCommandResponse(
message=f"Jail {name!r} idle mode turned {state_str}.",
jail=name,
@@ -330,7 +331,7 @@ async def reload_jail(
_auth: AuthDep,
name: _NamePath,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailCommandResponse:
"""Reload a single fail2ban jail to pick up configuration changes.
@@ -347,7 +348,7 @@ async def reload_jail(
HTTPException: 502 when fail2ban is unreachable.
"""
try:
await jail_service.reload_jail(socket_path, name)
await jail_service_dep.reload_jail(socket_path, name)
return JailCommandResponse(message=f"Jail {name!r} reloaded.", jail=name)
except JailNotFoundError:
raise _not_found(name) from None
@@ -379,7 +380,7 @@ async def get_ignore_list(
_auth: AuthDep,
name: _NamePath,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> list[str]:
"""Return the current ignore list (IP whitelist) for a fail2ban jail.
@@ -395,7 +396,7 @@ async def get_ignore_list(
HTTPException: 502 when fail2ban is unreachable.
"""
try:
return await jail_service.get_ignore_list(socket_path, name)
return await jail_service_dep.get_ignore_list(socket_path, name)
except JailNotFoundError:
raise _not_found(name) from None
except Fail2BanConnectionError as exc:
@@ -413,7 +414,7 @@ async def add_ignore_ip(
name: _NamePath,
body: IgnoreIpRequest,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailCommandResponse:
"""Add an IP address or CIDR network to a jail's ignore list.
@@ -435,7 +436,7 @@ async def add_ignore_ip(
HTTPException: 502 when fail2ban is unreachable.
"""
try:
await jail_service.add_ignore_ip(socket_path, name, body.ip)
await jail_service_dep.add_ignore_ip(socket_path, name, body.ip)
return JailCommandResponse(
message=f"IP {body.ip!r} added to ignore list of jail {name!r}.",
jail=name,
@@ -463,7 +464,7 @@ async def del_ignore_ip(
name: _NamePath,
body: IgnoreIpRequest,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
) -> JailCommandResponse:
"""Remove an IP address or CIDR network from a jail's ignore list.
@@ -481,7 +482,7 @@ async def del_ignore_ip(
HTTPException: 502 when fail2ban is unreachable.
"""
try:
await jail_service.del_ignore_ip(socket_path, name, body.ip)
await jail_service_dep.del_ignore_ip(socket_path, name, body.ip)
return JailCommandResponse(
message=f"IP {body.ip!r} removed from ignore list of jail {name!r}.",
jail=name,
@@ -503,7 +504,7 @@ async def toggle_ignore_self(
_auth: AuthDep,
name: _NamePath,
socket_path: Fail2BanSocketDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
on: bool = Body(..., description="``true`` to enable ignoreself, ``false`` to disable."),
) -> JailCommandResponse:
"""Toggle the ``ignoreself`` flag for a fail2ban jail.
@@ -526,7 +527,7 @@ async def toggle_ignore_self(
"""
state_str = "enabled" if on else "disabled"
try:
await jail_service.set_ignore_self(socket_path, name, on=on)
await jail_service_dep.set_ignore_self(socket_path, name, on=on)
return JailCommandResponse(
message=f"ignoreself {state_str} for jail {name!r}.",
jail=name,
@@ -555,7 +556,8 @@ async def get_jail_banned_ips(
name: _NamePath,
socket_path: Fail2BanSocketDep,
http_session: HttpSessionDep,
jail_service: JailServiceDep,
jail_service_dep: JailServiceDep,
geo_batch_lookup: GeoBatchLookupDep,
page: int = 1,
page_size: int = 25,
search: str | None = None,
@@ -593,13 +595,13 @@ async def get_jail_banned_ips(
)
try:
return await jail_service.get_jail_banned_ips(
return await jail_service_dep.get_jail_banned_ips(
socket_path=socket_path,
jail_name=name,
page=page,
page_size=page_size,
search=search,
geo_batch_lookup=geo_service.lookup_batch,
geo_batch_lookup=geo_batch_lookup,
http_session=http_session,
app_db=db,
)