From 02678f4a097dcffe00a4bbbdc01ebc9c190a5b4c Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 5 Mar 2026 17:17:41 -0600 Subject: [PATCH] show log when anonymous users log in (#22254) based on a cache key built from remote_addr and user agent, expires after 7 days by default --- frigate/api/auth.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/frigate/api/auth.py b/frigate/api/auth.py index 04a5bd19a..39089b583 100644 --- a/frigate/api/auth.py +++ b/frigate/api/auth.py @@ -32,6 +32,12 @@ from frigate.models import User logger = logging.getLogger(__name__) +# In-memory cache to track which clients we've logged for an anonymous access event. +# Keyed by a hashed value combining remote address + user-agent. The value is +# an expiration timestamp (float). +FIRST_LOAD_TTL_SECONDS = 60 * 60 * 24 * 7 # 7 days +_first_load_seen: dict[str, float] = {} + def require_admin_by_default(): """ @@ -284,6 +290,15 @@ def get_remote_addr(request: Request): return remote_addr or "127.0.0.1" +def _cleanup_first_load_seen() -> None: + """Cleanup expired entries in the in-memory first-load cache.""" + now = time.time() + # Build list for removal to avoid mutating dict during iteration + expired = [k for k, exp in _first_load_seen.items() if exp <= now] + for k in expired: + del _first_load_seen[k] + + def get_jwt_secret() -> str: jwt_secret = None # check env var @@ -744,10 +759,30 @@ def profile(request: Request): roles_dict = request.app.frigate_config.auth.roles allowed_cameras = User.get_allowed_cameras(role, roles_dict, all_camera_names) - return JSONResponse( + response = JSONResponse( content={"username": username, "role": role, "allowed_cameras": allowed_cameras} ) + if username == "anonymous": + try: + remote_addr = get_remote_addr(request) + except Exception: + remote_addr = ( + request.client.host if hasattr(request, "client") else "unknown" + ) + + ua = request.headers.get("user-agent", "") + key_material = f"{remote_addr}|{ua}" + cache_key = hashlib.sha256(key_material.encode()).hexdigest() + + _cleanup_first_load_seen() + now = time.time() + if cache_key not in _first_load_seen: + _first_load_seen[cache_key] = now + FIRST_LOAD_TTL_SECONDS + logger.info(f"Anonymous user access from {remote_addr} ua={ua[:200]}") + + return response + @router.get( "/logout",