mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-03 22:04:53 +03:00
Add validations to shared link
This commit is contained in:
parent
b4a632e818
commit
878e81e05b
@ -43,7 +43,9 @@
|
|||||||
},
|
},
|
||||||
"documentTitle": "Review - Frigate",
|
"documentTitle": "Review - Frigate",
|
||||||
"recordings": {
|
"recordings": {
|
||||||
"documentTitle": "Recordings - Frigate"
|
"documentTitle": "Recordings - Frigate",
|
||||||
|
"invalidSharedLink": "Unable to open timestamped recording link due to parsing error.",
|
||||||
|
"invalidSharedCamera": "Unable to open timestamped recording link due to an unknown or unauthorized camera."
|
||||||
},
|
},
|
||||||
"calendarFilter": {
|
"calendarFilter": {
|
||||||
"last24Hours": "Last 24 Hours"
|
"last24Hours": "Last 24 Hours"
|
||||||
|
|||||||
@ -30,9 +30,10 @@ import EventView from "@/views/events/EventView";
|
|||||||
import MotionSearchView from "@/views/motion-search/MotionSearchView";
|
import MotionSearchView from "@/views/motion-search/MotionSearchView";
|
||||||
import { RecordingView } from "@/views/recording/RecordingView";
|
import { RecordingView } from "@/views/recording/RecordingView";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
|
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
|
||||||
|
import { toast } from "sonner";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
export default function Events() {
|
export default function Events() {
|
||||||
@ -74,6 +75,7 @@ export default function Events() {
|
|||||||
const [motionSearchDay, setMotionSearchDay] = useState<Date | undefined>(
|
const [motionSearchDay, setMotionSearchDay] = useState<Date | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
|
const handledReviewLinkRef = useRef<string | null>(null);
|
||||||
|
|
||||||
const motionSearchCameras = useMemo(() => {
|
const motionSearchCameras = useMemo(() => {
|
||||||
if (!config?.cameras) {
|
if (!config?.cameras) {
|
||||||
@ -257,16 +259,48 @@ export default function Events() {
|
|||||||
const timezone = searchParams.get(RECORDING_REVIEW_TIMEZONE_PARAM);
|
const timezone = searchParams.get(RECORDING_REVIEW_TIMEZONE_PARAM);
|
||||||
|
|
||||||
if (!timestamp) {
|
if (!timestamp) {
|
||||||
|
handledReviewLinkRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const camera = location.hash
|
const camera = location.hash
|
||||||
? decodeURIComponent(location.hash.substring(1))
|
? decodeURIComponent(location.hash.substring(1))
|
||||||
: null;
|
: null;
|
||||||
|
const reviewLinkKey = `${camera ?? ""}|${timestamp}|${timezone ?? ""}`;
|
||||||
|
|
||||||
|
if (handledReviewLinkRef.current === reviewLinkKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handledReviewLinkRef.current = reviewLinkKey;
|
||||||
|
|
||||||
const reviewLink = parseRecordingReviewLink(camera, timestamp, timezone);
|
const reviewLink = parseRecordingReviewLink(camera, timestamp, timezone);
|
||||||
|
|
||||||
if (!reviewLink) {
|
if (!reviewLink) {
|
||||||
|
toast.error(t("recordings.invalidSharedLink"), {
|
||||||
|
position: "top-center",
|
||||||
|
});
|
||||||
|
navigate(location.pathname, {
|
||||||
|
state: location.state,
|
||||||
|
replace: true,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reject unknown or unauthorized cameras before switching into
|
||||||
|
// recording view so bad links cleanly fall back to plain /review
|
||||||
|
const validCamera =
|
||||||
|
config.cameras[reviewLink.camera] &&
|
||||||
|
allowedCameras.includes(reviewLink.camera);
|
||||||
|
|
||||||
|
if (!validCamera) {
|
||||||
|
toast.error(t("recordings.invalidSharedCamera"), {
|
||||||
|
position: "top-center",
|
||||||
|
});
|
||||||
navigate(location.pathname, {
|
navigate(location.pathname, {
|
||||||
state: location.state,
|
state: location.state,
|
||||||
replace: true,
|
replace: true,
|
||||||
@ -298,11 +332,14 @@ export default function Events() {
|
|||||||
location.hash,
|
location.hash,
|
||||||
location.pathname,
|
location.pathname,
|
||||||
location.state,
|
location.state,
|
||||||
|
config,
|
||||||
navigate,
|
navigate,
|
||||||
|
allowedCameras,
|
||||||
getReviewDayBounds,
|
getReviewDayBounds,
|
||||||
reviewFilter,
|
reviewFilter,
|
||||||
searchParams,
|
searchParams,
|
||||||
setReviewFilter,
|
setReviewFilter,
|
||||||
|
t,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// review paging
|
// review paging
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user