1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-06 06:02:40 +03:00

Remove the old password change page (#2874)

This commit is contained in:
reivilibre
2024-06-27 13:41:24 +01:00
committed by GitHub
parent aaa7cf3fe9
commit 7c67630c95
7 changed files with 10 additions and 270 deletions

View File

@@ -354,7 +354,7 @@ where
.route(
mas_router::ChangePasswordDiscovery::route(),
get(|State(url_builder): State<UrlBuilder>| async move {
url_builder.redirect(&mas_router::AccountPassword)
url_builder.redirect(&mas_router::AccountPasswordChange)
}),
)
.route(mas_router::Index::route(), get(self::views::index::get))
@@ -371,10 +371,6 @@ where
mas_router::Register::route(),
get(self::views::register::get).post(self::views::register::post),
)
.route(
mas_router::AccountPassword::route(),
get(self::views::account::password::get).post(self::views::account::password::post),
)
.route(
mas_router::AccountVerifyEmail::route(),
get(self::views::account::emails::verify::get)

View File

@@ -13,4 +13,3 @@
// limitations under the License.
pub mod emails;
pub mod password;

View File

@@ -1,198 +0,0 @@
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use anyhow::Context;
use axum::{
extract::{Form, State},
http::StatusCode,
response::{Html, IntoResponse, Response},
};
use mas_axum_utils::{
cookies::CookieJar,
csrf::{CsrfExt, ProtectedForm},
FancyError, SessionInfoExt,
};
use mas_data_model::{BrowserSession, SiteConfig};
use mas_i18n::DataLocale;
use mas_policy::Policy;
use mas_router::UrlBuilder;
use mas_storage::{
user::{BrowserSessionRepository, UserPasswordRepository},
BoxClock, BoxRepository, BoxRng, Clock,
};
use mas_templates::{EmptyContext, TemplateContext, Templates};
use rand::Rng;
use serde::Deserialize;
use zeroize::Zeroizing;
use crate::{passwords::PasswordManager, BoundActivityTracker, PreferredLanguage};
#[derive(Deserialize)]
pub struct ChangeForm {
current_password: String,
new_password: String,
new_password_confirm: String,
}
#[tracing::instrument(name = "handlers.views.account_password.get", skip_all, err)]
pub(crate) async fn get(
mut rng: BoxRng,
clock: BoxClock,
PreferredLanguage(locale): PreferredLanguage,
State(templates): State<Templates>,
State(site_config): State<SiteConfig>,
activity_tracker: BoundActivityTracker,
State(url_builder): State<UrlBuilder>,
mut repo: BoxRepository,
cookie_jar: CookieJar,
) -> Result<Response, FancyError> {
// If the password manager is disabled, we can go back to the account page.
if !site_config.password_change_allowed {
return Ok(url_builder
.redirect(&mas_router::Account::default())
.into_response());
}
let (session_info, cookie_jar) = cookie_jar.session_info();
let maybe_session = session_info.load_session(&mut repo).await?;
if let Some(session) = maybe_session {
activity_tracker
.record_browser_session(&clock, &session)
.await;
render(&mut rng, &clock, locale, templates, session, cookie_jar).await
} else {
let login = mas_router::Login::and_then(mas_router::PostAuthAction::ChangePassword);
Ok((cookie_jar, url_builder.redirect(&login)).into_response())
}
}
async fn render(
rng: impl Rng + Send,
clock: &impl Clock,
locale: DataLocale,
templates: Templates,
session: BrowserSession,
cookie_jar: CookieJar,
) -> Result<Response, FancyError> {
let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng);
let ctx = EmptyContext
.with_session(session)
.with_csrf(csrf_token.form_value())
.with_language(locale);
let content = templates.render_account_password(&ctx)?;
Ok((cookie_jar, Html(content)).into_response())
}
#[tracing::instrument(name = "handlers.views.account_password.post", skip_all, err)]
pub(crate) async fn post(
mut rng: BoxRng,
clock: BoxClock,
PreferredLanguage(locale): PreferredLanguage,
State(password_manager): State<PasswordManager>,
State(site_config): State<SiteConfig>,
State(templates): State<Templates>,
activity_tracker: BoundActivityTracker,
State(url_builder): State<UrlBuilder>,
mut policy: Policy,
mut repo: BoxRepository,
cookie_jar: CookieJar,
Form(form): Form<ProtectedForm<ChangeForm>>,
) -> Result<Response, FancyError> {
if !site_config.password_change_allowed {
// XXX: do something better here
return Ok(StatusCode::METHOD_NOT_ALLOWED.into_response());
}
let form = cookie_jar.verify_form(&clock, form)?;
let (session_info, cookie_jar) = cookie_jar.session_info();
let maybe_session = session_info.load_session(&mut repo).await?;
let Some(session) = maybe_session else {
let login = mas_router::Login::and_then(mas_router::PostAuthAction::ChangePassword);
return Ok((cookie_jar, url_builder.redirect(&login)).into_response());
};
let user_password = repo
.user_password()
.active(&session.user)
.await?
.context("user has no password")?;
let res = policy.evaluate_password(&form.new_password).await?;
// TODO: display nice form errors
if !res.valid() {
return Err(anyhow::anyhow!("Password policy violation: {res}").into());
}
let password = Zeroizing::new(form.current_password.into_bytes());
let new_password = Zeroizing::new(form.new_password.into_bytes());
let new_password_confirm = Zeroizing::new(form.new_password_confirm.into_bytes());
password_manager
.verify(
user_password.version,
password,
user_password.hashed_password,
)
.await?;
// TODO: display nice form errors
if new_password != new_password_confirm {
return Err(anyhow::anyhow!("Password mismatch").into());
}
let (version, hashed_password) = password_manager.hash(&mut rng, new_password).await?;
let user_password = repo
.user_password()
.add(
&mut rng,
&clock,
&session.user,
version,
hashed_password,
None,
)
.await?;
repo.browser_session()
.authenticate_with_password(&mut rng, &clock, &session, &user_password)
.await?;
activity_tracker
.record_browser_session(&clock, &session)
.await;
let reply = render(
&mut rng,
&clock,
locale,
templates.clone(),
session,
cookie_jar,
)
.await?;
repo.save().await?;
Ok(reply)
}

