diff options
Diffstat (limited to '')
| -rw-r--r-- | crates/secd/src/client/email.rs | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/crates/secd/src/client/email.rs b/crates/secd/src/client/email.rs new file mode 100644 index 0000000..fc48702 --- /dev/null +++ b/crates/secd/src/client/email.rs @@ -0,0 +1,62 @@ +use std::{path::PathBuf, str::FromStr}; + +use email_address::EmailAddress; + +use super::{ + EmailMessenger, EmailMessengerError, EmailType, EMAIL_TEMPLATE_DEFAULT_LOGIN, + EMAIL_TEMPLATE_DEFAULT_SIGNUP, +}; + +pub(crate) struct LocalEmailStubber { + pub(crate) email_template_login: Option<String>, + pub(crate) email_template_signup: Option<String>, +} + +#[async_trait::async_trait] +impl EmailMessenger for LocalEmailStubber { + // TODO: this module really shouldn't be called client, it should be called services... the client is sqlx/mailgun/sns wrapper or whatever... + async fn send_email( + &self, + email_address: &str, + validation_id: &str, + secret_code: &str, + t: EmailType, + ) -> Result<(), EmailMessengerError> { + let login_template = self + .email_template_login + .clone() + .unwrap_or(EMAIL_TEMPLATE_DEFAULT_LOGIN.to_string()); + let signup_template = self + .email_template_signup + .clone() + .unwrap_or(EMAIL_TEMPLATE_DEFAULT_SIGNUP.to_string()); + + let replace_template = |s: &str| { + s.replace( + "%secd_link%", + &format!("{}?code={}", validation_id, secret_code), + ) + .replace("%secd_email_address%", email_address) + .replace("%secd_code%", secret_code) + }; + + if !EmailAddress::is_valid(email_address) { + return Err(EmailMessengerError::InvalidEmailAddress); + } + + let body = match t { + EmailType::Login => replace_template(&login_template), + EmailType::Signup => replace_template(&signup_template), + }; + + // TODO: write to the system mailbox instead? + std::fs::write( + PathBuf::from_str(&format!("/tmp/{}.localmail", validation_id)) + .map_err(|_| EmailMessengerError::Unknown)?, + body, + ) + .map_err(|_| EmailMessengerError::FailedToSendEmail)?; + + Ok(()) + } +} |
