server: Add a message ID to sent emails

Fixes #608
This commit is contained in:
Valentin Tolmer authored and nitnelave committed 2023-08-02 15:34:13 +02:00
1 parent f0bbcfd2c8
commit d0cdfa97c7
6 files changed
+48 -14

No files matched your search

Generated
+3
View File
@@ -2466,6 +2466,7 @@ dependencies = [
"tracing-forest",
"tracing-log",
"tracing-subscriber",
"url",
"urlencoding",
"uuid 1.3.1",
"webpki-roots",
@@ -4509,6 +4510,7 @@ dependencies = [
"form_urlencoded",
"idna 0.3.0",
"percent-encoding",
"serde",
]
[[package]]
@@ -4538,6 +4540,7 @@ version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b55a3fef2a1e3b3a00ce878640918820d3c51081576ac657d23af9fc7928fdb"
dependencies = [
"atomic",
"getrandom 0.2.8",
"md-5",
]
+5 -1
View File
@@ -96,7 +96,7 @@ features = ["full"]
version = "1.25"
[dependencies.uuid]
features = ["v3"]
features = ["v1", "v3"]
version = "*"
[dependencies.tracing-forest]
@@ -126,6 +126,10 @@ features = ["rustls-tls-webpki-roots"]
version = "0.20"
features = ["dangerous_configuration"]
[dependencies.url]
version = "2"
features = ["serde"]
[dev-dependencies]
assert_cmd = "2.0"
mockall = "0.11.4"
+2 -1
View File
@@ -1,6 +1,7 @@
use clap::{builder::EnumValueParser, Parser};
use lettre::message::Mailbox;
use serde::{Deserialize, Serialize};
use url::Url;
/// lldap is a lightweight LDAP server
#[derive(Debug, Parser, Clone)]
@@ -82,7 +83,7 @@ pub struct RunOpts {
/// URL of the server, for password reset links.
#[clap(long, env = "LLDAP_HTTP_URL")]
pub http_url: Option<String>,
pub http_url: Option<Url>,
/// Database connection URL
#[clap(short, long, env = "LLDAP_DATABASE_URL")]
+4 -3
View File
@@ -11,6 +11,7 @@ use lettre::message::Mailbox;
use lldap_auth::opaque::{server::ServerSetup, KeyPair};
use secstr::SecUtf8;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)]
#[builder(pattern = "owned")]
@@ -100,8 +101,8 @@ pub struct Configuration {
pub smtp_options: MailOptions,
#[builder(default)]
pub ldaps_options: LdapsOptions,
#[builder(default = r#"String::from("http://localhost")"#)]
pub http_url: String,
#[builder(default = r#"Url::parse("http://localhost").unwrap()"#)]
pub http_url: Url,
#[serde(skip)]
#[builder(field(private), default = "None")]
server_setup: Option<ServerSetup>,
@@ -237,7 +238,7 @@ impl ConfigOverrider for RunOpts {
}
if let Some(url) = self.http_url.as_ref() {
config.http_url = url.to_string();
config.http_url = url.clone();
}
if let Some(database_url) = self.database_url.as_ref() {
+32 -7
View File
@@ -6,7 +6,13 @@ use lettre::{
};
use tracing::debug;
async fn send_email(to: Mailbox, subject: &str, body: String, options: &MailOptions) -> Result<()> {
async fn send_email(
to: Mailbox,
subject: &str,
body: String,
options: &MailOptions,
server_url: &url::Url,
) -> Result<()> {
let from = options
.from
.clone()
@@ -17,6 +23,14 @@ async fn send_email(to: Mailbox, subject: &str, body: String, options: &MailOpti
&to, &from, &options.user, &options.server, options.port
);
let email = Message::builder()
.message_id(Some(format!(
"<{}@{}>",
uuid::Uuid::new_v1(
uuid::Timestamp::now(uuid::NoContext),
"lldap!".as_bytes().try_into().unwrap()
),
server_url.domain().unwrap_or_default()
)))
.from(from)
.reply_to(reply_to)
.to(to)
@@ -58,24 +72,34 @@ pub async fn send_password_reset_email(
username: &str,
to: &str,
token: &str,
domain: &str,
server_url: &url::Url,
options: &MailOptions,
) -> Result<()> {
let to = to.parse()?;
let mut reset_url = server_url.clone();
reset_url
.path_segments_mut()
.unwrap()
.extend(["reset-password", "step2", token]);
let body = format!(
"Hello {},
This email has been sent to you in order to validate your identity.
If you did not initiate the process your credentials might have been
compromised. You should reset your password and contact an administrator.
To reset your password please visit the following URL: {}/reset-password/step2/{}
To reset your password please visit the following URL: {}
Please contact an administrator if you did not initiate the process.",
username,
domain.trim_end_matches('/'),
token
username, reset_url
);
send_email(to, "[LLDAP] Password reset requested", body, options).await
send_email(
to,
"[LLDAP] Password reset requested",
body,
options,
server_url,
)
.await
}
pub async fn send_test_email(to: Mailbox, options: &MailOptions) -> Result<()> {
@@ -84,6 +108,7 @@ pub async fn send_test_email(to: Mailbox, options: &MailOptions) -> Result<()> {
"LLDAP test email",
"The test is successful! You can send emails from LLDAP".to_string(),
options,
&url::Url::parse("http://localhost").unwrap(),
)
.await
}
+2 -2
View File
@@ -87,7 +87,7 @@ fn http_config<Backend>(
backend_handler: Backend,
jwt_secret: secstr::SecUtf8,
jwt_blacklist: HashSet<u64>,
server_url: String,
server_url: url::Url,
mail_options: MailOptions,
) where
Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + Clone + 'static,
@@ -132,7 +132,7 @@ pub(crate) struct AppState<Backend> {
pub backend_handler: AccessControlledBackendHandler<Backend>,
pub jwt_key: Hmac<Sha512>,
pub jwt_blacklist: RwLock<HashSet<u64>>,
pub server_url: String,
pub server_url: url::Url,
pub mail_options: MailOptions,
}