Enhance user roles to limit camera access (#20024)

* update config for roles and add validator

* ensure admin and viewer are never overridden

* add class method to user to retrieve all allowed cameras

* enforce config roles in auth api endpoints

* add camera access api dependency functions

* protect review endpoints

* protect preview endpoints

* rename param name for better fastapi injection matching

* remove unneeded

* protect export endpoints

* protect event endpoints

* protect media endpoints

* update auth hook for allowed cameras

* update default app view

* ensure anonymous user always returns all cameras

* limit cameras in explore

* cameras is already a list

* limit cameras in review/history

* limit cameras in live view

* limit cameras in camera groups

* only show face library and classification in sidebar for admin

* remove check in delete reviews

since admin role is required, no need to check camera access. fixes failing test

* pass request with camera access for tests

* more async

* camera access tests

* fix proxy auth tests

* allowed cameras for review tests

* combine event tests and refactor for camera access

* fix post validation for roles

* don't limit roles in create user dialog

* fix triggers endpoints

no need to run require camera access dep since the required role is admin

* fix type

* create and edit role dialogs

* delete role dialog

* fix role change dialog

* update settings view for roles

* i18n changes

* minor spacing tweaks

* docs

* use badges and camera name label component

* clarify docs

* display all cameras badge for admin and viewer

* i18n fix

* use validator to prevent reserved and empty roles from being assigned

* split users and roles into separate tabs in settings

* tweak docs

* clarify docs

* change icon

* don't memoize roles

always recalculate on component render
This commit is contained in:
Josh Hawkins
2025-09-12 05:19:29 -06:00
committed by GitHub
parent ba650af6f2
commit ed1e3a7c9a
41 changed files with 2286 additions and 739 deletions
+12 -5
View File
@@ -33,6 +33,7 @@ import { TooltipPortal } from "@radix-ui/react-tooltip";
import SearchActionGroup from "@/components/filter/SearchActionGroup";
import { Trans, useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { useAllowedCameras } from "@/hooks/use-allowed-cameras";
type SearchViewProps = {
search: string;
@@ -96,6 +97,7 @@ export default function SearchView({
);
// suggestions values
const allowedCameras = useAllowedCameras();
const allLabels = useMemo<string[]>(() => {
if (!config) {
@@ -103,7 +105,9 @@ export default function SearchView({
}
const labels = new Set<string>();
const cameras = searchFilter?.cameras || Object.keys(config.cameras);
const cameras = (searchFilter?.cameras || allowedCameras).filter((camera) =>
allowedCameras.includes(camera),
);
cameras.forEach((camera) => {
if (camera == "birdseye") {
@@ -128,7 +132,7 @@ export default function SearchView({
});
return [...labels].sort();
}, [config, searchFilter]);
}, [config, searchFilter, allowedCameras]);
const { data: allSubLabels } = useSWR("sub_labels");
const { data: allRecognizedLicensePlates } = useSWR(
@@ -141,7 +145,9 @@ export default function SearchView({
}
const zones = new Set<string>();
const cameras = searchFilter?.cameras || Object.keys(config.cameras);
const cameras = (searchFilter?.cameras || allowedCameras).filter((camera) =>
allowedCameras.includes(camera),
);
cameras.forEach((camera) => {
if (camera == "birdseye") {
@@ -160,11 +166,11 @@ export default function SearchView({
});
return [...zones].sort();
}, [config, searchFilter]);
}, [config, searchFilter, allowedCameras]);
const suggestionsValues = useMemo(
() => ({
cameras: Object.keys(config?.cameras || {}),
cameras: allowedCameras,
labels: Object.values(allLabels || {}),
zones: Object.values(allZones || {}),
sub_labels: allSubLabels,
@@ -192,6 +198,7 @@ export default function SearchView({
allSubLabels,
allRecognizedLicensePlates,
searchFilter,
allowedCameras,
],
);