mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-07-26 13:47:03 +02:00
Fixes (#18055)
* frigate+ pane i18n fix * catch more exceptions * explore search result tooltip i18n fix * i18n fix * remove comments about deprecated strftime_fmt * Catch producers exists but is None * Formatting * fix live camera view i18n * Add default role config for proxy users This allows users to specify a default role for users when using a proxy for auth. This can be useful for users who can't/don't want to define a header mapping for the remote-role header. * update reference config and auth docs * clarify face rec camera level config * clarify auth docs * Fix onnx not working with openvino * Update openvino to fix failed npu plugin check --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
parent
976863518b
commit
511542eaf8
@ -37,9 +37,9 @@ opencv-python-headless == 4.11.0.*
|
||||
opencv-contrib-python == 4.11.0.*
|
||||
scipy == 1.14.*
|
||||
# OpenVino & ONNX
|
||||
openvino == 2024.4.*
|
||||
onnxruntime-openvino == 1.20.* ; platform_machine == 'x86_64'
|
||||
onnxruntime == 1.20.* ; platform_machine == 'aarch64'
|
||||
openvino == 2025.0.*
|
||||
onnxruntime-openvino == 1.21.0 ; platform_machine == 'x86_64'
|
||||
onnxruntime == 1.21.0 ; platform_machine == 'aarch64'
|
||||
# Embeddings
|
||||
transformers == 4.45.*
|
||||
# Generative AI
|
||||
|
@ -13,5 +13,5 @@ nvidia-cudnn-cu12 == 9.5.0.*; platform_machine == 'x86_64'
|
||||
nvidia-cufft-cu11==10.*; platform_machine == 'x86_64'
|
||||
nvidia-cufft-cu12==11.*; platform_machine == 'x86_64'
|
||||
onnx==1.16.*; platform_machine == 'x86_64'
|
||||
onnxruntime-gpu==1.20.*; platform_machine == 'x86_64'
|
||||
onnxruntime-gpu==1.21.0; platform_machine == 'x86_64'
|
||||
protobuf==3.20.3; platform_machine == 'x86_64'
|
||||
|
@ -77,7 +77,7 @@ Changing the secret will invalidate current tokens.
|
||||
|
||||
Frigate can be configured to leverage features of common upstream authentication proxies such as Authelia, Authentik, oauth2_proxy, or traefik-forward-auth.
|
||||
|
||||
If you are leveraging the authentication of an upstream proxy, you likely want to disable Frigate's authentication. Optionally, if communication between the reverse proxy and Frigate is over an untrusted network, you should set an `auth_secret` in the `proxy` config and configure the proxy to send the secret value as a header named `X-Proxy-Secret`. Assuming this is an untrusted network, you will also want to [configure a real TLS certificate](tls.md) to ensure the traffic can't simply be sniffed to steal the secret.
|
||||
If you are leveraging the authentication of an upstream proxy, you likely want to disable Frigate's authentication as there is no correspondence between users in Frigate's database and users authenticated via the proxy. Optionally, if communication between the reverse proxy and Frigate is over an untrusted network, you should set an `auth_secret` in the `proxy` config and configure the proxy to send the secret value as a header named `X-Proxy-Secret`. Assuming this is an untrusted network, you will also want to [configure a real TLS certificate](tls.md) to ensure the traffic can't simply be sniffed to steal the secret.
|
||||
|
||||
Here is an example of how to disable Frigate's authentication and also ensure the requests come only from your known proxy.
|
||||
|
||||
@ -109,6 +109,14 @@ proxy:
|
||||
|
||||
Frigate supports both `admin` and `viewer` roles (see below). When using port `8971`, Frigate validates these headers and subsequent requests use the headers `remote-user` and `remote-role` for authorization.
|
||||
|
||||
A default role can be provided. Any value in the mapped `role` header will override the default.
|
||||
|
||||
```yaml
|
||||
proxy:
|
||||
...
|
||||
default_role: viewer
|
||||
```
|
||||
|
||||
#### Port Considerations
|
||||
|
||||
**Authenticated Port (8971)**
|
||||
|
@ -47,7 +47,7 @@ face_recognition:
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
Fine-tune face recognition with these optional parameters:
|
||||
Fine-tune face recognition with these optional parameters at the global level of your config. The only optional parameters that can be set at the camera level are `enabled` and `min_area`.
|
||||
|
||||
### Detection
|
||||
|
||||
|
@ -78,16 +78,19 @@ proxy:
|
||||
# Optional: Mapping for headers from upstream proxies. Only used if Frigate's auth
|
||||
# is disabled.
|
||||
# NOTE: Many authentication proxies pass a header downstream with the authenticated
|
||||
# user name. Not all values are supported. It must be a whitelisted header.
|
||||
# user name and role. Not all values are supported. It must be a whitelisted header.
|
||||
# See the docs for more info.
|
||||
header_map:
|
||||
user: x-forwarded-user
|
||||
role: x-forwarded-role
|
||||
# Optional: Url for logging out a user. This sets the location of the logout url in
|
||||
# the UI.
|
||||
logout_url: /api/logout
|
||||
# Optional: Auth secret that is checked against the X-Proxy-Secret header sent from
|
||||
# the proxy. If not set, all requests are trusted regardless of origin.
|
||||
auth_secret: None
|
||||
# Optional: The default role to use for proxy auth. Must be "admin" or "viewer"
|
||||
default_role: viewer
|
||||
|
||||
# Optional: Authentication configuration
|
||||
auth:
|
||||
|
@ -74,7 +74,7 @@ def go2rtc_streams():
|
||||
)
|
||||
stream_data = r.json()
|
||||
for data in stream_data.values():
|
||||
for producer in data.get("producers", []):
|
||||
for producer in data.get("producers") or []:
|
||||
producer["url"] = clean_camera_user_pass(producer.get("url", ""))
|
||||
return JSONResponse(content=stream_data)
|
||||
|
||||
|
@ -261,14 +261,14 @@ def auth(request: Request):
|
||||
|
||||
role_header = proxy_config.header_map.role
|
||||
role = (
|
||||
request.headers.get(role_header, default="viewer")
|
||||
request.headers.get(role_header, default=proxy_config.default_role)
|
||||
if role_header
|
||||
else "viewer"
|
||||
else proxy_config.default_role
|
||||
)
|
||||
|
||||
# if comma-separated with "admin", use "admin", else "viewer"
|
||||
# if comma-separated with "admin", use "admin", else use default role
|
||||
success_response.headers["remote-role"] = (
|
||||
"admin" if role and "admin" in role else "viewer"
|
||||
"admin" if role and "admin" in role else proxy_config.default_role
|
||||
)
|
||||
|
||||
return success_response
|
||||
|
@ -30,3 +30,6 @@ class ProxyConfig(FrigateBaseModel):
|
||||
default=None,
|
||||
title="Secret value for proxy authentication.",
|
||||
)
|
||||
default_role: Optional[str] = Field(
|
||||
default="viewer", title="Default role for proxy users."
|
||||
)
|
||||
|
@ -74,7 +74,7 @@ class OnvifController:
|
||||
"features": [],
|
||||
"presets": {},
|
||||
}
|
||||
except ONVIFError as e:
|
||||
except (Fault, ONVIFError, TransportError, Exception) as e:
|
||||
logger.error(f"Failed to create ONVIF camera instance for {cam_name}: {e}")
|
||||
# track initial failures
|
||||
self.failed_cams[cam_name] = {
|
||||
@ -100,7 +100,7 @@ class OnvifController:
|
||||
# this will fire an exception if camera is not a ptz
|
||||
capabilities = onvif.get_definition("ptz")
|
||||
logger.debug(f"Onvif capabilities for {camera_name}: {capabilities}")
|
||||
except (ONVIFError, Fault, TransportError) as e:
|
||||
except (Fault, ONVIFError, TransportError, Exception) as e:
|
||||
logger.error(
|
||||
f"Unable to get Onvif capabilities for camera: {camera_name}: {e}"
|
||||
)
|
||||
@ -109,7 +109,7 @@ class OnvifController:
|
||||
try:
|
||||
profiles = await media.GetProfiles()
|
||||
logger.debug(f"Onvif profiles for {camera_name}: {profiles}")
|
||||
except (ONVIFError, Fault, TransportError) as e:
|
||||
except (Fault, ONVIFError, TransportError, Exception) as e:
|
||||
logger.error(
|
||||
f"Unable to get Onvif media profiles for camera: {camera_name}: {e}"
|
||||
)
|
||||
@ -263,7 +263,7 @@ class OnvifController:
|
||||
# setup existing presets
|
||||
try:
|
||||
presets: list[dict] = await ptz.GetPresets({"ProfileToken": profile.token})
|
||||
except ONVIFError as e:
|
||||
except (Fault, ONVIFError, TransportError, Exception) as e:
|
||||
logger.warning(f"Unable to get presets from camera: {camera_name}: {e}")
|
||||
presets = []
|
||||
|
||||
@ -392,7 +392,7 @@ class OnvifController:
|
||||
|
||||
try:
|
||||
asyncio.run(self.cams[camera_name]["ptz"].ContinuousMove(move_request))
|
||||
except ONVIFError as e:
|
||||
except (Fault, ONVIFError, TransportError, Exception) as e:
|
||||
logger.warning(f"Onvif sending move request to {camera_name} failed: {e}")
|
||||
|
||||
def _move_relative(self, camera_name: str, pan, tilt, zoom, speed) -> None:
|
||||
@ -593,7 +593,7 @@ class OnvifController:
|
||||
self._zoom(camera_name, command)
|
||||
else:
|
||||
self._move(camera_name, command)
|
||||
except ONVIFError as e:
|
||||
except (Fault, ONVIFError, TransportError, Exception) as e:
|
||||
logger.error(f"Unable to handle onvif command: {e}")
|
||||
|
||||
async def get_camera_info(self, camera_name: str) -> dict[str, any]:
|
||||
|
@ -340,7 +340,6 @@ def get_ort_providers(
|
||||
providers.append(provider)
|
||||
options.append(
|
||||
{
|
||||
"arena_extend_strategy": "kSameAsRequested",
|
||||
"cache_dir": os.path.join(MODEL_CACHE_DIR, "openvino/ort"),
|
||||
"device_type": device,
|
||||
}
|
||||
|
@ -33,5 +33,6 @@
|
||||
},
|
||||
"selected_one": "{{count}} selected",
|
||||
"selected_other": "{{count}} selected",
|
||||
"camera": "Camera"
|
||||
"camera": "Camera",
|
||||
"detected": "detected"
|
||||
}
|
||||
|
@ -190,6 +190,7 @@
|
||||
"trackedObjectsCount_one": "{{count}} tracked object ",
|
||||
"trackedObjectsCount_other": "{{count}} tracked objects ",
|
||||
"searchResult": {
|
||||
"tooltip": "Matched {{type}} at {{confidence}}%",
|
||||
"deleteTrackedObject": {
|
||||
"toast": {
|
||||
"success": "Tracked object deleted successfully.",
|
||||
|
@ -229,7 +229,7 @@ export function AnimatedEventCard({
|
||||
.map((text) => text.charAt(0).toUpperCase() + text.substring(1))
|
||||
.sort()
|
||||
.join(", ")
|
||||
.replaceAll("-verified", "")} detected`}
|
||||
.replaceAll("-verified", "")} ` + t("detected")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
|
@ -1167,9 +1167,9 @@ export function ObjectSnapshotTab({
|
||||
ns="components/dialog"
|
||||
values={{
|
||||
untranslatedLabel: search?.label,
|
||||
translatedLabel: t(
|
||||
"filter.label." + search?.label,
|
||||
),
|
||||
translatedLabel: t(search?.label, {
|
||||
ns: "objects",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
explore.plus.review.question.ask_full
|
||||
|
@ -28,9 +28,6 @@ export const getNowYesterdayInLong = (): number => {
|
||||
* The `timezone` option allows you to specify a specific timezone for the output, otherwise the user's browser timezone will be used.
|
||||
* The `use12hour` option allows you to display time in a 12-hour format if true, and 24-hour format if false.
|
||||
* The `dateStyle` and `timeStyle` options allow you to specify pre-defined formats for displaying the date and time.
|
||||
* The `strftime_fmt` option allows you to specify a custom format using the strftime syntax.
|
||||
*
|
||||
* If both `strftime_fmt` and `dateStyle`/`timeStyle` are provided, `strftime_fmt` takes precedence.
|
||||
*
|
||||
* @param unixTimestamp The Unix timestamp to format
|
||||
* @param config An object containing the configuration options for date/time display
|
||||
|
@ -531,11 +531,9 @@ export default function LiveCameraView({
|
||||
Icon={mic ? FaMicrophone : FaMicrophoneSlash}
|
||||
isActive={mic}
|
||||
title={
|
||||
(mic
|
||||
? t("button.disable", { ns: "common" })
|
||||
: t("button.enable", { ns: "common" })) +
|
||||
" " +
|
||||
t("button.twoWayTalk", { ns: "common" })
|
||||
mic
|
||||
? t("twoWayTalk.disable", { ns: "views/live" })
|
||||
: t("twoWayTalk.enable", { ns: "views/live" })
|
||||
}
|
||||
onClick={() => {
|
||||
setMic(!mic);
|
||||
@ -553,11 +551,9 @@ export default function LiveCameraView({
|
||||
Icon={audio ? GiSpeaker : GiSpeakerOff}
|
||||
isActive={audio ?? false}
|
||||
title={
|
||||
(audio
|
||||
? t("button.disable", { ns: "common" })
|
||||
: t("button.enable", { ns: "common" })) +
|
||||
" " +
|
||||
t("button.cameraAudio", { ns: "common" })
|
||||
audio
|
||||
? t("cameraAudio.disable", { ns: "views/live" })
|
||||
: t("cameraAudio.enable", { ns: "views/live" })
|
||||
}
|
||||
onClick={() => setAudio(!audio)}
|
||||
disabled={!cameraEnabled}
|
||||
|
@ -31,7 +31,7 @@ import {
|
||||
import Chip from "@/components/indicators/Chip";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
import SearchActionGroup from "@/components/filter/SearchActionGroup";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type SearchViewProps = {
|
||||
search: string;
|
||||
@ -608,8 +608,21 @@ export default function SearchView({
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
Matched {value.search_source} at{" "}
|
||||
{zScoreToConfidence(value.search_distance)}%
|
||||
<Trans
|
||||
ns="views/explore"
|
||||
values={{
|
||||
type: t(
|
||||
"filter.searchType." +
|
||||
value.search_source,
|
||||
{ ns: "views/search" },
|
||||
),
|
||||
confidence: zScoreToConfidence(
|
||||
value.search_distance,
|
||||
),
|
||||
}}
|
||||
>
|
||||
searchResult.tooltip
|
||||
</Trans>
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
|
Loading…
Reference in New Issue
Block a user