From c9cc9bc0cb03ce6471804f0e66967d94978898ee Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 9 Nov 2026 11:59:44 +0000 Subject: dashboard: going to another node's dashboard without its login page in between Going to another member's dashboard showed its login page for a moment: a browser without a session there was sent from `/admin/dashboard` to `/login` (by `auth::basic_auth`), which began a session with the token handed over and went on to the dashboard. Now the dashboard's page is served without authentication, as the login page is (it holds nothing: what it shows it reads with the browser's session). Opened with a token handed over, the page begins the session with it (`POST /auth/session`) before it reads anything; without a session, `obtainTokens` goes to the login page, as the redirect did. A request without credentials is refused at once rather than after the 1.5 s that slow down guessing passwords: nothing is guessed there, and a page without a session goes to the login page without waiting twice for it. --- src/api/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src/api/mod.rs') diff --git a/src/api/mod.rs b/src/api/mod.rs index 437f932..6631bc9 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -137,8 +137,10 @@ pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) -> .route("/auth/challenge", axum::routing::post(login::challenge)) .route("/auth/login/key", axum::routing::post(login::login_key)) .route("/health", get(health::node_health)) - // To log in to the dashboard on, without authentication. + // To log in to the dashboard on, and the dashboard's page, without authentication + // (they hold nothing). .route("/login", get(dashboard_login)) + .route("/admin/dashboard", get(dashboard_page)) .route("/ready", get(health::ready)) // Outermost, so authentication failures get the error body too. .layer(middleware::from_fn(json_errors)) @@ -283,6 +285,17 @@ async fn json_errors(request: Request, next: Next) -> Response { } /// `GET /login` (`dashboard::login_page`); without the dashboard, none. +async fn dashboard_page() -> Response { + #[cfg(feature = "dashboard")] + { + dashboard::page_html().await + } + #[cfg(not(feature = "dashboard"))] + { + StatusCode::NOT_FOUND.into_response() + } +} + async fn dashboard_login() -> Response { #[cfg(feature = "dashboard")] { -- cgit v1.3.1