app: use auth model for init, sidebar, login
This commit is contained in:
+22
-4
@@ -1,4 +1,4 @@
|
||||
import { h, render, Link, hComp, ToastContainer, connect, apiFetch, modelRegister, modelFetch, reactive, initAuth, getAuthToken, checkSession } from '/static/hoover/index.js';
|
||||
import { h, render, Link, hComp, ToastContainer, connect, disconnect, apiFetch, modelRegister, modelFetch, reactive, createAuthModel, isAuthenticated, getAuthData } from '/static/hoover/index.js';
|
||||
|
||||
import DashboardPage from '/static/pages/dashboard.js';
|
||||
import InterfacesPage from '/static/pages/interfaces.js';
|
||||
@@ -32,14 +32,17 @@ const _NavBase = [
|
||||
];
|
||||
|
||||
function getNav() {
|
||||
const perms = getAuthData()?.permissions;
|
||||
const nav = [..._NavBase];
|
||||
const perms = JSON.parse(sessionStorage.getItem('vw:permissions') || 'null');
|
||||
if (perms && perms.auth === 'rw') {
|
||||
nav.push({ path: '/users', label: 'Users' });
|
||||
}
|
||||
return nav;
|
||||
}
|
||||
|
||||
/* ── Auth model (silent topic — the daemon never broadcasts 'auth') ── */
|
||||
modelRegister('auth', createAuthModel());
|
||||
|
||||
modelRegister('firewall', {
|
||||
subsystem: 'firewall',
|
||||
fetch: async () => {
|
||||
@@ -266,14 +269,29 @@ export async function initApp() {
|
||||
// Listen for login events to update router state after auth
|
||||
window.addEventListener('auth:login', () => {
|
||||
router.isAuthenticated = true;
|
||||
// Defer to a macrotask: at dispatch time (microtask) the login form's
|
||||
// hash change has not run yet — router.state.path is still '/login'.
|
||||
// The deferred check runs after the hashchange task, so a fresh login
|
||||
// fetches all models. connect() is idempotent (_wsConnect no-ops with
|
||||
// a live connection) and gives the post-login session its WS — today
|
||||
// WS only connects on an authenticated page load (pre-existing gap).
|
||||
setTimeout(() => {
|
||||
connect();
|
||||
if (!router.state.path.startsWith('/login')) {
|
||||
fetchInitialData();
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// Terminal auth transition — close the WS socket so a same-tab relogin
|
||||
// establishes a fresh connection with the new user's token.
|
||||
window.addEventListener('auth:logout', () => {
|
||||
disconnect();
|
||||
});
|
||||
|
||||
// Check auth state before connecting WS
|
||||
const ok = await initAuth();
|
||||
if (ok) {
|
||||
await modelFetch('auth', { action: 'check' });
|
||||
if (isAuthenticated()) {
|
||||
router.isAuthenticated = true;
|
||||
fetchInitialData();
|
||||
setTimeout(connect, 0);
|
||||
|
||||
@@ -23,13 +23,19 @@ export { definePage, hComp } from './component.js';
|
||||
export { createRouter, Link } from './router.js';
|
||||
|
||||
/* ── WebSocket ───────────────────────────────────────────────── */
|
||||
export { connect, onMessage } from './websocket.js';
|
||||
export { connect, onMessage, disconnect } from './websocket.js';
|
||||
|
||||
/* ── API & Toast ─────────────────────────────────────────────── */
|
||||
export { apiFetch, toast, dismissToast, apiSubmit, checkAbort, poll, refactorLoad, formAction, setAuthToken, clearAuthTokens, getAuthToken } from './api.js';
|
||||
export { apiFetch, toast, dismissToast, apiSubmit, checkAbort, poll, refactorLoad, formAction }
|
||||
from './api.js';
|
||||
|
||||
/* ── UI Components: Auth ──────────────────────────────────────── */
|
||||
export { scheduleTokenRefresh, cancelTokenRefresh, checkSession, logout, initAuth, handleLoginSuccess, webauthnSupported, startRegistration, startAuthentication } from './components/auth.js';
|
||||
export { logout, doLogin, webauthnSupported, checkWebAuthnCapable,
|
||||
startRegistration, startAuthentication } from './components/auth.js';
|
||||
|
||||
/* ── Auth model ───────────────────────────────────────────────── */
|
||||
export { createAuthModel, getAuthToken, isAuthenticated, refreshAuth, getAuthData }
|
||||
from './auth_model.js';
|
||||
|
||||
/* ── Model ───────────────────────────────────────────────────── */
|
||||
export { modelRegister, getModel, modelFetch, collectLoadingModels } from './model.js';
|
||||
|
||||
@@ -11,9 +11,7 @@ import {
|
||||
html,
|
||||
apiFetch,
|
||||
toast,
|
||||
setAuthToken,
|
||||
getAuthToken,
|
||||
handleLoginSuccess,
|
||||
doLogin,
|
||||
webauthnSupported,
|
||||
startAuthentication,
|
||||
esc,
|
||||
@@ -89,7 +87,7 @@ async function doPasswordLogin() {
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
handleLoginSuccess(res.data);
|
||||
doLogin(res.data);
|
||||
toast('Welcome, ' + esc(username), 'success');
|
||||
} else {
|
||||
errEl.textContent = res.error || 'Login failed';
|
||||
@@ -173,7 +171,7 @@ const passkeyClickHandler = async () => {
|
||||
});
|
||||
|
||||
if (finishRes.ok) {
|
||||
handleLoginSuccess(finishRes.data);
|
||||
doLogin(finishRes.data);
|
||||
toast('Welcome, ' + esc(username), 'success');
|
||||
} else {
|
||||
errEl.textContent = finishRes.error || 'Passkey authentication failed';
|
||||
|
||||
Reference in New Issue
Block a user