mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-10 23:35:42 +03:00
* 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
111 lines
2.5 KiB
TypeScript
111 lines
2.5 KiB
TypeScript
import axios from "axios";
|
|
import { createContext, useEffect, useState } from "react";
|
|
import useSWR from "swr";
|
|
|
|
interface AuthState {
|
|
user: { username: string; role: string | null } | null;
|
|
allowedCameras: string[];
|
|
isLoading: boolean;
|
|
isAuthenticated: boolean; // true if auth is required
|
|
}
|
|
|
|
interface AuthContextType {
|
|
auth: AuthState;
|
|
login: (user: AuthState["user"]) => void;
|
|
logout: () => void;
|
|
}
|
|
|
|
export const AuthContext = createContext<AuthContextType>({
|
|
auth: {
|
|
user: null,
|
|
allowedCameras: [],
|
|
isLoading: true,
|
|
isAuthenticated: false,
|
|
},
|
|
login: () => {},
|
|
logout: () => {},
|
|
});
|
|
|
|
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
const [auth, setAuth] = useState<AuthState>({
|
|
user: null,
|
|
allowedCameras: [],
|
|
isLoading: true,
|
|
isAuthenticated: false,
|
|
});
|
|
|
|
const { data: profile, error } = useSWR("/profile", {
|
|
revalidateOnFocus: false,
|
|
revalidateOnReconnect: true,
|
|
fetcher: (url) =>
|
|
axios.get(url, { withCredentials: true }).then((res) => res.data),
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (error) {
|
|
if (axios.isAxiosError(error) && error.response?.status === 401) {
|
|
// auth required but not logged in
|
|
setAuth({
|
|
user: null,
|
|
allowedCameras: [],
|
|
isLoading: false,
|
|
isAuthenticated: true,
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (profile) {
|
|
if (profile.username && profile.username !== "anonymous") {
|
|
const newUser = {
|
|
username: profile.username,
|
|
role: profile.role || "viewer",
|
|
};
|
|
|
|
const allowedCameras = Array.isArray(profile.allowed_cameras)
|
|
? profile.allowed_cameras
|
|
: [];
|
|
setAuth({
|
|
user: newUser,
|
|
allowedCameras,
|
|
isLoading: false,
|
|
isAuthenticated: true,
|
|
});
|
|
} else {
|
|
// Unauthenticated mode (anonymous)
|
|
setAuth({
|
|
user: null,
|
|
allowedCameras: [],
|
|
isLoading: false,
|
|
isAuthenticated: false,
|
|
});
|
|
}
|
|
}
|
|
}, [profile, error]);
|
|
|
|
const login = (user: AuthState["user"]) => {
|
|
setAuth((current) => ({
|
|
...current,
|
|
user,
|
|
isLoading: false,
|
|
isAuthenticated: true,
|
|
}));
|
|
};
|
|
|
|
const logout = () => {
|
|
setAuth({
|
|
user: null,
|
|
allowedCameras: [],
|
|
isLoading: false,
|
|
isAuthenticated: true,
|
|
});
|
|
axios.get("/logout", { withCredentials: true });
|
|
};
|
|
|
|
return (
|
|
<AuthContext.Provider value={{ auth, login, logout }}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
}
|