1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

Axum migration: /account/* routes

This commit is contained in:
Quentin Gliech
2022-03-28 17:04:40 +02:00
parent b4d0906e75
commit 9cb5650167
9 changed files with 233 additions and 261 deletions

View File

@@ -114,7 +114,10 @@ pub trait CsrfExt {
impl<K> CsrfExt for PrivateCookieJar<K> { impl<K> CsrfExt for PrivateCookieJar<K> {
fn csrf_token(self) -> (CsrfToken, Self) { fn csrf_token(self) -> (CsrfToken, Self) {
let jar = self; let jar = self;
let cookie = jar.get("csrf").unwrap_or_else(|| Cookie::new("csrf", "")); let mut cookie = jar.get("csrf").unwrap_or_else(|| Cookie::new("csrf", ""));
cookie.set_path("/");
cookie.set_http_only(true);
let new_token = cookie let new_token = cookie
.decode() .decode()
.ok() .ok()

View File

@@ -76,9 +76,11 @@ pub trait SessionInfoExt {
impl<K> SessionInfoExt for PrivateCookieJar<K> { impl<K> SessionInfoExt for PrivateCookieJar<K> {
fn session_info(self) -> (SessionInfo, Self) { fn session_info(self) -> (SessionInfo, Self) {
let jar = self; let jar = self;
let cookie = jar let mut cookie = jar
.get("session") .get("session")
.unwrap_or_else(|| Cookie::new("session", "")); .unwrap_or_else(|| Cookie::new("session", ""));
cookie.set_path("/");
cookie.set_http_only(true);
let session_info = cookie.decode().unwrap_or_default(); let session_info = cookie.decode().unwrap_or_default();
let cookie = cookie.encode(&session_info); let cookie = cookie.encode(&session_info);

View File

@@ -39,7 +39,7 @@ mod health;
mod oauth2; mod oauth2;
mod views; mod views;
use self::{oauth2::filter as oauth2, views::filter as views}; use self::oauth2::filter as oauth2;
#[must_use] #[must_use]
pub fn root( pub fn root(
@@ -47,20 +47,11 @@ pub fn root(
templates: &Templates, templates: &Templates,
key_store: &Arc<StaticKeystore>, key_store: &Arc<StaticKeystore>,
encrypter: &Encrypter, encrypter: &Encrypter,
mailer: &Mailer,
config: &RootConfig, config: &RootConfig,
) -> BoxedFilter<(impl Reply,)> { ) -> BoxedFilter<(impl Reply,)> {
let oauth2 = oauth2(pool, templates, key_store, encrypter, &config.http); let oauth2 = oauth2(pool, templates, key_store, encrypter, &config.http);
let views = views(
pool,
templates,
mailer,
encrypter,
&config.http,
&config.csrf,
);
let filter = views.or(oauth2); let filter = oauth2;
filter.with(warp::log(module_path!())).boxed() filter.with(warp::log(module_path!())).boxed()
} }
@@ -96,6 +87,15 @@ where
get(self::views::register::get).post(self::views::register::post), get(self::views::register::get).post(self::views::register::post),
) )
.route("/verify/:code", get(self::views::verify::get)) .route("/verify/:code", get(self::views::verify::get))
.route("/account", get(self::views::account::get))
.route(
"/account/password",
get(self::views::account::password::get).post(self::views::account::password::post),
)
.route(
"/account/emails",
get(self::views::account::emails::get).post(self::views::account::emails::post),
)
.fallback(mas_static_files::Assets) .fallback(mas_static_files::Assets)
.layer(Extension(pool.clone())) .layer(Extension(pool.clone()))
.layer(Extension(templates.clone())) .layer(Extension(templates.clone()))

View File

@@ -12,8 +12,16 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use axum::{
extract::{Extension, Form},
response::{Html, IntoResponse, Redirect, Response},
};
use lettre::{message::Mailbox, Address}; use lettre::{message::Mailbox, Address};
use mas_config::{CsrfConfig, Encrypter, HttpConfig}; use mas_axum_utils::{
csrf::{CsrfExt, ProtectedForm},
fancy_error, FancyError, PrivateCookieJar, SessionInfoExt, UrlBuilder,
};
use mas_config::Encrypter;
use mas_data_model::{BrowserSession, User, UserEmail}; use mas_data_model::{BrowserSession, User, UserEmail};
use mas_email::Mailer; use mas_email::Mailer;
use mas_storage::{ use mas_storage::{
@@ -24,99 +32,70 @@ use mas_storage::{
PostgresqlBackend, PostgresqlBackend,
}; };
use mas_templates::{AccountEmailsContext, EmailVerificationContext, TemplateContext, Templates}; use mas_templates::{AccountEmailsContext, EmailVerificationContext, TemplateContext, Templates};
use mas_warp_utils::{
errors::WrapError,
filters::{
self,
cookies::{encrypted_cookie_saver, EncryptedCookieSaver},
csrf::{protected_form, updated_csrf_token},
database::{connection, transaction},
session::session,
url_builder::{url_builder, UrlBuilder},
with_templates, CsrfToken,
},
};
use rand::{distributions::Alphanumeric, thread_rng, Rng}; use rand::{distributions::Alphanumeric, thread_rng, Rng};
use serde::Deserialize; use serde::Deserialize;
use sqlx::{pool::PoolConnection, PgExecutor, PgPool, Postgres, Transaction}; use sqlx::{PgExecutor, PgPool};
use tracing::info; use tracing::info;
use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply};
pub(super) fn filter( use crate::views::LoginRequest;
pool: &PgPool,
templates: &Templates,
mailer: &Mailer,
encrypter: &Encrypter,
http_config: &HttpConfig,
csrf_config: &CsrfConfig,
) -> BoxedFilter<(Box<dyn Reply>,)> {
let mailer = mailer.clone();
let get = with_templates(templates)
.and(filters::trace::name("GET /account/emails"))
.and(encrypted_cookie_saver(encrypter))
.and(updated_csrf_token(encrypter, csrf_config))
.and(session(pool, encrypter))
.and(connection(pool))
.and_then(get);
let post = with_templates(templates)
.and(filters::trace::name("POST /account/emails"))
.and(warp::any().map(move || mailer.clone()))
.and(url_builder(http_config))
.and(encrypted_cookie_saver(encrypter))
.and(updated_csrf_token(encrypter, csrf_config))
.and(session(pool, encrypter))
.and(transaction(pool))
.and(protected_form(encrypter))
.and_then(post);
let get = warp::get().and(get);
let post = warp::post().and(post);
let filter = get.or(post).unify();
warp::path!("emails").and(filter).boxed()
}
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
#[serde(tag = "action", rename_all = "snake_case")] #[serde(tag = "action", rename_all = "snake_case")]
enum Form { pub enum ManagementForm {
Add { email: String }, Add { email: String },
ResendConfirmation { data: String }, ResendConfirmation { data: String },
SetPrimary { data: String }, SetPrimary { data: String },
Remove { data: String }, Remove { data: String },
} }
async fn get( pub(crate) async fn get(
templates: Templates, Extension(templates): Extension<Templates>,
cookie_saver: EncryptedCookieSaver, Extension(pool): Extension<PgPool>,
csrf_token: CsrfToken, cookie_jar: PrivateCookieJar<Encrypter>,
session: BrowserSession<PostgresqlBackend>, ) -> Result<Response, FancyError> {
mut conn: PoolConnection<Postgres>, let mut conn = pool
) -> Result<Box<dyn Reply>, Rejection> { .acquire()
render(templates, cookie_saver, csrf_token, session, &mut conn).await .await
.map_err(fancy_error(templates.clone()))?;
let (session_info, cookie_jar) = cookie_jar.session_info();
let maybe_session = session_info
.load_session(&mut conn)
.await
.map_err(fancy_error(templates.clone()))?;
if let Some(session) = maybe_session {
render(templates, session, cookie_jar, &mut conn).await
} else {
let login = LoginRequest::default();
let login = login.build_uri().map_err(fancy_error(templates.clone()))?;
Ok((cookie_jar.headers(), Redirect::to(login)).into_response())
}
} }
async fn render( async fn render(
templates: Templates, templates: Templates,
cookie_saver: EncryptedCookieSaver,
csrf_token: CsrfToken,
session: BrowserSession<PostgresqlBackend>, session: BrowserSession<PostgresqlBackend>,
cookie_jar: PrivateCookieJar<Encrypter>,
executor: impl PgExecutor<'_>, executor: impl PgExecutor<'_>,
) -> Result<Box<dyn Reply>, Rejection> { ) -> Result<Response, FancyError> {
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
let emails = get_user_emails(executor, &session.user) let emails = get_user_emails(executor, &session.user)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
let ctx = AccountEmailsContext::new(emails) let ctx = AccountEmailsContext::new(emails)
.with_session(session) .with_session(session)
.with_csrf(csrf_token.form_value()); .with_csrf(csrf_token.form_value());
let content = templates.render_account_emails(&ctx).await?; let content = templates
let reply = html(content); .render_account_emails(&ctx)
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?; .await
.map_err(fancy_error(templates))?;
Ok(Box::new(reply)) Ok((cookie_jar.headers(), Html(content)).into_response())
} }
async fn start_email_verification( async fn start_email_verification(
@@ -150,59 +129,80 @@ async fn start_email_verification(
Ok(()) Ok(())
} }
#[allow(clippy::too_many_arguments)] pub(crate) async fn post(
async fn post( Extension(templates): Extension<Templates>,
templates: Templates, Extension(pool): Extension<PgPool>,
mailer: Mailer, Extension(url_builder): Extension<UrlBuilder>,
url_builder: UrlBuilder, Extension(mailer): Extension<Mailer>,
cookie_saver: EncryptedCookieSaver, cookie_jar: PrivateCookieJar<Encrypter>,
csrf_token: CsrfToken, Form(form): Form<ProtectedForm<ManagementForm>>,
mut session: BrowserSession<PostgresqlBackend>, ) -> Result<Response, FancyError> {
mut txn: Transaction<'_, Postgres>, let mut txn = pool.begin().await.map_err(fancy_error(templates.clone()))?;
form: Form,
) -> Result<Box<dyn Reply>, Rejection> { let (session_info, cookie_jar) = cookie_jar.session_info();
let maybe_session = session_info
.load_session(&mut txn)
.await
.map_err(fancy_error(templates.clone()))?;
let mut session = if let Some(session) = maybe_session {
session
} else {
let login = LoginRequest::default();
let login = login.build_uri().map_err(fancy_error(templates.clone()))?;
return Ok((cookie_jar.headers(), Redirect::to(login)).into_response());
};
let form = cookie_jar
.verify_form(form)
.map_err(fancy_error(templates.clone()))?;
match form { match form {
Form::Add { email } => { ManagementForm::Add { email } => {
let user_email = add_user_email(&mut txn, &session.user, email) let user_email = add_user_email(&mut txn, &session.user, email)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
start_email_verification(&mailer, &url_builder, &mut txn, &session.user, &user_email) start_email_verification(&mailer, &url_builder, &mut txn, &session.user, &user_email)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
} }
Form::Remove { data } => { ManagementForm::Remove { data } => {
let id = data.parse().wrap_error()?; let id = data.parse().map_err(fancy_error(templates.clone()))?;
let email = get_user_email(&mut txn, &session.user, id) let email = get_user_email(&mut txn, &session.user, id)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
remove_user_email(&mut txn, email).await.wrap_error()?; remove_user_email(&mut txn, email)
.await
.map_err(fancy_error(templates.clone()))?;
} }
Form::ResendConfirmation { data } => { ManagementForm::ResendConfirmation { data } => {
let id: i64 = data.parse().wrap_error()?; let id = data.parse().map_err(fancy_error(templates.clone()))?;
let user_email = get_user_email(&mut txn, &session.user, id) let user_email = get_user_email(&mut txn, &session.user, id)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
start_email_verification(&mailer, &url_builder, &mut txn, &session.user, &user_email) start_email_verification(&mailer, &url_builder, &mut txn, &session.user, &user_email)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
} }
Form::SetPrimary { data } => { ManagementForm::SetPrimary { data } => {
let id = data.parse().wrap_error()?; let id = data.parse().map_err(fancy_error(templates.clone()))?;
let email = get_user_email(&mut txn, &session.user, id) let email = get_user_email(&mut txn, &session.user, id)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
set_user_email_as_primary(&mut txn, &email) set_user_email_as_primary(&mut txn, &email)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
session.user.primary_email = Some(email); session.user.primary_email = Some(email);
} }
}; };
let reply = render(templates, cookie_saver, csrf_token, session, &mut txn).await?; let reply = render(templates.clone(), session, cookie_jar, &mut txn).await?;
txn.commit().await.wrap_error()?; txn.commit().await.map_err(fancy_error(templates.clone()))?;
Ok(reply) Ok(reply)
} }

View File

@@ -1,4 +1,4 @@
// Copyright 2021-2022 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.
@@ -12,81 +12,63 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
mod emails; pub mod emails;
mod password; pub mod password;
use mas_config::{CsrfConfig, Encrypter, HttpConfig}; use axum::{
use mas_data_model::BrowserSession; extract::Extension,
use mas_email::Mailer; response::{Html, IntoResponse, Redirect, Response},
use mas_storage::{
user::{count_active_sessions, get_user_emails},
PostgresqlBackend,
}; };
use mas_axum_utils::{csrf::CsrfExt, fancy_error, FancyError, PrivateCookieJar, SessionInfoExt};
use mas_config::Encrypter;
use mas_storage::user::{count_active_sessions, get_user_emails};
use mas_templates::{AccountContext, TemplateContext, Templates}; use mas_templates::{AccountContext, TemplateContext, Templates};
use mas_warp_utils::{ use sqlx::PgPool;
errors::WrapError,
filters::{ use super::LoginRequest;
self,
cookies::{encrypted_cookie_saver, EncryptedCookieSaver}, pub(crate) async fn get(
csrf::updated_csrf_token, Extension(templates): Extension<Templates>,
database::connection, Extension(pool): Extension<PgPool>,
session::session, cookie_jar: PrivateCookieJar<Encrypter>,
with_templates, CsrfToken, ) -> Result<Response, FancyError> {
}, let mut conn = pool
.acquire()
.await
.map_err(fancy_error(templates.clone()))?;
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
let (session_info, cookie_jar) = cookie_jar.session_info();
let maybe_session = session_info
.load_session(&mut conn)
.await
.map_err(fancy_error(templates.clone()))?;
let session = if let Some(session) = maybe_session {
session
} else {
let login = LoginRequest::default();
let login = login.build_uri().map_err(fancy_error(templates.clone()))?;
return Ok((cookie_jar.headers(), Redirect::to(login)).into_response());
}; };
use sqlx::{pool::PoolConnection, PgPool, Postgres};
use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply};
use self::{emails::filter as emails, password::filter as password};
pub(super) fn filter(
pool: &PgPool,
templates: &Templates,
mailer: &Mailer,
encrypter: &Encrypter,
http_config: &HttpConfig,
csrf_config: &CsrfConfig,
) -> BoxedFilter<(Box<dyn Reply>,)> {
let get = warp::get()
.and(filters::trace::name("GET /account"))
.and(with_templates(templates))
.and(encrypted_cookie_saver(encrypter))
.and(updated_csrf_token(encrypter, csrf_config))
.and(session(pool, encrypter))
.and(connection(pool))
.and_then(get);
let index = warp::path::end().and(get);
let password = password(pool, templates, encrypter, csrf_config);
let emails = emails(pool, templates, mailer, encrypter, http_config, csrf_config);
let filter = index.or(password).unify().or(emails).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) let active_sessions = count_active_sessions(&mut conn, &session.user)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
let emails = get_user_emails(&mut conn, &session.user) let emails = get_user_emails(&mut conn, &session.user)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
let ctx = AccountContext::new(active_sessions, emails) 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_index(&ctx).await?; let content = templates
let reply = html(content); .render_account_index(&ctx)
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?; .await
.map_err(fancy_error(templates.clone()))?;
Ok(Box::new(reply)) Ok((cookie_jar.headers(), Html(content)).into_response())
} }

View File

@@ -13,117 +13,122 @@
// limitations under the License. // limitations under the License.
use argon2::Argon2; use argon2::Argon2;
use mas_config::{CsrfConfig, Encrypter}; use axum::{
extract::{Extension, Form},
response::{Html, IntoResponse, Redirect, Response},
};
use mas_axum_utils::{
csrf::{CsrfExt, ProtectedForm},
fancy_error, FancyError, PrivateCookieJar, SessionInfoExt,
};
use mas_config::Encrypter;
use mas_data_model::BrowserSession; use mas_data_model::BrowserSession;
use mas_storage::{ use mas_storage::{
user::{authenticate_session, set_password}, user::{authenticate_session, set_password},
PostgresqlBackend, PostgresqlBackend,
}; };
use mas_templates::{EmptyContext, TemplateContext, Templates}; use mas_templates::{EmptyContext, TemplateContext, Templates};
use mas_warp_utils::{
errors::WrapError,
filters::{
self,
cookies::{encrypted_cookie_saver, EncryptedCookieSaver},
csrf::{protected_form, updated_csrf_token},
database::transaction,
session::session,
with_templates, CsrfToken,
},
};
use serde::Deserialize; use serde::Deserialize;
use sqlx::{PgPool, Postgres, Transaction}; use sqlx::PgPool;
use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply};
pub(super) fn filter( use crate::views::LoginRequest;
pool: &PgPool,
templates: &Templates,
encrypter: &Encrypter,
csrf_config: &CsrfConfig,
) -> BoxedFilter<(Box<dyn Reply>,)> {
let get = with_templates(templates)
.and(encrypted_cookie_saver(encrypter))
.and(updated_csrf_token(encrypter, csrf_config))
.and(session(pool, encrypter))
.and_then(get);
let post = with_templates(templates)
.and(encrypted_cookie_saver(encrypter))
.and(updated_csrf_token(encrypter, csrf_config))
.and(session(pool, encrypter))
.and(transaction(pool))
.and(protected_form(encrypter))
.and_then(post);
let get = warp::get()
.and(get)
.and(filters::trace::name("GET /account/passwords"));
let post = warp::post()
.and(post)
.and(filters::trace::name("POST /account/passwords"));
let filter = get.or(post).unify();
warp::path!("password").and(filter).boxed()
}
#[derive(Deserialize)] #[derive(Deserialize)]
struct Form { pub struct ChangeForm {
current_password: String, current_password: String,
new_password: String, new_password: String,
new_password_confirm: String, new_password_confirm: String,
} }
async fn get( pub(crate) async fn get(
templates: Templates, Extension(templates): Extension<Templates>,
cookie_saver: EncryptedCookieSaver, Extension(pool): Extension<PgPool>,
csrf_token: CsrfToken, cookie_jar: PrivateCookieJar<Encrypter>,
session: BrowserSession<PostgresqlBackend>, ) -> Result<Response, FancyError> {
) -> Result<Box<dyn Reply>, Rejection> { let mut conn = pool
render(templates, cookie_saver, csrf_token, session).await .acquire()
.await
.map_err(fancy_error(templates.clone()))?;
let (session_info, cookie_jar) = cookie_jar.session_info();
let maybe_session = session_info
.load_session(&mut conn)
.await
.map_err(fancy_error(templates.clone()))?;
if let Some(session) = maybe_session {
render(templates, session, cookie_jar).await
} else {
let login = LoginRequest::default();
let login = login.build_uri().map_err(fancy_error(templates.clone()))?;
Ok((cookie_jar.headers(), Redirect::to(login)).into_response())
}
} }
async fn render( async fn render(
templates: Templates, templates: Templates,
cookie_saver: EncryptedCookieSaver,
csrf_token: CsrfToken,
session: BrowserSession<PostgresqlBackend>, session: BrowserSession<PostgresqlBackend>,
) -> Result<Box<dyn Reply>, Rejection> { cookie_jar: PrivateCookieJar<Encrypter>,
) -> Result<Response, FancyError> {
let (csrf_token, cookie_jar) = cookie_jar.csrf_token();
let ctx = EmptyContext let ctx = EmptyContext
.with_session(session) .with_session(session)
.with_csrf(csrf_token.form_value()); .with_csrf(csrf_token.form_value());
let content = templates.render_account_password(&ctx).await?; let content = templates
let reply = html(content); .render_account_password(&ctx)
let reply = cookie_saver.save_encrypted(&csrf_token, reply)?; .await
.map_err(fancy_error(templates))?;
Ok(Box::new(reply)) Ok((cookie_jar.headers(), Html(content)).into_response())
} }
async fn post( pub(crate) async fn post(
templates: Templates, Extension(templates): Extension<Templates>,
cookie_saver: EncryptedCookieSaver, Extension(pool): Extension<PgPool>,
csrf_token: CsrfToken, cookie_jar: PrivateCookieJar<Encrypter>,
mut session: BrowserSession<PostgresqlBackend>, Form(form): Form<ProtectedForm<ChangeForm>>,
mut txn: Transaction<'_, Postgres>, ) -> Result<Response, FancyError> {
form: Form, let mut txn = pool.begin().await.map_err(fancy_error(templates.clone()))?;
) -> Result<Box<dyn Reply>, Rejection> {
let form = cookie_jar
.verify_form(form)
.map_err(fancy_error(templates.clone()))?;
let (session_info, cookie_jar) = cookie_jar.session_info();
let maybe_session = session_info
.load_session(&mut txn)
.await
.map_err(fancy_error(templates.clone()))?;
let mut session = if let Some(session) = maybe_session {
session
} else {
let login = LoginRequest::default();
let login = login.build_uri().map_err(fancy_error(templates.clone()))?;
return Ok((cookie_jar.headers(), Redirect::to(login)).into_response());
};
authenticate_session(&mut txn, &mut session, form.current_password) authenticate_session(&mut txn, &mut session, form.current_password)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
// TODO: display nice form errors // TODO: display nice form errors
if form.new_password != form.new_password_confirm { if form.new_password != form.new_password_confirm {
return Err(anyhow::anyhow!("password mismatch")).wrap_error(); return Err(anyhow::anyhow!("password mismatch")).map_err(fancy_error(templates.clone()));
} }
let phf = Argon2::default(); let phf = Argon2::default();
set_password(&mut txn, phf, &session.user, &form.new_password) set_password(&mut txn, phf, &session.user, &form.new_password)
.await .await
.wrap_error()?; .map_err(fancy_error(templates.clone()))?;
let reply = render(templates, cookie_saver, csrf_token, session).await?; let reply = render(templates.clone(), session, cookie_jar).await?;
txn.commit().await.wrap_error()?; txn.commit().await.map_err(fancy_error(templates.clone()))?;
Ok(reply) Ok(reply)
} }

View File

@@ -30,7 +30,7 @@ use sqlx::PgPool;
use super::{shared::PostAuthAction, RegisterRequest}; use super::{shared::PostAuthAction, RegisterRequest};
#[derive(Deserialize)] #[derive(Deserialize, Default)]
pub(crate) struct LoginRequest { pub(crate) struct LoginRequest {
#[serde(flatten)] #[serde(flatten)]
post_auth_action: Option<PostAuthAction>, post_auth_action: Option<PostAuthAction>,

View File

@@ -1,4 +1,4 @@
// Copyright 2021-2022 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.
@@ -12,12 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use mas_config::{CsrfConfig, Encrypter, HttpConfig};
use mas_email::Mailer;
use mas_templates::Templates;
use sqlx::PgPool;
use warp::{filters::BoxedFilter, Filter, Reply};
pub mod account; pub mod account;
pub mod index; pub mod index;
pub mod login; pub mod login;
@@ -27,20 +21,6 @@ pub mod register;
pub mod shared; pub mod shared;
pub mod verify; pub mod verify;
use self::account::filter as account;
pub(crate) use self::{ pub(crate) use self::{
login::LoginRequest, reauth::ReauthRequest, register::RegisterRequest, shared::PostAuthAction, login::LoginRequest, reauth::ReauthRequest, register::RegisterRequest, shared::PostAuthAction,
}; };
pub(super) fn filter(
pool: &PgPool,
templates: &Templates,
mailer: &Mailer,
encrypter: &Encrypter,
http_config: &HttpConfig,
csrf_config: &CsrfConfig,
) -> BoxedFilter<(Box<dyn Reply>,)> {
let account = account(pool, templates, mailer, encrypter, http_config, csrf_config);
account.boxed()
}

View File

@@ -1,4 +1,4 @@
// 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.