View File

@@ -77,7 +77,7 @@ impl PostAuthAction {
Self::ContinueCompatSsoLogin { id } => {
url_builder.redirect(&CompatLoginSsoComplete::new(*id, None))
}
Self::ChangePassword => url_builder.redirect(&AccountPassword),
Self::ChangePassword => url_builder.redirect(&AccountPasswordChange),
Self::LinkUpstream { id } => url_builder.redirect(&UpstreamOAuth2Link::new(*id)),
Self::ManageAccount { action } => url_builder.redirect(&Account {
action: action.clone(),
@@ -506,12 +506,15 @@ impl SimpleRoute for AccountWildcard {
const PATH: &'static str = "/account/*rest";
}
/// `GET|POST /change-password`
/// `GET /account/password/change`
///
/// Handled by the React frontend; this struct definition is purely for
/// redirects.
#[derive(Default, Debug, Clone)]
pub struct AccountPassword;
pub struct AccountPasswordChange;
impl SimpleRoute for AccountPassword {
const PATH: &'static str = "/change-password";
impl SimpleRoute for AccountPasswordChange {
const PATH: &'static str = "/account/password/change";
}
/// `GET /authorize/:grant_id`

View File

@@ -341,9 +341,6 @@ register_templates! {
/// Render the home page
pub fn render_index(WithLanguage<WithCsrf<WithOptionalSession<IndexContext>>>) { "pages/index.html" }
/// Render the password change page
pub fn render_account_password(WithLanguage<WithCsrf<WithSession<EmptyContext>>>) { "pages/account/password.html" }
/// Render the email verification page
pub fn render_account_verify_email(WithLanguage<WithCsrf<WithSession<EmailVerificationPageContext>>>) { "pages/account/emails/verify.html" }
@@ -404,7 +401,6 @@ impl Templates {
check::render_policy_violation(self, now, rng)?;
check::render_sso_login(self, now, rng)?;
check::render_index(self, now, rng)?;
check::render_account_password(self, now, rng)?;
check::render_account_add_email(self, now, rng)?;
check::render_account_verify_email(self, now, rng)?;
check::render_reauth(self, now, rng)?;