Task 13: wire geo_batch_lookup through dependency injection and mark task completed
This commit is contained in:
@@ -371,6 +371,8 @@ None.
|
||||
|
||||
### Task 13 — Wire geo_batch_lookup through dependency injection
|
||||
|
||||
**Status:** Completed
|
||||
|
||||
**Severity:** Medium
|
||||
|
||||
**Where:**
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user