docs: remove 5000 port tips

This commit is contained in:
ZhaiSoul 2026-04-29 14:13:32 +08:00
parent 39f9491971
commit 6cc4db1103
6 changed files with 44 additions and 153 deletions

View File

@ -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

View File

@ -1,103 +1,34 @@
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 (
<div className={styles.portSection}>
{portEnabled && (
<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
type="checkbox"
checked={portEnabled}
onChange={onToggle}
/>
<span>Port 5000 (unauthenticated access)</span>
<span className={styles.warningBadge}> Expose carefully</span>
</label>
</div>
); );
}
export default function PortConfigSection({
portEnabled,
port5000Confirmed,
onTogglePort,
onConfirm5000,
}: Props) {
return ( return (
<div className={styles.formSection}> <div className={styles.hardwareItem}>
<h4>Port Configuration</h4>
{/* All ports except 5000 */}
<div className={styles.checkboxGrid}>
{ports
.filter((p) => p.id !== "5000")
.map((port) => (
<div key={port.id} className={styles.hardwareItem}>
<label className={`${styles.checkboxLabel} ${port.locked ? styles.checkboxDisabled : ""}`}> <label className={`${styles.checkboxLabel} ${port.locked ? styles.checkboxDisabled : ""}`}>
<input <input
type="checkbox" type="checkbox"
checked={!!portEnabled[port.id]} checked={enabled}
onChange={() => onTogglePort(port.id)} onChange={onToggle}
disabled={port.locked} disabled={port.locked}
/> />
<span> <span>
@ -109,17 +40,32 @@ export default function PortConfigSection({
{port.description && ( {port.description && (
<div className={styles.hardwareDescription}>{port.description}</div> <div className={styles.hardwareDescription}>{port.description}</div>
)} )}
</div> {showWarning && (
))} <Admonition type={port.warningType || "warning"}>
</div> {port.warningContent}
</Admonition>
{/* Port 5000 with special warning — placed last */} )}
<Port5000Confirmation </div>
portEnabled={!!portEnabled["5000"]} );
confirmed={port5000Confirmed} }
onToggle={() => onTogglePort("5000")}
onConfirm={onConfirm5000} export default function PortConfigSection({
/> portEnabled,
onTogglePort,
}: Props) {
return (
<div className={styles.formSection}>
<h4>Port Configuration</h4>
<div className={styles.checkboxGrid}>
{ports.map((port) => (
<PortItem
key={port.id}
port={port}
enabled={!!portEnabled[port.id]}
onToggle={() => onTogglePort(port.id)}
/>
))}
</div>
</div> </div>
); );
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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,

View File

@ -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 };
}