Fix camera name collision bypassing admin check (#24516)

* don't let camera names waive the admin check on non-camera routes

The global admin guard skipped the admin check for any request whose first path segment matched a configured camera name, without looking at which route actually handled it. A camera named `faces`, `lpr`, `audio`, or `classification` let viewers reach the face, LPR, audio transcription, and classification endpoints that rely only on the global guard. The exemption now also requires the matched route to be a `/{camera_name}` route, so camera routes behave exactly as before.

* add test
This commit is contained in:
Josh Hawkins
2026-10-01 08:56:04 -06:00
committed by GitHub
parent 160d213025
commit 17a8efa09c
3 changed files with 35 additions and 19 deletions
+19
View File
@@ -47,6 +47,25 @@ class TestHttpApp(BaseTestHttp):
assert response.status_code == 200
assert response.json()["front_door"]["usage_percent"] == 25.0
def test_camera_name_collision_keeps_admin_default(self):
self.minimal_config["cameras"]["faces"] = self.minimal_config["cameras"].pop(
"front_door"
)
app = super().create_app(enforce_default_admin=True)
viewer = {"remote-user": "viewer", "remote-role": "viewer"}
with AuthTestClient(app) as client:
assert client.get("/faces", headers=viewer).status_code == 403
assert client.get("/faces").status_code == 200
assert (
client.post("/faces/train/person/classify", headers=viewer).status_code
== 403
)
# Camera routes for the same name stay reachable by viewers
response = client.get("/faces/recordings/summary", headers=viewer)
assert response.status_code == 200
def test_config_set_in_memory_replaces_objects_track_list(self):
self.minimal_config["cameras"]["front_door"]["objects"] = {
"track": ["person", "car"],