refactor, security updates, cv extraction upgrades

This commit is contained in:
2026-04-11 01:34:32 +02:00
parent 806b200ac5
commit 27fd70a2d7
59 changed files with 6817 additions and 1561 deletions
+38 -56
View File
@@ -1,13 +1,9 @@
export const AUTH_TOKEN_KEY = "authToken";
export const AUTH_REMEMBER_ME_KEY = "authRememberMe";
const LEGACY_AUTH_TOKEN_KEY = "googleIdToken";
const AUTH_TOKEN_PERSISTENCE_KEY = "authTokenPersistence";
const AUTH_PERSISTENCE_KEY = "authTokenPersistence";
const AUTH_USER_KEY = "authUserKey";
const AUTH_CSRF_COOKIE = "XSRF-TOKEN";
type AuthPersistence = "local" | "session";
function normalizePersistence(value: string | null | undefined): AuthPersistence {
return value === "session" ? "session" : "local";
}
export type AuthPersistence = "local" | "session";
function safeGet(storage: Storage, key: string): string | null {
try {
@@ -33,28 +29,27 @@ function safeRemove(storage: Storage, key: string) {
}
}
function emitAuthChanged() {
window.dispatchEvent(new Event("auth-changed"));
}
function normalizePersistence(value: string | null | undefined): AuthPersistence {
return value === "session" ? "session" : "local";
}
function persistPreference(persistence: AuthPersistence) {
safeSet(window.localStorage, AUTH_TOKEN_PERSISTENCE_KEY, persistence);
safeSet(window.localStorage, AUTH_PERSISTENCE_KEY, persistence);
safeSet(window.localStorage, AUTH_REMEMBER_ME_KEY, persistence === "local" ? "1" : "0");
}
function getStoredPersistence(): AuthPersistence {
const explicit = safeGet(window.localStorage, AUTH_TOKEN_PERSISTENCE_KEY);
const explicit = safeGet(window.localStorage, AUTH_PERSISTENCE_KEY);
if (explicit) return normalizePersistence(explicit);
const rememberMe = safeGet(window.localStorage, AUTH_REMEMBER_ME_KEY);
if (rememberMe === "0") return "session";
return "local";
}
function migrateLegacyToken(): string | null {
const legacy = safeGet(window.localStorage, LEGACY_AUTH_TOKEN_KEY) ?? safeGet(window.sessionStorage, LEGACY_AUTH_TOKEN_KEY);
if (!legacy) return null;
safeRemove(window.localStorage, LEGACY_AUTH_TOKEN_KEY);
safeRemove(window.sessionStorage, LEGACY_AUTH_TOKEN_KEY);
setAuthToken(legacy, getStoredPersistence());
return legacy;
}
export function getRememberMePref(): boolean {
return getAuthPersistencePreference() === "local";
}
@@ -63,53 +58,40 @@ export function setRememberMePref(value: boolean) {
persistPreference(value ? "local" : "session");
}
export function getAuthToken(): string | null {
const localToken = safeGet(window.localStorage, AUTH_TOKEN_KEY);
if (localToken) {
persistPreference("local");
return localToken;
}
const sessionToken = safeGet(window.sessionStorage, AUTH_TOKEN_KEY);
if (sessionToken) {
persistPreference("session");
return sessionToken;
}
return migrateLegacyToken();
}
export function getAuthPersistencePreference(): AuthPersistence {
if (safeGet(window.sessionStorage, AUTH_TOKEN_KEY)) return "session";
if (safeGet(window.localStorage, AUTH_TOKEN_KEY)) return "local";
return getStoredPersistence();
}
export function setAuthToken(token: string, persistence: AuthPersistence = "local") {
safeRemove(window.localStorage, AUTH_TOKEN_KEY);
safeRemove(window.sessionStorage, AUTH_TOKEN_KEY);
if (persistence === "session") {
safeSet(window.sessionStorage, AUTH_TOKEN_KEY, token);
} else {
safeSet(window.localStorage, AUTH_TOKEN_KEY, token);
}
export function setAuthPersistencePreference(persistence: AuthPersistence) {
persistPreference(persistence);
emitAuthChanged();
}
export function clearAuthToken() {
safeRemove(window.localStorage, AUTH_TOKEN_KEY);
safeRemove(window.sessionStorage, AUTH_TOKEN_KEY);
export function getAuthUserKey(): string {
return safeGet(window.localStorage, AUTH_USER_KEY) ?? "anon";
}
export function decodeJwtPayload(token: string): any {
export function setAuthUserKey(value: string | null | undefined, emit = true) {
const next = typeof value === "string" ? value.trim() : "";
if (!next) {
safeRemove(window.localStorage, AUTH_USER_KEY);
} else {
safeSet(window.localStorage, AUTH_USER_KEY, next);
}
if (emit) emitAuthChanged();
}
export function clearAuthClientState(emit = true) {
safeRemove(window.localStorage, AUTH_USER_KEY);
if (emit) emitAuthChanged();
}
export function getCsrfToken(): string | null {
try {
const parts = token.split(".");
if (parts.length < 2) return null;
const base64 = parts[1].replaceAll("-", "+").replaceAll("_", "/");
const json = atob(base64);
return JSON.parse(json);
const parts = document.cookie.split(";").map((part) => part.trim());
const match = parts.find((part) => part.startsWith(`${AUTH_CSRF_COOKIE}=`));
if (!match) return null;
return decodeURIComponent(match.slice(AUTH_CSRF_COOKIE.length + 1));
} catch {
return null;
}