mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-01 19:17:41 +03:00
docs: remove 5000 port tips
This commit is contained in:
parent
39f9491971
commit
6cc4db1103
@ -32,12 +32,12 @@ function renderHelpText(text: string): React.ReactNode {
|
|||||||
export default function DockerComposeGenerator() {
|
export default function DockerComposeGenerator() {
|
||||||
const {
|
const {
|
||||||
deviceId, device, hardwareEnabled,
|
deviceId, device, hardwareEnabled,
|
||||||
portEnabled, port5000Confirmed,
|
portEnabled,
|
||||||
nvidiaGpuCount, nvidiaGpuDeviceId,
|
nvidiaGpuCount, nvidiaGpuDeviceId,
|
||||||
configPath, mediaPath, rtspPassword, timezone, shmSize,
|
configPath, mediaPath, rtspPassword, timezone, shmSize,
|
||||||
shmSizeError, gpuDeviceIdError, configPathError, mediaPathError,
|
shmSizeError, gpuDeviceIdError, configPathError, mediaPathError,
|
||||||
hasAnyHardware, generatedYaml,
|
hasAnyHardware, generatedYaml,
|
||||||
selectDevice, toggleHardware, togglePort, setPort5000Confirmed,
|
selectDevice, toggleHardware, togglePort,
|
||||||
handleShmSizeChange, handleConfigPathChange, handleMediaPathChange,
|
handleShmSizeChange, handleConfigPathChange, handleMediaPathChange,
|
||||||
handleNvidiaGpuCountChange, handleNvidiaGpuDeviceIdChange,
|
handleNvidiaGpuCountChange, handleNvidiaGpuDeviceIdChange,
|
||||||
setRtspPassword, setTimezone, isHardwareDisabled,
|
setRtspPassword, setTimezone, isHardwareDisabled,
|
||||||
@ -82,9 +82,7 @@ export default function DockerComposeGenerator() {
|
|||||||
|
|
||||||
<PortConfigSection
|
<PortConfigSection
|
||||||
portEnabled={portEnabled}
|
portEnabled={portEnabled}
|
||||||
port5000Confirmed={port5000Confirmed}
|
|
||||||
onTogglePort={togglePort}
|
onTogglePort={togglePort}
|
||||||
onConfirm5000={setPort5000Confirmed}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<OtherOptions
|
<OtherOptions
|
||||||
|
|||||||
@ -1,125 +1,71 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Admonition from "@theme/Admonition";
|
import Admonition from "@theme/Admonition";
|
||||||
import { ports } from "../config";
|
import { ports } from "../config";
|
||||||
import { useCooldown } from "../hooks/useCooldown";
|
|
||||||
import styles from "../styles.module.css";
|
import styles from "../styles.module.css";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
portEnabled: Record<string, boolean>;
|
portEnabled: Record<string, boolean>;
|
||||||
port5000Confirmed: boolean;
|
|
||||||
onTogglePort: (portId: string) => void;
|
onTogglePort: (portId: string) => void;
|
||||||
onConfirm5000: (confirmed: boolean) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Port5000Confirmation({
|
function PortItem({
|
||||||
portEnabled,
|
port,
|
||||||
confirmed,
|
enabled,
|
||||||
onToggle,
|
onToggle,
|
||||||
onConfirm,
|
|
||||||
}: {
|
}: {
|
||||||
portEnabled: boolean;
|
port: typeof ports[number];
|
||||||
confirmed: boolean;
|
enabled: boolean;
|
||||||
onToggle: () => void;
|
onToggle: () => void;
|
||||||
onConfirm: (confirmed: boolean) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const { remaining, start, stop } = useCooldown(10);
|
const showWarning = port.warningContent && (
|
||||||
|
port.warningWhen === "checked" ? enabled :
|
||||||
React.useEffect(() => {
|
port.warningWhen === "unchecked" ? !enabled : enabled
|
||||||
if (portEnabled) {
|
);
|
||||||
start();
|
|
||||||
} else {
|
|
||||||
stop();
|
|
||||||
onConfirm(false);
|
|
||||||
}
|
|
||||||
return stop;
|
|
||||||
}, [portEnabled]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.portSection}>
|
<div className={styles.hardwareItem}>
|
||||||
{portEnabled && (
|
<label className={`${styles.checkboxLabel} ${port.locked ? styles.checkboxDisabled : ""}`}>
|
||||||
<Admonition type="danger">
|
|
||||||
<p>
|
|
||||||
Exposing port 5000 allows <strong>unauthenticated access</strong> to
|
|
||||||
your Frigate instance. Anyone on your network (or the internet if you
|
|
||||||
have a public IP) could access it without credentials.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
This may lead to <strong>unauthorized access</strong>,{" "}
|
|
||||||
<strong>privacy leaks</strong>, or further attacks. Ensure you have
|
|
||||||
proper firewall rules or VPN in place.
|
|
||||||
</p>
|
|
||||||
<label
|
|
||||||
className={`${styles.checkboxLabel} ${remaining > 0 ? styles.checkboxDisabled : ""}`}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={confirmed}
|
|
||||||
onChange={(e) => onConfirm(e.target.checked)}
|
|
||||||
disabled={remaining > 0}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
I understand the risk and confirm enabling port 5000
|
|
||||||
{remaining > 0 && ` (${remaining}s)`}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</Admonition>
|
|
||||||
)}
|
|
||||||
<label className={styles.checkboxLabel}>
|
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={portEnabled}
|
checked={enabled}
|
||||||
onChange={onToggle}
|
onChange={onToggle}
|
||||||
|
disabled={port.locked}
|
||||||
/>
|
/>
|
||||||
<span>Port 5000 (unauthenticated access)</span>
|
<span>
|
||||||
<span className={styles.warningBadge}>⚠️ Expose carefully</span>
|
{port.locked && "🔒 "}
|
||||||
|
Port {port.host}
|
||||||
|
{port.protocol !== "tcp" && `/${port.protocol}`}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
{port.description && (
|
||||||
|
<div className={styles.hardwareDescription}>{port.description}</div>
|
||||||
|
)}
|
||||||
|
{showWarning && (
|
||||||
|
<Admonition type={port.warningType || "warning"}>
|
||||||
|
{port.warningContent}
|
||||||
|
</Admonition>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PortConfigSection({
|
export default function PortConfigSection({
|
||||||
portEnabled,
|
portEnabled,
|
||||||
port5000Confirmed,
|
|
||||||
onTogglePort,
|
onTogglePort,
|
||||||
onConfirm5000,
|
|
||||||
}: Props) {
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.formSection}>
|
<div className={styles.formSection}>
|
||||||
<h4>Port Configuration</h4>
|
<h4>Port Configuration</h4>
|
||||||
|
|
||||||
{/* All ports except 5000 */}
|
|
||||||
<div className={styles.checkboxGrid}>
|
<div className={styles.checkboxGrid}>
|
||||||
{ports
|
{ports.map((port) => (
|
||||||
.filter((p) => p.id !== "5000")
|
<PortItem
|
||||||
.map((port) => (
|
key={port.id}
|
||||||
<div key={port.id} className={styles.hardwareItem}>
|
port={port}
|
||||||
<label className={`${styles.checkboxLabel} ${port.locked ? styles.checkboxDisabled : ""}`}>
|
enabled={!!portEnabled[port.id]}
|
||||||
<input
|
onToggle={() => onTogglePort(port.id)}
|
||||||
type="checkbox"
|
/>
|
||||||
checked={!!portEnabled[port.id]}
|
))}
|
||||||
onChange={() => onTogglePort(port.id)}
|
|
||||||
disabled={port.locked}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
{port.locked && "🔒 "}
|
|
||||||
Port {port.host}
|
|
||||||
{port.protocol !== "tcp" && `/${port.protocol}`}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
{port.description && (
|
|
||||||
<div className={styles.hardwareDescription}>{port.description}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Port 5000 with special warning — placed last */}
|
|
||||||
<Port5000Confirmation
|
|
||||||
portEnabled={!!portEnabled["5000"]}
|
|
||||||
confirmed={port5000Confirmed}
|
|
||||||
onToggle={() => onTogglePort("5000")}
|
|
||||||
onConfirm={onConfirm5000}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -265,7 +265,8 @@ ports:
|
|||||||
protocol: "tcp"
|
protocol: "tcp"
|
||||||
description: "Authenticated UI and API access (default HTTPS)"
|
description: "Authenticated UI and API access (default HTTPS)"
|
||||||
defaultEnabled: true
|
defaultEnabled: true
|
||||||
locked: true
|
warningContent: "This is the access port for Frigate. Closing it means you will no longer be able to access the instance."
|
||||||
|
warningWhen: "unchecked"
|
||||||
|
|
||||||
- id: "8554"
|
- id: "8554"
|
||||||
host: 8554
|
host: 8554
|
||||||
|
|||||||
@ -145,14 +145,10 @@ export interface PortConfig {
|
|||||||
defaultEnabled: boolean;
|
defaultEnabled: boolean;
|
||||||
/** Whether this port is locked (always enabled, cannot be toggled off) */
|
/** Whether this port is locked (always enabled, cannot be toggled off) */
|
||||||
locked?: boolean;
|
locked?: boolean;
|
||||||
/** Whether this port requires a confirmation step before enabling */
|
|
||||||
requiresConfirmation?: boolean;
|
|
||||||
/** Admonition type for the warning */
|
/** Admonition type for the warning */
|
||||||
warningType?: "warning" | "danger";
|
warningType?: "warning" | "danger";
|
||||||
/** Warning content (markdown) */
|
/** Warning content (markdown) */
|
||||||
warningContent?: string;
|
warningContent?: string;
|
||||||
/** Confirmation checkbox label */
|
/** When to show the warning: when the port is checked or unchecked */
|
||||||
confirmationLabel?: string;
|
warningWhen?: "checked" | "unchecked";
|
||||||
/** Cooldown in seconds before the confirmation checkbox becomes available */
|
|
||||||
cooldownSeconds?: number;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,6 @@ export function useConfigGenerator() {
|
|||||||
return initial;
|
return initial;
|
||||||
});
|
});
|
||||||
|
|
||||||
const [port5000Confirmed, setPort5000Confirmed] = useState(false);
|
|
||||||
const [nvidiaGpuCount, setNvidiaGpuCount] = useState("all");
|
const [nvidiaGpuCount, setNvidiaGpuCount] = useState("all");
|
||||||
const [nvidiaGpuDeviceId, setNvidiaGpuDeviceId] = useState("");
|
const [nvidiaGpuDeviceId, setNvidiaGpuDeviceId] = useState("");
|
||||||
const [configPath, setConfigPath] = useState("");
|
const [configPath, setConfigPath] = useState("");
|
||||||
@ -69,13 +68,7 @@ export function useConfigGenerator() {
|
|||||||
const togglePort = useCallback((portId: string) => {
|
const togglePort = useCallback((portId: string) => {
|
||||||
const port = portMap.get(portId);
|
const port = portMap.get(portId);
|
||||||
if (port?.locked) return;
|
if (port?.locked) return;
|
||||||
setPortEnabled((prev) => {
|
setPortEnabled((prev) => ({ ...prev, [portId]: !prev[portId] }));
|
||||||
const next = { ...prev, [portId]: !prev[portId] };
|
|
||||||
if (portId === "5000" && !next[portId]) {
|
|
||||||
setPort5000Confirmed(false);
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const isHardwareDisabled = useCallback(
|
const isHardwareDisabled = useCallback(
|
||||||
@ -149,7 +142,6 @@ export function useConfigGenerator() {
|
|||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
for (const [id, enabled] of Object.entries(portEnabled)) {
|
for (const [id, enabled] of Object.entries(portEnabled)) {
|
||||||
if (!enabled) continue;
|
if (!enabled) continue;
|
||||||
if (id === "5000" && !port5000Confirmed) continue;
|
|
||||||
const p = portMap.get(id);
|
const p = portMap.get(id);
|
||||||
if (!p) continue;
|
if (!p) continue;
|
||||||
const proto = p.protocol && p.protocol !== "tcp" ? `/${p.protocol}` : "";
|
const proto = p.protocol && p.protocol !== "tcp" ? `/${p.protocol}` : "";
|
||||||
@ -157,7 +149,7 @@ export function useConfigGenerator() {
|
|||||||
lines.push(` - "${p.host}:${p.container}${proto}"${comment}`);
|
lines.push(` - "${p.host}:${p.container}${proto}"${comment}`);
|
||||||
}
|
}
|
||||||
return lines;
|
return lines;
|
||||||
}, [portEnabled, port5000Confirmed]);
|
}, [portEnabled]);
|
||||||
|
|
||||||
const selectedHardwareIds = useMemo(() => {
|
const selectedHardwareIds = useMemo(() => {
|
||||||
return Object.entries(hardwareEnabled)
|
return Object.entries(hardwareEnabled)
|
||||||
@ -195,11 +187,11 @@ export function useConfigGenerator() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
deviceId, device, hardwareEnabled, portEnabled,
|
deviceId, device, hardwareEnabled, portEnabled,
|
||||||
port5000Confirmed, nvidiaGpuCount, nvidiaGpuDeviceId,
|
nvidiaGpuCount, nvidiaGpuDeviceId,
|
||||||
configPath, mediaPath, rtspPassword, timezone, shmSize,
|
configPath, mediaPath, rtspPassword, timezone, shmSize,
|
||||||
shmSizeError, gpuDeviceIdError, configPathError, mediaPathError,
|
shmSizeError, gpuDeviceIdError, configPathError, mediaPathError,
|
||||||
hasAnyHardware, generatedYaml,
|
hasAnyHardware, generatedYaml,
|
||||||
selectDevice, toggleHardware, togglePort, setPort5000Confirmed,
|
selectDevice, toggleHardware, togglePort,
|
||||||
handleShmSizeChange, handleConfigPathChange, handleMediaPathChange,
|
handleShmSizeChange, handleConfigPathChange, handleMediaPathChange,
|
||||||
handleNvidiaGpuCountChange, handleNvidiaGpuDeviceIdChange,
|
handleNvidiaGpuCountChange, handleNvidiaGpuDeviceIdChange,
|
||||||
setRtspPassword, setTimezone, isHardwareDisabled,
|
setRtspPassword, setTimezone, isHardwareDisabled,
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
import { useState, useEffect, useCallback, useRef } from "react";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for a countdown timer (e.g. cooldown before confirming port 5000).
|
|
||||||
*/
|
|
||||||
export function useCooldown(initialSeconds: number) {
|
|
||||||
const [remaining, setRemaining] = useState(0);
|
|
||||||
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
||||||
|
|
||||||
const start = useCallback(() => {
|
|
||||||
// Clear any existing timer
|
|
||||||
if (timerRef.current) clearInterval(timerRef.current);
|
|
||||||
setRemaining(initialSeconds);
|
|
||||||
timerRef.current = setInterval(() => {
|
|
||||||
setRemaining((prev) => {
|
|
||||||
if (prev <= 1) {
|
|
||||||
if (timerRef.current) clearInterval(timerRef.current);
|
|
||||||
timerRef.current = null;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return prev - 1;
|
|
||||||
});
|
|
||||||
}, 1000);
|
|
||||||
}, [initialSeconds]);
|
|
||||||
|
|
||||||
const stop = useCallback(() => {
|
|
||||||
if (timerRef.current) {
|
|
||||||
clearInterval(timerRef.current);
|
|
||||||
timerRef.current = null;
|
|
||||||
}
|
|
||||||
setRemaining(0);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Cleanup on unmount
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
if (timerRef.current) clearInterval(timerRef.current);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return { remaining, start, stop };
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user