refactor: create mail state and reword email

This commit is contained in:
Max Hohlfeld 2024-07-16 14:43:20 +02:00
parent 10df91adfe
commit 99b2fbafa0
6 changed files with 85 additions and 20 deletions

6
.env
View File

@ -4,4 +4,10 @@
DATABASE_URL=postgresql://max@localhost/brass
# 64 byte long
SECRET_KEY="changeInProdOrHandAb11111111111111111111111111111111111111111111"
HOSTNAME="localhost"
SMTP_SERVER="localhost"
SMTP_PORT="1025"
# SMTP_LOGIN=""
# SMTP_PASSWORD=""
SMTP_TLSTYPE="none"

View File

@ -8,3 +8,4 @@
## Useful stuff
- cargo-watch, cargo-add
- mailtutan

View File

@ -1,5 +1,10 @@
use std::env;
use actix_web::{web, HttpResponse, Responder};
use lettre::{message::header::ContentType, Message, SmtpTransport, Transport};
use lettre::{
message::{header::ContentType, MultiPart, SinglePart},
Message, SmtpTransport, Transport,
};
use serde::Deserialize;
use sqlx::PgPool;
@ -17,7 +22,11 @@ struct ResetPasswordForm {
}
#[actix_web::post("/reset-password")]
async fn post(form: web::Form<ResetPasswordForm>, pool: web::Data<PgPool>) -> impl Responder {
async fn post(
form: web::Form<ResetPasswordForm>,
pool: web::Data<PgPool>,
mailer: web::Data<SmtpTransport>,
) -> impl Responder {
if form.email.is_some()
&& form.token.is_none()
&& form.password.is_none()
@ -28,35 +37,45 @@ async fn post(form: web::Form<ResetPasswordForm>, pool: web::Data<PgPool>) -> im
.await
.unwrap();
// send email to user
let hostname = env::var("HOSTNAME").unwrap();
let reset_url = format!("https://{}/reset-password?token={}", hostname, reset.token);
let message = Message::builder()
.from("noreply <noreply@brasiwa-leipzig.de>".parse().unwrap())
.reply_to("noreply <noreply@brasiwa-leipzig.de>".parse().unwrap())
.to(format!("{} <{}>", user.name, user.email).parse().unwrap())
.subject("Brass: Zurücksetzen des Passworts angefordert")
.multipart(
MultiPart::alternative()
.singlepart(
SinglePart::builder()
.header(ContentType::TEXT_PLAIN)
.body(format!(r##"
Hallo {},
.body(format!(r##"Hallo {},
hier der Link zur Passwortzurücksetzung: https://brasiwa-leipzig.de/reset-password?token={}
Debug: http://localhost:8080/reset-password?token={}
du hast angefordert, dein Passwort zurückzusetzen. Kopiere dafür folgenden Link in deinen Browser:
Nur 24 Stunden gültig!
Wenn du das nicht angefordert hast, dann hast du nichts weiter zu tun. Vielleicht solltest du deine Email bei haveibeenpawn checken!
{}
Bitte nicht auf die E-Mail antworten.
Bitte beachte, dass der Link nur 24 Stunden gültig ist. Solltest du nichts angefordert haben, dann musst du nichts weiter tun.
Viele Grüße
"##, user.name, reset.token, reset.token))
Viele Grüße"##, user.name, reset_url))
)
.singlepart(
SinglePart::builder()
.header(ContentType::TEXT_HTML)
.body(format!(r##"<p>Hallo {},</p>
<p>du hast angefordert, dein Passwort zurückzusetzen. Klicke dafür <a href="{}" target="_blank">hier</a> oder kopiere folgenden Link in deinen Browser:</p>
<p>{}</p>
<p>Bitte beachte, dass der Link <b>nur 24 Stunden gültig</b> ist. Solltest du nichts angefordert haben, dann musst du nichts weiter tun.</p>
<p>Viele Grüße</p>"##, user.name, reset_url, reset_url))
))
.unwrap();
let mailer = SmtpTransport::from_url("smtp://localhost:1025")
.unwrap()
.build();
mailer.send(&message).unwrap();
println!("{reset:?}");
}
return HttpResponse::Ok().body("E-Mail versandt!");
@ -91,7 +110,7 @@ async fn post(form: web::Form<ResetPasswordForm>, pool: web::Data<PgPool>) -> im
None,
None,
None,
None
None,
)
.await
.unwrap();

View File

@ -19,6 +19,7 @@ mod auth;
mod endpoints;
mod models;
mod middleware;
mod utils;
mod filters;
mod postgres_session_store;
@ -75,6 +76,7 @@ async fn main() -> anyhow::Result<()> {
};
let pool = PgPool::connect(&env::var("DATABASE_URL")?).await?;
let mailer = utils::email::get_mailer()?;
let secret_key = Key::from(env::var("SECRET_KEY")?.as_bytes());
let store = SqlxPostgresqlSessionStore::from_pool(pool.clone().into());
@ -121,6 +123,7 @@ async fn main() -> anyhow::Result<()> {
App::new()
.app_data(web::Data::new(pool.clone()))
.app_data(web::Data::new(mailer.clone()))
.configure(endpoints::init)
.wrap(middleware::RedirectToLogin)
.wrap(middleware::LoadCurrentUser)

35
src/utils/email.rs Normal file
View File

@ -0,0 +1,35 @@
use std::env;
use lettre::{
transport::smtp::{authentication::Credentials, extension::ClientId},
SmtpTransport,
};
pub fn get_mailer() -> anyhow::Result<SmtpTransport> {
let server = &env::var("SMTP_SERVER")?;
let port = &env::var("SMTP_PORT")?.parse()?;
let login = &env::var("SMTP_LOGIN")
.and_then(|x| Ok(Some(x)))
.unwrap_or(None);
let password = &env::var("SMTP_PASSWORD")
.and_then(|x| Ok(Some(x)))
.unwrap_or(None);
let tls_type = &env::var("SMTP_TLSTYPE")?;
let hostname = &env::var("HOSTNAME")?;
let mut builder = match tls_type.as_str() {
"starttls" => SmtpTransport::starttls_relay(server)?.port(*port),
"tls" => SmtpTransport::relay(server)?.port(*port),
_ => SmtpTransport::builder_dangerous(server).port(*port),
};
if let (Some(login), Some(password)) = (login, password) {
builder = builder.credentials(Credentials::new(login.to_string(), password.to_string()));
}
let mailer = builder
.hello_name(ClientId::Domain(hostname.to_string()))
.build();
Ok(mailer)
}

1
src/utils/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod email;