Enforce repository boundary: Remove DbDep from routers
This commit enforces the repository boundary by eliminating direct database connection dependencies (DbDep) from all routers. Routers now depend on service context dependencies that combine the database connection with the related repositories. Changes: - Add 5 service context dependencies in dependencies.py: * SessionServiceContext: db + session_repo * BlocklistServiceContext: db + blocklist_repo + import_log_repo + settings_repo * SettingsServiceContext: db + settings_repo * BanServiceContext: db + fail2ban_db_repo * HistoryServiceContext: db + fail2ban_db_repo + history_archive_repo - Refactor all 9 routers (auth, bans, blocklist, config_misc, dashboard, geo, history, jails, setup) to use service contexts instead of DbDep. - Update Backend-Development.md with clear examples of the new pattern and documentation of available service contexts. Rationale: - Enforces the repository boundary through the dependency system - Makes database operations explicit and auditable - Improves testability by allowing service contexts to be mocked - Prevents accidental direct database access from routers The deprecated DbDep remains available for backward compatibility with services that have not yet been refactored, but routers can no longer import it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -26,10 +26,9 @@ from fastapi import APIRouter, HTTPException, Request, Response, status
|
||||
|
||||
from app.dependencies import (
|
||||
AuthDep,
|
||||
DbDep,
|
||||
LoginRateLimiterDep,
|
||||
SessionCacheDep,
|
||||
SessionRepoDep,
|
||||
SessionServiceContextDep,
|
||||
SettingsDep,
|
||||
)
|
||||
from app.models.auth import LoginRequest, LoginResponse, LogoutResponse
|
||||
@@ -55,9 +54,8 @@ async def login(
|
||||
body: LoginRequest,
|
||||
response: Response,
|
||||
request: Request,
|
||||
db: DbDep,
|
||||
session_ctx: SessionServiceContextDep,
|
||||
settings: SettingsDep,
|
||||
session_repo: SessionRepoDep,
|
||||
rate_limiter: LoginRateLimiterDep,
|
||||
) -> LoginResponse:
|
||||
"""Verify the master password and return a session token.
|
||||
@@ -73,9 +71,8 @@ async def login(
|
||||
body: Login request validated by Pydantic.
|
||||
response: FastAPI response object used to set the cookie.
|
||||
request: The incoming HTTP request (used to extract client IP).
|
||||
db: Injected aiosqlite connection.
|
||||
session_ctx: Session service context containing db and repository.
|
||||
settings: Application settings (used for session duration).
|
||||
session_repo: The session repository.
|
||||
rate_limiter: The login rate limiter (per IP).
|
||||
|
||||
Returns:
|
||||
@@ -97,11 +94,11 @@ async def login(
|
||||
|
||||
try:
|
||||
signed_token, expires_at = await auth_service.login(
|
||||
db,
|
||||
session_ctx.db,
|
||||
password=body.password,
|
||||
session_duration_minutes=settings.session_duration_minutes,
|
||||
session_secret=settings.session_secret,
|
||||
session_repo=session_repo,
|
||||
session_repo=session_ctx.session_repo,
|
||||
)
|
||||
except ValueError as exc:
|
||||
# Add delay on wrong password to slow down brute-force attacks.
|
||||
@@ -159,10 +156,9 @@ async def validate_session(
|
||||
async def logout(
|
||||
request: Request,
|
||||
response: Response,
|
||||
db: DbDep,
|
||||
session_ctx: SessionServiceContextDep,
|
||||
settings: SettingsDep,
|
||||
session_cache: SessionCacheDep,
|
||||
session_repo: SessionRepoDep,
|
||||
) -> LogoutResponse:
|
||||
"""Invalidate the active session.
|
||||
|
||||
@@ -173,8 +169,9 @@ async def logout(
|
||||
Args:
|
||||
request: FastAPI request (used to extract the token).
|
||||
response: FastAPI response (used to clear the cookie).
|
||||
db: Injected aiosqlite connection.
|
||||
session_ctx: Session service context containing db and repository.
|
||||
settings: Application settings (used to unwrap signed tokens).
|
||||
session_cache: Session cache for invalidation.
|
||||
|
||||
Returns:
|
||||
:class:`~app.models.auth.LogoutResponse`.
|
||||
@@ -182,10 +179,10 @@ async def logout(
|
||||
token = _extract_token(request)
|
||||
if token:
|
||||
raw_token = await auth_service.logout(
|
||||
db,
|
||||
session_ctx.db,
|
||||
token,
|
||||
settings.session_secret,
|
||||
session_repo=session_repo,
|
||||
session_repo=session_ctx.session_repo,
|
||||
)
|
||||
if raw_token:
|
||||
session_cache.invalidate(raw_token)
|
||||
|
||||
Reference in New Issue
Block a user