You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Move password change to its own page
Also restructure the templates structure a bit
This commit is contained in:
85
crates/handlers/src/views/account/mod.rs
Normal file
85
crates/handlers/src/views/account/mod.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2021-2022 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.
|
||||||
|
|
||||||
|
mod password;
|
||||||
|
|
||||||
|
use mas_config::{CookiesConfig, CsrfConfig};
|
||||||
|
use mas_data_model::BrowserSession;
|
||||||
|
use mas_storage::{
|
||||||
|
user::{count_active_sessions, get_user_emails},
|
||||||
|
PostgresqlBackend,
|
||||||
|
};
|
||||||
|
use mas_templates::{AccountContext, TemplateContext, Templates};
|
||||||
|
use mas_warp_utils::{
|
||||||
|
errors::WrapError,
|
||||||
|
filters::{
|
||||||
|
cookies::{encrypted_cookie_saver, EncryptedCookieSaver},
|
||||||
|
csrf::updated_csrf_token,
|
||||||
|
database::connection,
|
||||||
|
session::session,
|
||||||
|
with_templates, CsrfToken,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use sqlx::{pool::PoolConnection, PgPool, Postgres};
|
||||||
|
use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply};
|
||||||
|
|
||||||
|
use self::password::filter as password;
|
||||||
|
|
||||||
|
pub(super) fn filter(
|
||||||
|
pool: &PgPool,
|
||||||
|
templates: &Templates,
|
||||||
|
csrf_config: &CsrfConfig,
|
||||||
|
cookies_config: &CookiesConfig,
|
||||||
|
) -> BoxedFilter<(Box<dyn Reply>,)> {
|
||||||
|
let get = warp::get()
|
||||||
|
.and(with_templates(templates))
|
||||||
|
.and(encrypted_cookie_saver(cookies_config))
|
||||||
|
.and(updated_csrf_token(cookies_config, csrf_config))
|
||||||
|
.and(session(pool, cookies_config))
|
||||||
|
.and(connection(pool))
|
||||||
|
.and_then(get);
|
||||||
|
|
||||||
|
let index = warp::path::end().and(get);
|
||||||
|
let password = password(pool, templates, csrf_config, cookies_config);
|
||||||
|
|
||||||
|
let filter = index.or(password).unify();
|
||||||
|
|
||||||
|
warp::path::path("account").and(filter).boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get(
|
||||||
|
templates: Templates,
|
||||||
|
cookie_saver: EncryptedCookieSaver,
|
||||||
|
csrf_token: CsrfToken,
|
||||||
|
session: BrowserSession<PostgresqlBackend>,
|
||||||
|
mut conn: PoolConnection<Postgres>,
|
||||||
|
) -> Result<Box<dyn Reply>, Rejection> {
|
||||||
|
let active_sessions = count_active_sessions(&mut conn, &session.user)
|
||||||
|
.await
|
||||||
|
.wrap_error()?;
|
||||||
|
|
||||||
|
let emails = get_user_emails(&mut conn, &session.user)
|
||||||
|
.await
|
||||||
|
.wrap_error()?;
|
||||||
|
|
||||||
|
let ctx = AccountContext::new(active_sessions, emails)
|
||||||
|
.with_session(session)
|
||||||
|
.with_csrf(csrf_token.form_value());
|
||||||
|
|
||||||
|
let content = templates.render_account_index(&ctx).await?;
|
||||||
|
let reply = html(content);
|
||||||
|
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?;
|
||||||
|
|
||||||
|
Ok(Box::new(reply))
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -16,10 +16,10 @@ use argon2::Argon2;
|
|||||||
use mas_config::{CookiesConfig, CsrfConfig};
|
use mas_config::{CookiesConfig, CsrfConfig};
|
||||||
use mas_data_model::BrowserSession;
|
use mas_data_model::BrowserSession;
|
||||||
use mas_storage::{
|
use mas_storage::{
|
||||||
user::{authenticate_session, count_active_sessions, get_user_emails, set_password},
|
user::{authenticate_session, set_password},
|
||||||
PostgresqlBackend,
|
PostgresqlBackend,
|
||||||
};
|
};
|
||||||
use mas_templates::{AccountContext, TemplateContext, Templates};
|
use mas_templates::{EmptyContext, TemplateContext, Templates};
|
||||||
use mas_warp_utils::{
|
use mas_warp_utils::{
|
||||||
errors::WrapError,
|
errors::WrapError,
|
||||||
filters::{
|
filters::{
|
||||||
@ -44,7 +44,6 @@ pub(super) fn filter(
|
|||||||
.and(encrypted_cookie_saver(cookies_config))
|
.and(encrypted_cookie_saver(cookies_config))
|
||||||
.and(updated_csrf_token(cookies_config, csrf_config))
|
.and(updated_csrf_token(cookies_config, csrf_config))
|
||||||
.and(session(pool, cookies_config))
|
.and(session(pool, cookies_config))
|
||||||
.and(transaction(pool))
|
|
||||||
.and_then(get);
|
.and_then(get);
|
||||||
|
|
||||||
let post = with_templates(templates)
|
let post = with_templates(templates)
|
||||||
@ -55,9 +54,11 @@ pub(super) fn filter(
|
|||||||
.and(protected_form(cookies_config))
|
.and(protected_form(cookies_config))
|
||||||
.and_then(post);
|
.and_then(post);
|
||||||
|
|
||||||
let filter = warp::get().and(get).or(warp::post().and(post)).unify();
|
let get = warp::get().and(get);
|
||||||
|
let post = warp::post().and(post);
|
||||||
|
let filter = get.or(post).unify();
|
||||||
|
|
||||||
warp::path!("account").and(filter).boxed()
|
warp::path!("password").and(filter).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -66,14 +67,14 @@ struct Form {
|
|||||||
new_password: String,
|
new_password: String,
|
||||||
new_password_confirm: String,
|
new_password_confirm: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get(
|
async fn get(
|
||||||
templates: Templates,
|
templates: Templates,
|
||||||
cookie_saver: EncryptedCookieSaver,
|
cookie_saver: EncryptedCookieSaver,
|
||||||
csrf_token: CsrfToken,
|
csrf_token: CsrfToken,
|
||||||
session: BrowserSession<PostgresqlBackend>,
|
session: BrowserSession<PostgresqlBackend>,
|
||||||
txn: Transaction<'_, Postgres>,
|
|
||||||
) -> Result<Box<dyn Reply>, Rejection> {
|
) -> Result<Box<dyn Reply>, Rejection> {
|
||||||
render(templates, cookie_saver, csrf_token, session, txn).await
|
render(templates, cookie_saver, csrf_token, session).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn render(
|
async fn render(
|
||||||
@ -81,23 +82,12 @@ async fn render(
|
|||||||
cookie_saver: EncryptedCookieSaver,
|
cookie_saver: EncryptedCookieSaver,
|
||||||
csrf_token: CsrfToken,
|
csrf_token: CsrfToken,
|
||||||
session: BrowserSession<PostgresqlBackend>,
|
session: BrowserSession<PostgresqlBackend>,
|
||||||
mut txn: Transaction<'_, Postgres>,
|
|
||||||
) -> Result<Box<dyn Reply>, Rejection> {
|
) -> Result<Box<dyn Reply>, Rejection> {
|
||||||
let active_sessions = count_active_sessions(&mut txn, &session.user)
|
let ctx = EmptyContext
|
||||||
.await
|
|
||||||
.wrap_error()?;
|
|
||||||
|
|
||||||
let emails = get_user_emails(&mut txn, &session.user)
|
|
||||||
.await
|
|
||||||
.wrap_error()?;
|
|
||||||
|
|
||||||
txn.commit().await.wrap_error()?;
|
|
||||||
|
|
||||||
let ctx = AccountContext::new(active_sessions, emails)
|
|
||||||
.with_session(session)
|
.with_session(session)
|
||||||
.with_csrf(csrf_token.form_value());
|
.with_csrf(csrf_token.form_value());
|
||||||
|
|
||||||
let content = templates.render_account(&ctx).await?;
|
let content = templates.render_account_password(&ctx).await?;
|
||||||
let reply = html(content);
|
let reply = html(content);
|
||||||
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?;
|
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?;
|
||||||
|
|
||||||
@ -126,7 +116,9 @@ async fn post(
|
|||||||
.await
|
.await
|
||||||
.wrap_error()?;
|
.wrap_error()?;
|
||||||
|
|
||||||
let reply = render(templates, cookie_saver, csrf_token, session, txn).await?;
|
let reply = render(templates, cookie_saver, csrf_token, session).await?;
|
||||||
|
|
||||||
|
txn.commit().await.wrap_error()?;
|
||||||
|
|
||||||
Ok(reply)
|
Ok(reply)
|
||||||
}
|
}
|
@ -285,25 +285,28 @@ register_templates! {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Render the login page
|
/// Render the login page
|
||||||
pub fn render_login(WithCsrf<LoginContext>) { "login.html" }
|
pub fn render_login(WithCsrf<LoginContext>) { "pages/login.html" }
|
||||||
|
|
||||||
/// Render the registration page
|
/// Render the registration page
|
||||||
pub fn render_register(WithCsrf<RegisterContext>) { "register.html" }
|
pub fn render_register(WithCsrf<RegisterContext>) { "pages/register.html" }
|
||||||
|
|
||||||
/// Render the home page
|
/// Render the home page
|
||||||
pub fn render_index(WithCsrf<WithOptionalSession<IndexContext>>) { "index.html" }
|
pub fn render_index(WithCsrf<WithOptionalSession<IndexContext>>) { "pages/index.html" }
|
||||||
|
|
||||||
/// Render the account management page
|
/// Render the account management page
|
||||||
pub fn render_account(WithCsrf<WithSession<AccountContext>>) { "account.html" }
|
pub fn render_account_index(WithCsrf<WithSession<AccountContext>>) { "pages/account/index.html" }
|
||||||
|
|
||||||
|
/// Render the password change page
|
||||||
|
pub fn render_account_password(WithCsrf<WithSession<EmptyContext>>) { "pages/account/password.html" }
|
||||||
|
|
||||||
/// Render the re-authentication form
|
/// Render the re-authentication form
|
||||||
pub fn render_reauth(WithCsrf<WithSession<ReauthContext>>) { "reauth.html" }
|
pub fn render_reauth(WithCsrf<WithSession<ReauthContext>>) { "pages/reauth.html" }
|
||||||
|
|
||||||
/// Render the form used by the form_post response mode
|
/// Render the form used by the form_post response mode
|
||||||
pub fn render_form_post<T: Serialize>(FormPostContext<T>) { "form_post.html" }
|
pub fn render_form_post<T: Serialize>(FormPostContext<T>) { "form_post.html" }
|
||||||
|
|
||||||
/// Render the HTML error page
|
/// Render the HTML error page
|
||||||
pub fn render_error(ErrorContext) { "error.html" }
|
pub fn render_error(ErrorContext) { "pages/error.html" }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Templates {
|
impl Templates {
|
||||||
@ -313,7 +316,8 @@ impl Templates {
|
|||||||
check::render_login(self).await?;
|
check::render_login(self).await?;
|
||||||
check::render_register(self).await?;
|
check::render_register(self).await?;
|
||||||
check::render_index(self).await?;
|
check::render_index(self).await?;
|
||||||
check::render_account(self).await?;
|
check::render_account_index(self).await?;
|
||||||
|
check::render_account_password(self).await?;
|
||||||
check::render_reauth(self).await?;
|
check::render_reauth(self).await?;
|
||||||
check::render_form_post::<EmptyContext>(self).await?;
|
check::render_form_post::<EmptyContext>(self).await?;
|
||||||
check::render_error(self).await?;
|
check::render_error(self).await?;
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
{#
|
|
||||||
Copyright 2021 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.
|
|
||||||
#}
|
|
||||||
|
|
||||||
{% if code %}
|
|
||||||
{{- code }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{%- if description %}
|
|
||||||
{{ description }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{%- if details %}
|
|
||||||
{{ details }}
|
|
||||||
{% endif %}
|
|
@ -1,5 +1,5 @@
|
|||||||
{#
|
{#
|
||||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
Copyright 2021-2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -30,15 +30,8 @@ limitations under the License.
|
|||||||
<div class="font-bold">Primary email</div>
|
<div class="font-bold">Primary email</div>
|
||||||
<div>{{ current_session.user.primary_email.email }}</div>
|
<div>{{ current_session.user.primary_email.email }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{{ button::link_ghost(text="Change password", href="/account/password", class="col-span-2 place-self-end") }}
|
||||||
</div>
|
</div>
|
||||||
<form class="rounded border-2 border-grey-50 dark:border-grey-450 p-4 grid gap-4 xl:grid-cols-2 grid-cols-1 place-content-start" method="POST">
|
|
||||||
<h2 class="text-xl font-bold xl:col-span-2">Change my password</h2>
|
|
||||||
<input type="hidden" name="csrf" value="{{ csrf_token }}" />
|
|
||||||
{{ field::input(label="Current password", name="current_password", type="password", class="xl:col-span-2") }}
|
|
||||||
{{ field::input(label="New password", name="new_password", type="password") }}
|
|
||||||
{{ field::input(label="Confirm password", name="new_password_confirm", type="password") }}
|
|
||||||
{{ button::button(text="Change password", type="password", class="xl:col-span-2 place-self-end") }}
|
|
||||||
</form>
|
|
||||||
<div class="rounded border-2 border-grey-50 dark:border-grey-450 p-4 grid gap-4 xl:grid-cols-2 grid-cols-1 place-content-start">
|
<div class="rounded border-2 border-grey-50 dark:border-grey-450 p-4 grid gap-4 xl:grid-cols-2 grid-cols-1 place-content-start">
|
||||||
<h2 class="text-xl font-bold xl:col-span-2">Current session</h2>
|
<h2 class="text-xl font-bold xl:col-span-2">Current session</h2>
|
||||||
<div class="font-bold">Started at</div>
|
<div class="font-bold">Started at</div>
|
31
crates/templates/src/res/pages/account/password.html
Normal file
31
crates/templates/src/res/pages/account/password.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{#
|
||||||
|
Copyright 2022 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.
|
||||||
|
#}
|
||||||
|
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="container mx-auto grid gap-4 grid-cols-1 md:grid-cols-2 xl:grid-cols-3 p-2">
|
||||||
|
<form class="rounded border-2 border-grey-50 dark:border-grey-450 p-4 grid gap-4 xl:grid-cols-2 grid-cols-1 place-content-start" method="POST">
|
||||||
|
<h2 class="text-xl font-bold xl:col-span-2">Change my password</h2>
|
||||||
|
<input type="hidden" name="csrf" value="{{ csrf_token }}" />
|
||||||
|
{{ field::input(label="Current password", name="current_password", type="password", class="xl:col-span-2") }}
|
||||||
|
{{ field::input(label="New password", name="new_password", type="password") }}
|
||||||
|
{{ field::input(label="Confirm password", name="new_password_confirm", type="password") }}
|
||||||
|
{{ button::button(text="Change password", type="password", class="xl:col-span-2 place-self-end") }}
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
{% endblock content %}
|
||||||
|
|
Reference in New Issue
Block a user