From e22016f85cf1df237d3c6a1a4a41f5b40538e796 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 11 Apr 2025 13:35:59 +0200 Subject: [PATCH] Remove the reauth view --- crates/handlers/src/lib.rs | 4 - crates/handlers/src/views/mod.rs | 1 - crates/handlers/src/views/reauth.rs | 189 ---------------------------- crates/router/src/endpoints.rs | 60 --------- crates/templates/src/context.rs | 57 +-------- crates/templates/src/lib.rs | 12 +- 6 files changed, 6 insertions(+), 317 deletions(-) delete mode 100644 crates/handlers/src/views/reauth.rs diff --git a/crates/handlers/src/lib.rs b/crates/handlers/src/lib.rs index 3b7f15c02..cbf12ad50 100644 --- a/crates/handlers/src/lib.rs +++ b/crates/handlers/src/lib.rs @@ -371,10 +371,6 @@ where get(self::views::login::get).post(self::views::login::post), ) .route(mas_router::Logout::route(), post(self::views::logout::post)) - .route( - mas_router::Reauth::route(), - get(self::views::reauth::get).post(self::views::reauth::post), - ) .route( mas_router::Register::route(), get(self::views::register::get), diff --git a/crates/handlers/src/views/mod.rs b/crates/handlers/src/views/mod.rs index 336ec9f2f..5d5c615e8 100644 --- a/crates/handlers/src/views/mod.rs +++ b/crates/handlers/src/views/mod.rs @@ -8,7 +8,6 @@ pub mod app; pub mod index; pub mod login; pub mod logout; -pub mod reauth; pub mod recovery; pub mod register; pub mod shared; diff --git a/crates/handlers/src/views/reauth.rs b/crates/handlers/src/views/reauth.rs deleted file mode 100644 index d7f238c71..000000000 --- a/crates/handlers/src/views/reauth.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2024 New Vector Ltd. -// Copyright 2021-2024 The Matrix.org Foundation C.I.C. -// -// SPDX-License-Identifier: AGPL-3.0-only -// Please see LICENSE in the repository root for full details. - -use anyhow::Context; -use axum::{ - extract::{Form, Query, State}, - response::{Html, IntoResponse, Response}, -}; -use hyper::StatusCode; -use mas_axum_utils::{ - FancyError, SessionInfoExt, - cookies::CookieJar, - csrf::{CsrfExt, ProtectedForm}, -}; -use mas_router::UrlBuilder; -use mas_storage::{ - BoxClock, BoxRepository, BoxRng, - user::{BrowserSessionRepository, UserPasswordRepository}, -}; -use mas_templates::{ReauthContext, TemplateContext, Templates}; -use serde::Deserialize; -use zeroize::Zeroizing; - -use super::shared::OptionalPostAuthAction; -use crate::{ - BoundActivityTracker, PreferredLanguage, SiteConfig, - passwords::PasswordManager, - session::{SessionOrFallback, load_session_or_fallback}, -}; - -#[derive(Deserialize, Debug)] -pub(crate) struct ReauthForm { - password: String, -} - -#[tracing::instrument(name = "handlers.views.reauth.get", skip_all, err)] -pub(crate) async fn get( - mut rng: BoxRng, - clock: BoxClock, - PreferredLanguage(locale): PreferredLanguage, - State(templates): State, - State(url_builder): State, - State(site_config): State, - activity_tracker: BoundActivityTracker, - mut repo: BoxRepository, - Query(query): Query, - cookie_jar: CookieJar, -) -> Result { - if !site_config.password_login_enabled { - // XXX: do something better here - return Ok(url_builder - .redirect(&mas_router::Account::default()) - .into_response()); - } - - let (cookie_jar, maybe_session) = match load_session_or_fallback( - cookie_jar, &clock, &mut rng, &templates, &locale, &mut repo, - ) - .await? - { - SessionOrFallback::MaybeSession { - cookie_jar, - maybe_session, - .. - } => (cookie_jar, maybe_session), - SessionOrFallback::Fallback { response } => return Ok(response), - }; - - let Some(session) = maybe_session else { - // If there is no session, redirect to the login screen, keeping the - // PostAuthAction - let login = mas_router::Login::from(query.post_auth_action); - return Ok((cookie_jar, url_builder.redirect(&login)).into_response()); - }; - - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); - - activity_tracker - .record_browser_session(&clock, &session) - .await; - - let ctx = ReauthContext::default(); - let next = query.load_context(&mut repo).await?; - let ctx = if let Some(next) = next { - ctx.with_post_action(next) - } else { - ctx - }; - let ctx = ctx - .with_session(session) - .with_csrf(csrf_token.form_value()) - .with_language(locale); - - let content = templates.render_reauth(&ctx)?; - - Ok((cookie_jar, Html(content)).into_response()) -} - -#[tracing::instrument(name = "handlers.views.reauth.post", skip_all, err)] -pub(crate) async fn post( - mut rng: BoxRng, - clock: BoxClock, - PreferredLanguage(locale): PreferredLanguage, - State(templates): State, - State(password_manager): State, - State(url_builder): State, - State(site_config): State, - mut repo: BoxRepository, - Query(query): Query, - cookie_jar: CookieJar, - Form(form): Form>, -) -> Result { - if !site_config.password_login_enabled { - // XXX: do something better here - return Ok(StatusCode::METHOD_NOT_ALLOWED.into_response()); - } - - let form = cookie_jar.verify_form(&clock, form)?; - - let (cookie_jar, maybe_session) = match load_session_or_fallback( - cookie_jar, &clock, &mut rng, &templates, &locale, &mut repo, - ) - .await? - { - SessionOrFallback::MaybeSession { - cookie_jar, - maybe_session, - .. - } => (cookie_jar, maybe_session), - SessionOrFallback::Fallback { response } => return Ok(response), - }; - - let Some(session) = maybe_session else { - // If there is no session, redirect to the login screen, keeping the - // PostAuthAction - let login = mas_router::Login::from(query.post_auth_action); - return Ok((cookie_jar, url_builder.redirect(&login)).into_response()); - }; - - // Load the user password - let user_password = repo - .user_password() - .active(&session.user) - .await? - .context("User has no password")?; - - let password = Zeroizing::new(form.password.as_bytes().to_vec()); - - // TODO: recover from errors - // Verify the password, and upgrade it on-the-fly if needed - let new_password_hash = password_manager - .verify_and_upgrade( - &mut rng, - user_password.version, - password, - user_password.hashed_password.clone(), - ) - .await?; - - let user_password = if let Some((version, new_password_hash)) = new_password_hash { - // Save the upgraded password - repo.user_password() - .add( - &mut rng, - &clock, - &session.user, - version, - new_password_hash, - Some(&user_password), - ) - .await? - } else { - user_password - }; - - // Mark the session as authenticated by the password - repo.browser_session() - .authenticate_with_password(&mut rng, &clock, &session, &user_password) - .await?; - - let cookie_jar = cookie_jar.set_session(&session); - repo.save().await?; - - let reply = query.go_next(&url_builder); - Ok((cookie_jar, reply).into_response()) -} diff --git a/crates/router/src/endpoints.rs b/crates/router/src/endpoints.rs index 059dda31e..ceead6d12 100644 --- a/crates/router/src/endpoints.rs +++ b/crates/router/src/endpoints.rs @@ -255,66 +255,6 @@ impl SimpleRoute for Logout { const PATH: &'static str = "/logout"; } -/// `GET|POST /reauth` -#[derive(Default, Debug, Clone)] -pub struct Reauth { - post_auth_action: Option, -} - -impl Reauth { - #[must_use] - pub fn and_then(action: PostAuthAction) -> Self { - Self { - post_auth_action: Some(action), - } - } - - #[must_use] - pub fn and_continue_grant(data: Ulid) -> Self { - Self { - post_auth_action: Some(PostAuthAction::continue_grant(data)), - } - } - - #[must_use] - pub fn and_continue_device_code_grant(data: Ulid) -> Self { - Self { - post_auth_action: Some(PostAuthAction::continue_device_code_grant(data)), - } - } - - /// Get a reference to the reauth's post auth action. - #[must_use] - pub fn post_auth_action(&self) -> Option<&PostAuthAction> { - self.post_auth_action.as_ref() - } - - pub fn go_next(&self, url_builder: &UrlBuilder) -> axum::response::Redirect { - match &self.post_auth_action { - Some(action) => action.go_next(url_builder), - None => url_builder.redirect(&Index), - } - } -} - -impl Route for Reauth { - type Query = PostAuthAction; - - fn route() -> &'static str { - "/reauth" - } - - fn query(&self) -> Option<&Self::Query> { - self.post_auth_action.as_ref() - } -} - -impl From> for Reauth { - fn from(post_auth_action: Option) -> Self { - Self { post_auth_action } - } -} - /// `POST /register` #[derive(Default, Debug, Clone)] pub struct Register { diff --git a/crates/templates/src/context.rs b/crates/templates/src/context.rs index 26ed200e1..b6661d540 100644 --- a/crates/templates/src/context.rs +++ b/crates/templates/src/context.rs @@ -381,7 +381,7 @@ impl FormField for LoginFormField { } } -/// Inner context used in login and reauth screens. See [`PostAuthContext`]. +/// Inner context used in login screen. See [`PostAuthContext`]. #[derive(Serialize)] #[serde(tag = "kind", rename_all = "snake_case")] pub enum PostAuthContextInner { @@ -420,7 +420,7 @@ pub enum PostAuthContextInner { ManageAccount, } -/// Context used in login and reauth screens, for the post-auth action to do +/// Context used in login screen, for the post-auth action to do #[derive(Serialize)] pub struct PostAuthContext { /// The post auth action params from the URL @@ -734,59 +734,6 @@ impl PolicyViolationContext { } } -/// Fields of the reauthentication form -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -pub enum ReauthFormField { - /// The password field - Password, -} - -impl FormField for ReauthFormField { - fn keep(&self) -> bool { - match self { - Self::Password => false, - } - } -} - -/// Context used by the `reauth.html` template -#[derive(Serialize, Default)] -pub struct ReauthContext { - form: FormState, - next: Option, -} - -impl TemplateContext for ReauthContext { - fn sample(_now: chrono::DateTime, _rng: &mut impl Rng) -> Vec - where - Self: Sized, - { - // TODO: samples with errors - vec![ReauthContext { - form: FormState::default(), - next: None, - }] - } -} - -impl ReauthContext { - /// Add an error on the reauthentication form - #[must_use] - pub fn with_form_state(self, form: FormState) -> Self { - Self { form, ..self } - } - - /// Add a post authentication action to the context - #[must_use] - pub fn with_post_action(self, next: PostAuthContext) -> Self { - Self { - next: Some(next), - ..self - } - } -} - /// Context used by the `sso.html` template #[derive(Serialize)] pub struct CompatSsoContext { diff --git a/crates/templates/src/lib.rs b/crates/templates/src/lib.rs index 982b3fc02..05422359d 100644 --- a/crates/templates/src/lib.rs +++ b/crates/templates/src/lib.rs @@ -38,10 +38,10 @@ pub use self::{ DeviceConsentContext, DeviceLinkContext, DeviceLinkFormField, EmailRecoveryContext, EmailVerificationContext, EmptyContext, ErrorContext, FormPostContext, IndexContext, LoginContext, LoginFormField, NotFoundContext, PasswordRegisterContext, - PolicyViolationContext, PostAuthContext, PostAuthContextInner, ReauthContext, - ReauthFormField, RecoveryExpiredContext, RecoveryFinishContext, RecoveryFinishFormField, - RecoveryProgressContext, RecoveryStartContext, RecoveryStartFormField, RegisterContext, - RegisterFormField, RegisterStepsDisplayNameContext, RegisterStepsDisplayNameFormField, + PolicyViolationContext, PostAuthContext, PostAuthContextInner, RecoveryExpiredContext, + RecoveryFinishContext, RecoveryFinishFormField, RecoveryProgressContext, + RecoveryStartContext, RecoveryStartFormField, RegisterContext, RegisterFormField, + RegisterStepsDisplayNameContext, RegisterStepsDisplayNameFormField, RegisterStepsEmailInUseContext, RegisterStepsVerifyEmailContext, RegisterStepsVerifyEmailFormField, SiteBranding, SiteConfigExt, SiteFeatures, TemplateContext, UpstreamExistingLinkContext, UpstreamRegister, UpstreamRegisterFormField, @@ -372,9 +372,6 @@ register_templates! { /// Render the account recovery disabled page pub fn render_recovery_disabled(WithLanguage) { "pages/recovery/disabled.html" } - /// Render the re-authentication form - pub fn render_reauth(WithLanguage>>) { "pages/reauth.html" } - /// Render the form used by the form_post response mode pub fn render_form_post(WithLanguage>) { "form_post.html" } @@ -456,7 +453,6 @@ impl Templates { check::render_recovery_expired(self, now, rng)?; check::render_recovery_consumed(self, now, rng)?; check::render_recovery_disabled(self, now, rng)?; - check::render_reauth(self, now, rng)?; check::render_form_post::(self, now, rng)?; check::render_error(self, now, rng)?; check::render_email_verification_txt(self, now, rng)?;