import { type FormEvent, useState } from "react"; import { Logo } from "@/components/layout/Logo"; import { Button } from "@/components/ui/Button"; import { Card, CardContent } from "@/components/ui/Card"; import { Input, Label } from "@/components/ui/Input"; import { buildBasicAuthHeader, checkCredentials, isRememberSupported, setCredentials } from "@/lib/auth"; import { useTranslation } from "@/lib/i18n"; type Status = "idle" | "submitting" | "invalid" | "unreachable"; /** Shown by LoginGate when this instance requires Basic Auth and no valid * credentials are stored yet. Doesn't implement auth itself — it just * collects a username/password, checks them against a real protected * endpoint, and on success hands them to lib/auth.ts's setCredentials(), * which is what every subsequent request actually authenticates with. */ export function LoginScreen() { const { t } = useTranslation(); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [remember, setRemember] = useState(false); const [status, setStatus] = useState("idle"); // Remembering encrypts the credential with WebCrypto, which browsers only // expose in a secure context — over plain HTTP to a LAN address there's no // safe way to persist it, so the option is hidden rather than offered and // quietly ignored. See lib/credentialVault.ts. const canRemember = isRememberSupported(); const handleSubmit = async (event: FormEvent) => { event.preventDefault(); setStatus("submitting"); const result = await checkCredentials(buildBasicAuthHeader(username, password)); if (result === "ok") { setCredentials(username, password, canRemember && remember); return; } setStatus(result === "unauthorized" ? "invalid" : "unreachable"); }; return (
Aurum {t("auth.subtitle")}
setUsername(event.target.value)} required />
setPassword(event.target.value)} required />
{canRemember ? ( ) : (

{t("auth.sessionOnlyHint")}

)} {status === "invalid" &&

{t("auth.errorInvalidCredentials")}

} {status === "unreachable" &&

{t("auth.errorUnreachable")}

}
); }