web: separate search route
This commit is contained in:
103
web/src/hooks/use-session-auth.ts
Normal file
103
web/src/hooks/use-session-auth.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { getConfiguredToken, setAuthToken, verifySession } from "@/lib/api";
|
||||
|
||||
const TOKEN_STORAGE_KEY = "sybil_admin_token";
|
||||
|
||||
export type AuthMode = "open" | "token";
|
||||
|
||||
function readStoredToken() {
|
||||
return localStorage.getItem(TOKEN_STORAGE_KEY)?.trim() || null;
|
||||
}
|
||||
|
||||
function persistToken(token: string | null) {
|
||||
if (token) {
|
||||
localStorage.setItem(TOKEN_STORAGE_KEY, token);
|
||||
return;
|
||||
}
|
||||
localStorage.removeItem(TOKEN_STORAGE_KEY);
|
||||
}
|
||||
|
||||
function normalizeAuthError(message: string) {
|
||||
if (message.includes("missing bearer token") || message.includes("invalid bearer token")) {
|
||||
return "Authentication failed. Enter the ADMIN_TOKEN configured in server/.env.";
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
export function useSessionAuth() {
|
||||
const initialToken = readStoredToken() ?? getConfiguredToken() ?? "";
|
||||
|
||||
const [authTokenInput, setAuthTokenInput] = useState(initialToken);
|
||||
const [isCheckingSession, setIsCheckingSession] = useState(true);
|
||||
const [isSigningIn, setIsSigningIn] = useState(false);
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [authMode, setAuthMode] = useState<AuthMode | null>(null);
|
||||
const [authError, setAuthError] = useState<string | null>(null);
|
||||
|
||||
const completeSessionCheck = async (tokenCandidate: string | null) => {
|
||||
setAuthToken(tokenCandidate);
|
||||
const session = await verifySession();
|
||||
setIsAuthenticated(true);
|
||||
setAuthMode(session.mode);
|
||||
setAuthError(null);
|
||||
persistToken(tokenCandidate);
|
||||
};
|
||||
|
||||
const handleAuthFailure = (message: string) => {
|
||||
setIsAuthenticated(false);
|
||||
setAuthMode(null);
|
||||
setAuthError(normalizeAuthError(message));
|
||||
setAuthToken(null);
|
||||
persistToken(null);
|
||||
};
|
||||
|
||||
const handleSignIn = async (tokenCandidate: string | null) => {
|
||||
setIsSigningIn(true);
|
||||
setAuthError(null);
|
||||
try {
|
||||
await completeSessionCheck(tokenCandidate);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
setAuthError(normalizeAuthError(message));
|
||||
setIsAuthenticated(false);
|
||||
setAuthMode(null);
|
||||
} finally {
|
||||
setIsSigningIn(false);
|
||||
}
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
setAuthToken(null);
|
||||
persistToken(null);
|
||||
setIsAuthenticated(false);
|
||||
setAuthMode(null);
|
||||
setAuthError(null);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const token = readStoredToken() ?? getConfiguredToken();
|
||||
void (async () => {
|
||||
try {
|
||||
await completeSessionCheck(token);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
handleAuthFailure(message);
|
||||
} finally {
|
||||
setIsCheckingSession(false);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
authTokenInput,
|
||||
setAuthTokenInput,
|
||||
isCheckingSession,
|
||||
isSigningIn,
|
||||
isAuthenticated,
|
||||
authMode,
|
||||
authError,
|
||||
handleAuthFailure,
|
||||
handleSignIn,
|
||||
logout,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user