diff --git a/crates/handlers/src/lib.rs b/crates/handlers/src/lib.rs index 969255db..9a60def9 100644 --- a/crates/handlers/src/lib.rs +++ b/crates/handlers/src/lib.rs @@ -387,7 +387,7 @@ where ) .route( mas_router::AccountRecoveryProgress::route(), - get(self::views::recovery::progress::get), + get(self::views::recovery::progress::get).post(self::views::recovery::progress::post), ) .route( mas_router::OAuth2AuthorizationEndpoint::route(), diff --git a/crates/handlers/src/views/recovery/progress.rs b/crates/handlers/src/views/recovery/progress.rs index ce35d4f3..99c51182 100644 --- a/crates/handlers/src/views/recovery/progress.rs +++ b/crates/handlers/src/views/recovery/progress.rs @@ -15,10 +15,18 @@ use axum::{ extract::{Path, State}, response::{Html, IntoResponse, Response}, + Form, +}; +use mas_axum_utils::{ + cookies::CookieJar, + csrf::{CsrfExt, ProtectedForm}, + FancyError, SessionInfoExt, }; -use mas_axum_utils::{cookies::CookieJar, csrf::CsrfExt, FancyError, SessionInfoExt}; use mas_router::UrlBuilder; -use mas_storage::{BoxClock, BoxRepository, BoxRng}; +use mas_storage::{ + job::{JobRepositoryExt, SendAccountRecoveryEmailsJob}, + BoxClock, BoxRepository, BoxRng, +}; use mas_templates::{RecoveryProgressContext, TemplateContext, Templates}; use ulid::Ulid; @@ -62,3 +70,51 @@ pub(crate) async fn get( Ok((cookie_jar, Html(rendered)).into_response()) } + +pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, + mut repo: BoxRepository, + State(templates): State, + State(url_builder): State, + PreferredLanguage(locale): PreferredLanguage, + cookie_jar: CookieJar, + Path(id): Path, + Form(form): Form>, +) -> Result { + let (session_info, cookie_jar) = cookie_jar.session_info(); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); + + let maybe_session = session_info.load_session(&mut repo).await?; + if maybe_session.is_some() { + // TODO: redirect to continue whatever action was going on + return Ok((cookie_jar, url_builder.redirect(&mas_router::Index)).into_response()); + } + + let Some(recovery_session) = repo.user_recovery().lookup_session(id).await? else { + // XXX: is that the right thing to do? + return Ok(( + cookie_jar, + url_builder.redirect(&mas_router::AccountRecoveryStart), + ) + .into_response()); + }; + + // Verify the CSRF token + let () = cookie_jar.verify_form(&clock, form)?; + + // Schedule a new batch of emails + repo.job() + .schedule_job(SendAccountRecoveryEmailsJob::new(&recovery_session)) + .await?; + + repo.save().await?; + + let context = RecoveryProgressContext::new(recovery_session) + .with_csrf(csrf_token.form_value()) + .with_language(locale); + + let rendered = templates.render_recovery_progress(&context)?; + + Ok((cookie_jar, Html(rendered)).into_response()) +}