69 lines
2.4 KiB
TypeScript
69 lines
2.4 KiB
TypeScript
// SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
|
//
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
export type AuthRole = "rx" | "control";
|
|
|
|
export interface AuthSession {
|
|
authenticated: boolean;
|
|
role?: AuthRole;
|
|
auth_disabled?: boolean;
|
|
}
|
|
|
|
function decodeAuthSession(value: unknown): AuthSession {
|
|
if (typeof value !== "object" || value === null) {
|
|
throw new TypeError("The authentication response is malformed");
|
|
}
|
|
const session = value as Record<string, unknown>;
|
|
if (typeof session.authenticated !== "boolean") {
|
|
throw new TypeError("The authentication response has no authenticated flag");
|
|
}
|
|
if (session.role !== undefined && session.role !== "rx" && session.role !== "control") {
|
|
throw new TypeError("The authentication response has an invalid role");
|
|
}
|
|
if (session.auth_disabled !== undefined && typeof session.auth_disabled !== "boolean") {
|
|
throw new TypeError("The authentication response has an invalid auth_disabled flag");
|
|
}
|
|
const decoded: AuthSession = { authenticated: session.authenticated };
|
|
if (session.role !== undefined) decoded.role = session.role;
|
|
if (session.auth_disabled !== undefined) decoded.auth_disabled = session.auth_disabled;
|
|
return decoded;
|
|
}
|
|
|
|
const authDisabledSession: AuthSession = {
|
|
authenticated: true,
|
|
role: "control",
|
|
auth_disabled: true,
|
|
};
|
|
|
|
export async function fetchAuthSession(): Promise<AuthSession> {
|
|
try {
|
|
const response = await fetch("/auth/session");
|
|
if (response.status === 404) return authDisabledSession;
|
|
if (!response.ok) return { authenticated: false };
|
|
return decodeAuthSession(await response.json());
|
|
} catch (error: unknown) {
|
|
console.error("Auth check failed:", error);
|
|
return { authenticated: false };
|
|
}
|
|
}
|
|
|
|
export async function login(passphrase: string): Promise<AuthSession> {
|
|
const response = await fetch("/auth/login", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ passphrase }),
|
|
});
|
|
if (response.status === 404) return authDisabledSession;
|
|
if (!response.ok) {
|
|
const message = await response.text();
|
|
throw new Error(message || "Login failed");
|
|
}
|
|
return decodeAuthSession(await response.json());
|
|
}
|
|
|
|
export async function logout(): Promise<void> {
|
|
const response = await fetch("/auth/logout", { method: "POST" });
|
|
if (response.status !== 404 && !response.ok) throw new Error("Logout failed");
|
|
}
|