mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 17:12:16 +03:00
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:
@@ -65,6 +65,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { CameraNameLabel } from "@/components/camera/CameraNameLabel";
|
||||
import { useAllowedCameras } from "@/hooks/use-allowed-cameras";
|
||||
|
||||
type RecordingViewProps = {
|
||||
startCamera: string;
|
||||
@@ -97,11 +98,17 @@ export function RecordingView({
|
||||
|
||||
const timezone = useTimezone(config);
|
||||
|
||||
const allowedCameras = useAllowedCameras();
|
||||
const effectiveCameras = useMemo(
|
||||
() => allCameras.filter((camera) => allowedCameras.includes(camera)),
|
||||
[allCameras, allowedCameras],
|
||||
);
|
||||
|
||||
const { data: recordingsSummary } = useSWR<RecordingsSummary>([
|
||||
"recordings/summary",
|
||||
{
|
||||
timezone: timezone,
|
||||
cameras: allCameras.join(",") ?? null,
|
||||
cameras: effectiveCameras.join(",") ?? null,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -276,14 +283,16 @@ export function RecordingView({
|
||||
|
||||
const onSelectCamera = useCallback(
|
||||
(newCam: string) => {
|
||||
setMainCamera(newCam);
|
||||
setFullResolution({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
setPlaybackStart(currentTime);
|
||||
if (allowedCameras.includes(newCam)) {
|
||||
setMainCamera(newCam);
|
||||
setFullResolution({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
setPlaybackStart(currentTime);
|
||||
}
|
||||
},
|
||||
[currentTime],
|
||||
[currentTime, allowedCameras],
|
||||
);
|
||||
|
||||
// fullscreen
|
||||
@@ -488,12 +497,9 @@ export function RecordingView({
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<MobileCameraDrawer
|
||||
allCameras={allCameras}
|
||||
allCameras={effectiveCameras}
|
||||
selected={mainCamera}
|
||||
onSelectCamera={(cam) => {
|
||||
setPlaybackStart(currentTime);
|
||||
setMainCamera(cam);
|
||||
}}
|
||||
onSelectCamera={onSelectCamera}
|
||||
/>
|
||||
{isDesktop && (
|
||||
<ExportDialog
|
||||
@@ -674,7 +680,7 @@ export function RecordingView({
|
||||
containerRef={mainLayoutRef}
|
||||
/>
|
||||
</div>
|
||||
{isDesktop && allCameras.length > 1 && (
|
||||
{isDesktop && effectiveCameras.length > 1 && (
|
||||
<div
|
||||
ref={previewRowRef}
|
||||
className={cn(
|
||||
@@ -686,7 +692,7 @@ export function RecordingView({
|
||||
)}
|
||||
>
|
||||
<div className="w-2" />
|
||||
{allCameras.map((cam) => {
|
||||
{effectiveCameras.map((cam) => {
|
||||
if (cam == mainCamera || cam == "birdseye") {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user