1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-09 04:22:45 +03:00

Actually send emails for recovery

This commit is contained in:
Quentin Gliech
2024-06-24 17:20:22 +02:00
parent 4a60f5d32f
commit c156a3891e
17 changed files with 337 additions and 14 deletions

View File

@@ -29,7 +29,7 @@ use http::{Method, Uri, Version};
use mas_data_model::{
AuthorizationGrant, BrowserSession, Client, CompatSsoLogin, CompatSsoLoginState,
DeviceCodeGrant, UpstreamOAuthLink, UpstreamOAuthProvider, User, UserAgent, UserEmail,
UserEmailVerification,
UserEmailVerification, UserRecoverySession,
};
use mas_i18n::DataLocale;
use mas_router::{Account, GraphQL, PostAuthAction, UrlBuilder};
@@ -751,6 +751,61 @@ where {
}
}
/// Context used by the `emails/recovery.{txt,html,subject}` templates
#[derive(Serialize)]
pub struct EmailRecoveryContext {
user: User,
session: UserRecoverySession,
recovery_link: Url,
}
impl EmailRecoveryContext {
/// Constructs a context for the recovery email
#[must_use]
pub fn new(user: User, session: UserRecoverySession, recovery_link: Url) -> Self {
Self {
user,
session,
recovery_link,
}
}
/// Returns the user associated with the recovery email
#[must_use]
pub fn user(&self) -> &User {
&self.user
}
/// Returns the recovery session associated with the recovery email
#[must_use]
pub fn session(&self) -> &UserRecoverySession {
&self.session
}
}
impl TemplateContext for EmailRecoveryContext {
fn sample(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self>
where
Self: Sized,
{
User::samples(now, rng).into_iter().map(|user| {
let session = UserRecoverySession {
id: Ulid::from_datetime_with_source(now.into(), rng),
email: "hello@example.com".to_owned(),
user_agent: UserAgent::parse("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1".to_owned()),
ip_address: Some(IpAddr::from([192_u8, 0, 2, 1])),
locale: "en".to_owned(),
created_at: now,
consumed_at: None,
};
let link = "https://example.com/recovery/complete?ticket=abcdefghijklmnopqrstuvwxyz0123456789".parse().unwrap();
Self::new(user, session, link)
}).collect()
}
}
/// Context used by the `emails/verification.{txt,html,subject}` templates
#[derive(Serialize)]
pub struct EmailVerificationContext {

View File

@@ -56,7 +56,7 @@ pub struct WithCaptcha<T> {
impl<T> WithCaptcha<T> {
#[must_use]
pub fn new(captcha: Option<mas_data_model::CaptchaConfig>, inner: T) -> Self {
pub(crate) fn new(captcha: Option<mas_data_model::CaptchaConfig>, inner: T) -> Self {
Self {
captcha: captcha.map(|captcha| Value::from_object(CaptchaConfig(captcha))),
inner,

View File

@@ -22,7 +22,6 @@ use std::{collections::HashSet, sync::Arc};
use anyhow::Context as _;
use arc_swap::ArcSwap;
use camino::{Utf8Path, Utf8PathBuf};
use context::WithCaptcha;
use mas_i18n::Translator;
use mas_router::UrlBuilder;
use mas_spa::ViteManifest;
@@ -44,13 +43,13 @@ mod macros;
pub use self::{
context::{
AppContext, CompatSsoContext, ConsentContext, DeviceConsentContext, DeviceLinkContext,
DeviceLinkFormField, EmailAddContext, EmailVerificationContext,
DeviceLinkFormField, EmailAddContext, EmailRecoveryContext, EmailVerificationContext,
EmailVerificationPageContext, EmptyContext, ErrorContext, FormPostContext, IndexContext,
LoginContext, LoginFormField, NotFoundContext, PolicyViolationContext, PostAuthContext,
PostAuthContextInner, ReauthContext, ReauthFormField, RecoveryStartContext,
RecoveryStartFormField, RegisterContext, RegisterFormField, SiteBranding, SiteConfigExt,
SiteFeatures, TemplateContext, UpstreamExistingLinkContext, UpstreamRegister,
UpstreamRegisterFormField, UpstreamSuggestLink, WithCsrf, WithLanguage,
UpstreamRegisterFormField, UpstreamSuggestLink, WithCaptcha, WithCsrf, WithLanguage,
WithOptionalSession, WithSession,
},
forms::{FieldError, FormError, FormField, FormState, ToFormState},
@@ -360,6 +359,15 @@ register_templates! {
/// Render the HTML error page
pub fn render_error(ErrorContext) { "pages/error.html" }
/// Render the email recovery email (plain text variant)
pub fn render_email_recovery_txt(WithLanguage<EmailRecoveryContext>) { "emails/recovery.txt" }
/// Render the email recovery email (HTML text variant)
pub fn render_email_recovery_html(WithLanguage<EmailRecoveryContext>) { "emails/recovery.html" }
/// Render the email recovery subject
pub fn render_email_recovery_subject(WithLanguage<EmailRecoveryContext>) { "emails/recovery.subject" }
/// Render the email verification email (plain text variant)
pub fn render_email_verification_txt(WithLanguage<EmailVerificationContext>) { "emails/verification.txt" }