Get rate limiter working

This commit is contained in:
Nicolas Mowen 2024-09-24 06:56:08 -06:00
parent 22b6aaf070
commit 3758f10d03
4 changed files with 18 additions and 15 deletions

View File

@ -26,9 +26,7 @@ In the event that you are locked out of your instance, you can tell Frigate to r
## Login failure rate limiting ## Login failure rate limiting
# TODO: Rui Update to use FastAPI In order to limit the risk of brute force attacks, rate limiting is available for login failures. This is implemented with SlowApi, and the string notation for valid values is available in [the documentation](https://limits.readthedocs.io/en/stable/quickstart.html#examples).
In order to limit the risk of brute force attacks, rate limiting is available for login failures. This is implemented with Flask-Limiter, and the string notation for valid values is available in [the documentation](https://flask-limiter.readthedocs.io/en/stable/configuration.html#rate-limit-string-notation).
For example, `1/second;5/minute;20/hour` will rate limit the login endpoint when failures occur more than: For example, `1/second;5/minute;20/hour` will rate limit the login endpoint when failures occur more than:

View File

@ -33,6 +33,19 @@ logger = logging.getLogger(__name__)
router = APIRouter(tags=[Tags.auth]) router = APIRouter(tags=[Tags.auth])
class RateLimiter:
_limit = ""
def set_limit(self, limit: str):
self._limit = limit
def get_limit(self) -> str:
return self._limit
rateLimiter = RateLimiter()
def get_remote_addr(request: Request): def get_remote_addr(request: Request):
route = list(reversed(request.headers.get("x-forwarded-for").split(","))) route = list(reversed(request.headers.get("x-forwarded-for").split(",")))
logger.debug(f"IP Route: {[r for r in route]}") logger.debug(f"IP Route: {[r for r in route]}")
@ -299,14 +312,8 @@ def logout(request: Request):
limiter = Limiter(key_func=get_remote_addr) limiter = Limiter(key_func=get_remote_addr)
def get_rate_limit(request: Request):
return request.app.frigate_config.auth.failed_login_rate_limit
@router.post("/login") @router.post("/login")
# Ideally, this would be a decorator @limiter.limit(limit_value=get_rate_limit) but that way the request object is not passed to the method @limiter.limit(limit_value=rateLimiter.get_limit)
# See: https://github.com/laurentS/slowapi/issues/41
# @limiter.limit(limit_value=get_rate_limit)
def login(request: Request, body: AppPostLoginBody): def login(request: Request, body: AppPostLoginBody):
JWT_COOKIE_NAME = request.app.frigate_config.auth.cookie_name JWT_COOKIE_NAME = request.app.frigate_config.auth.cookie_name
JWT_COOKIE_SECURE = request.app.frigate_config.auth.cookie_secure JWT_COOKIE_SECURE = request.app.frigate_config.auth.cookie_secure

View File

@ -13,9 +13,9 @@ from starlette_context.plugins import Plugin
from frigate.api import app as main_app from frigate.api import app as main_app
from frigate.api import auth, event, export, media, notification, preview, review from frigate.api import auth, event, export, media, notification, preview, review
from frigate.api.auth import get_jwt_secret, limiter from frigate.api.auth import get_jwt_secret, limiter
from frigate.config import FrigateConfig
from frigate.embeddings import EmbeddingsContext from frigate.embeddings import EmbeddingsContext
from frigate.events.external import ExternalEventProcessor from frigate.events.external import ExternalEventProcessor
from frigate.plus import PlusApi
from frigate.ptz.onvif import OnvifController from frigate.ptz.onvif import OnvifController
from frigate.stats.emitter import StatsEmitter from frigate.stats.emitter import StatsEmitter
from frigate.storage import StorageMaintainer from frigate.storage import StorageMaintainer
@ -39,14 +39,13 @@ class RemoteUserPlugin(Plugin):
def create_fastapi_app( def create_fastapi_app(
frigate_config, frigate_config: FrigateConfig,
database: SqliteQueueDatabase, database: SqliteQueueDatabase,
embeddings: Optional[EmbeddingsContext], embeddings: Optional[EmbeddingsContext],
detected_frames_processor, detected_frames_processor,
storage_maintainer: StorageMaintainer, storage_maintainer: StorageMaintainer,
onvif: OnvifController, onvif: OnvifController,
external_processor: ExternalEventProcessor, external_processor: ExternalEventProcessor,
plus_api: PlusApi,
stats_emitter: StatsEmitter, stats_emitter: StatsEmitter,
): ):
logger.info("Starting FastAPI app") logger.info("Starting FastAPI app")
@ -80,6 +79,7 @@ def create_fastapi_app(
return response return response
# Rate limiter (used for login endpoint) # Rate limiter (used for login endpoint)
auth.rateLimiter.set_limit(frigate_config.auth.failed_login_rate_limit)
app.state.limiter = limiter app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(SlowAPIMiddleware) app.add_middleware(SlowAPIMiddleware)
@ -101,7 +101,6 @@ def create_fastapi_app(
app.storage_maintainer = storage_maintainer app.storage_maintainer = storage_maintainer
app.camera_error_image = None app.camera_error_image = None
app.onvif = onvif app.onvif = onvif
app.plus_api = plus_api
app.stats_emitter = stats_emitter app.stats_emitter = stats_emitter
app.external_processor = external_processor app.external_processor = external_processor
app.jwt_token = get_jwt_secret() if frigate_config.auth.enabled else None app.jwt_token = get_jwt_secret() if frigate_config.auth.enabled else None

View File

@ -655,7 +655,6 @@ class FrigateApp:
self.storage_maintainer, self.storage_maintainer,
self.onvif_controller, self.onvif_controller,
self.external_event_processor, self.external_event_processor,
self.plus_api,
self.stats_emitter, self.stats_emitter,
), ),
host="127.0.0.1", host="127.0.0.1",