2026-02-17 13:09:01 +01:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Middleware for checking if client IP is banned.
|
2026-03-09 17:59:00 +01:00
|
|
|
Resets the connection for banned IPs instead of sending a response.
|
2026-02-17 13:09:01 +01:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
|
|
|
from starlette.requests import Request
|
|
|
|
|
from starlette.responses import Response
|
|
|
|
|
|
|
|
|
|
from dependencies import get_client_ip
|
|
|
|
|
|
|
|
|
|
|
2026-03-09 17:59:00 +01:00
|
|
|
class ConnectionResetResponse(Response):
|
|
|
|
|
"""Response that abruptly closes the connection without sending data."""
|
|
|
|
|
|
|
|
|
|
async def __call__(self, scope, receive, send):
|
|
|
|
|
raise ConnectionResetError()
|
|
|
|
|
|
|
|
|
|
|
2026-02-17 13:09:01 +01:00
|
|
|
class BanCheckMiddleware(BaseHTTPMiddleware):
|
|
|
|
|
async def dispatch(self, request: Request, call_next):
|
|
|
|
|
# Skip ban check for dashboard routes
|
|
|
|
|
config = request.app.state.config
|
|
|
|
|
dashboard_prefix = "/" + config.dashboard_secret_path.lstrip("/")
|
|
|
|
|
if request.url.path.startswith(dashboard_prefix):
|
|
|
|
|
return await call_next(request)
|
|
|
|
|
|
|
|
|
|
client_ip = get_client_ip(request)
|
|
|
|
|
tracker = request.app.state.tracker
|
|
|
|
|
|
|
|
|
|
if tracker.is_banned_ip(client_ip):
|
2026-03-09 17:59:00 +01:00
|
|
|
return ConnectionResetResponse()
|
2026-02-17 13:09:01 +01:00
|
|
|
|
|
|
|
|
response = await call_next(request)
|
2026-02-17 13:13:06 +01:00
|
|
|
return response
|