Spaces:
Running
Running
| /** | |
| * auth-init.js β Enterprise Authentication Initialization | |
| * * Runs on page load to establish UI auth state and protect routes. | |
| * Strictly aligned with HTTP-Only Cookie architecture. | |
| */ | |
| (function initAuthState() { | |
| 'use strict'; | |
| const currentPath = window.location.pathname; | |
| // ββ 1. Check if user just logged in ββββββββββββββββββββββββββββββββββββββ | |
| const justLoggedIn = sessionStorage.getItem('just_logged_in'); | |
| if (justLoggedIn) sessionStorage.removeItem('just_logged_in'); | |
| // ββ 2. Sync User Metadata ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // We treat the 'user' object in localStorage as our UI "Auth Hint". | |
| // The actual security is handled by the invisible HTTP-Only access_token cookie. | |
| // Cookie Sync: Check for the 'qualora_logged_in' mirror cookie. | |
| // This allows JS to see if the server thinks we are authenticated (breaks 302 loops). | |
| function getCookie(name) { | |
| const value = `; ${document.cookie}`; | |
| const parts = value.split(`; ${name}=`); | |
| if (parts.length === 2) return parts.pop().split(';').shift(); | |
| return null; | |
| } | |
| const isLoggedIn = getCookie('qualora_logged_in') === 'true'; | |
| let userJSON = localStorage.getItem('user'); | |
| // Fallback to session if local is empty (e.g., privacy mode) | |
| if (!userJSON) { | |
| userJSON = sessionStorage.getItem('user'); | |
| if (userJSON) localStorage.setItem('user', userJSON); | |
| } | |
| let user = null; | |
| if (userJSON) { | |
| try { | |
| // If the mirror cookie is missing, the server session is gone. | |
| // We MUST purge the local 'Auth Hint' to prevent redirect loops. | |
| if (!isLoggedIn && !justLoggedIn) { | |
| localStorage.removeItem('user'); | |
| sessionStorage.removeItem('user'); | |
| userJSON = null; | |
| } else { | |
| user = JSON.parse(userJSON); | |
| // Validation: Ensure it's a real user object | |
| if (!user || (!user.email && !user._id)) { | |
| user = null; | |
| localStorage.removeItem('user'); | |
| } | |
| } | |
| } catch (e) { | |
| console.warn('[Qualora] Failed to parse user metadata:', e.message); | |
| localStorage.removeItem('user'); | |
| } | |
| } | |
| // ββ 3. Route Guarding ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // List of routes that require an authenticated session | |
| const protectedRoutes = ['/dashboard', '/audit', '/admin', '/knowledge-base', '/agents']; | |
| const isProtectedRoute = protectedRoutes.some(route => currentPath.startsWith(route)); | |
| if (isProtectedRoute && !user) { | |
| // Race condition check: If we just logged in, allow temporary pass-through | |
| if (justLoggedIn) { | |
| user = { _id: 'loading', email: 'loading...', temp: true }; | |
| } else { | |
| console.warn('[Qualora] Unauthorized access attempt. Redirecting to landing.'); | |
| window.location.href = '/'; | |
| return; | |
| } | |
| } | |
| // ββ 4. Landing Page Logic ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // If authenticated and sitting on landing page, move to dashboard | |
| if ((currentPath === '/' || currentPath === '/index.html') && user && !user.temp) { | |
| window.location.href = '/dashboard'; | |
| return; | |
| } | |
| // ββ 5. Establish Global Auth Context βββββββββββββββββββββββββββββββββββββ | |
| // NOTE: 'token' is now null because it is hidden in an HTTP-Only cookie. | |
| window.__authState = { | |
| isAuthenticated: !!user && !user.temp, | |
| user: user, | |
| cookieManaged: true, // Internal flag for fetch-wrapper | |
| lastChecked: new Date().toISOString() | |
| }; | |
| // Notify other modules (like nav-controllers) that auth state is ready | |
| document.dispatchEvent(new CustomEvent('authStateReady', { | |
| detail: window.__authState | |
| })); | |
| console.log(`[Qualora] Auth initialized. Mode: ${user ? 'Authenticated' : 'Guest'}`); | |
| })(); |