import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { System } from "@wailsio/runtime"; import Button from "@/components/buttons/Button"; import { HelpText } from "@/components/typography/HelpText"; import { Input } from "@/components/inputs/Input"; import { Label } from "@/components/typography/Label"; import { SectionGroup, SettingsBottomBar } from "@/modules/settings/SettingsSection.tsx"; import { useSettings } from "@/contexts/SettingsContext.tsx"; // macOS daemon/CLI only accept utun (Darwin parses digits as the utun unit); Linux caps at IFNAMSIZ-1 = 15 chars. const IS_MAC = System.IsMac(); const INTERFACE_NAME_RE = IS_MAC ? /^utun\d+$/ : /^[A-Za-z0-9._-]{1,15}$/; const INTERFACE_NAME_ERROR_KEY = IS_MAC ? "settings.advanced.interfaceName.errorMac" : "settings.advanced.interfaceName.error"; // Port 0 lets the daemon pick a random free port. const PORT_MIN = 0; const PORT_MAX = 65535; // Mirrors client/iface/iface.go MinMTU / MaxMTU. const MTU_MIN = 576; const MTU_MAX = 8192; export function SettingsAdvanced() { const { t } = useTranslation(); const { config, saveFields } = useSettings(); const [values, setValues] = useState({ interfaceName: config.interfaceName, wireguardPort: config.wireguardPort, mtu: config.mtu, preSharedKey: config.preSharedKey, }); const [saving, setSaving] = useState(false); useEffect(() => { setValues({ interfaceName: config.interfaceName, wireguardPort: config.wireguardPort, mtu: config.mtu, preSharedKey: config.preSharedKey, }); }, [config.interfaceName, config.wireguardPort, config.mtu, config.preSharedKey]); const errors = useMemo(() => { const out: { interfaceName?: string; wireguardPort?: string; mtu?: string } = {}; if (!INTERFACE_NAME_RE.test(values.interfaceName)) { out.interfaceName = t(INTERFACE_NAME_ERROR_KEY); } if ( !Number.isInteger(values.wireguardPort) || values.wireguardPort < PORT_MIN || values.wireguardPort > PORT_MAX ) { out.wireguardPort = t("settings.advanced.port.error", { min: PORT_MIN, max: PORT_MAX, }); } if (!Number.isInteger(values.mtu) || values.mtu < MTU_MIN || values.mtu > MTU_MAX) { out.mtu = t("settings.advanced.mtu.error", { min: MTU_MIN, max: MTU_MAX }); } return out; }, [values.interfaceName, values.wireguardPort, values.mtu, t]); const hasErrors = Object.keys(errors).length > 0; const hasChanges = values.interfaceName !== config.interfaceName || values.wireguardPort !== config.wireguardPort || values.mtu !== config.mtu || values.preSharedKey !== config.preSharedKey; const handleSave = async () => { if (!hasChanges || saving || hasErrors) return; setSaving(true); try { await saveFields(values); } finally { setSaving(false); } }; return ( <> setValues((v) => ({ ...v, interfaceName: e.target.value }))} />
setValues((v) => ({ ...v, wireguardPort: Number(e.target.value), })) } /> {t("settings.advanced.port.help")}
setValues((v) => ({ ...v, mtu: Number(e.target.value) }))} />
{t("settings.advanced.psk.help")} setValues((v) => ({ ...v, preSharedKey: e.target.value }))} />
); }