From eac74fa0d14425d32a78f93299b4ebfa4713b5f2 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Tue, 14 Jul 2026 22:35:14 +0200 Subject: [PATCH] changes for review --- .env.template | 9 +++++++++ src/config.rs | 13 ++++++++----- src/mail.rs | 51 +++++++++++++++++++++------------------------------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/.env.template b/.env.template index 0d922774..76652aa7 100644 --- a/.env.template +++ b/.env.template @@ -640,6 +640,15 @@ ## Embed images as email attachments # SMTP_EMBED_IMAGES=true +## Dkim signature (type:privatekey). |> Private must be base64-encoded ed key or PKCS#1 format RSA key. +# dkim_signing_key=rsa_key.pem +## Dkim algo (true if RSA else ed25519) +# dkim_use_rsa=true +## Dkim selector +# dkim_selector="dkim_key" +## Dkim domain +#dkim_domain="example.com" + ## SMTP debugging ## When set to true this will output very detailed SMTP messages. ## WARNING: This could contain sensitive information like passwords and usernames! Only enable this during troubleshooting! diff --git a/src/config.rs b/src/config.rs index 85696b83..547de889 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,6 +15,7 @@ use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor}; use crate::{ error::Error, mail::check_dkim, + storage, util::{ FeatureFlagFilter, get_active_web_release, get_env, get_env_bool, is_valid_email, parse_experimental_client_feature_flags, @@ -885,12 +886,14 @@ make_config! { smtp_username: String, true, option; /// Password smtp_password: Pass, true, option; - /// Dkim signature (type:privatekey). Private must be base64-encoded ed key or PKCS#1 format RSA key. - dkim_signature: String, true, option; - /// Dkim algo (true if RSA else ed25519) + /// Dkim signature (private key). |> Private must be base64-encoded ed key or PKCS#1 format RSA key. If set, dkim_selector and dkim_domain must be set as well. + dkim_signing_key: String, true, option; + /// Dkim algorithm (true if RSA else ed25519) dkim_use_rsa: bool, true, def, false; - /// Dkim infos (selector:domain) - dkim_infos: String, true, option; + /// Dkim selector + dkim_selector: String, true, option; + /// Dkim domain + dkim_domain: String, true, option; /// SMTP Auth mechanism |> Defaults for SSL is "Plain" and "Login" and nothing for Non-SSL connections. Possible values: ["Plain", "Login", "Xoauth2"]. Multiple options need to be separated by a comma ','. smtp_auth_mechanism: String, true, option; /// SMTP connection timeout |> Number of seconds when to stop trying to connect to the SMTP server diff --git a/src/mail.rs b/src/mail.rs index 73c1ded4..abe96229 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -2,15 +2,12 @@ use std::{env::consts::EXE_SUFFIX, str::FromStr}; use chrono::NaiveDateTime; use lettre::{ -<<<<<<< HEAD Address, AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Tokio1Executor, message::{Attachment, Body, Mailbox, Message, MultiPart, SinglePart}, -======= message::{ dkim::{DkimConfig, DkimSigningAlgorithm, DkimSigningKey}, - dkim_sign, Attachment, Body, Mailbox, Message, MultiPart, SinglePart, + dkim_sign, }, ->>>>>>> daa9e075 (corrections on config parsing) transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism}, transport::smtp::client::{Tls, TlsParameters}, transport::smtp::extension::ClientId, @@ -26,7 +23,7 @@ use crate::{ }, db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, error::Error, - util::upcase_first, + util::{get_env_str_value, upcase_first}, }; fn sendmail_transport() -> AsyncSendmailTransport { @@ -707,38 +704,32 @@ async fn send_with_selected_transport(email: Message) -> EmptyResult { } } pub fn check_dkim() -> Result, String> { - match (CONFIG.dkim_signature(), CONFIG.dkim_infos()) { - (Some(sig), Some(infos)) => { + match ( + CONFIG.dkim_signing_key().and_then(|a| get_env_str_value(&a)), + CONFIG.dkim_domain().and_then(|a| get_env_str_value(&a)), + CONFIG.dkim_selector().and_then(|a| get_env_str_value(&a)), //get_env_str should return None only if variables are not set, which is already checked + ) { + (Some(sig), Some(domain), Some(selector)) => { let config = { - let algo = if CONFIG.dkim_use_rsa() {DkimSigningAlgorithm::Rsa } else { DkimSigningAlgorithm::Ed25519 }; - let sig = match std::fs::read_to_string(sig) { + let algo = if CONFIG.dkim_use_rsa() { + DkimSigningAlgorithm::Rsa + } else { + DkimSigningAlgorithm::Ed25519 + }; + let sig = match DkimSigningKey::new(&sig, algo) { + Ok(d) => d, Err(e) => { - return Err(format!("Cannot read DKIM key. Err is {:?}", e)); + return Err(format!("DKIM key is invalid. Err is {e:?}")); } - Ok(key) => match DkimSigningKey::new(&key, algo) { - Ok(d) => d, - Err(e) => { - return Err(format!("DKIM key is invalid. Err is {:?}", e)); - } - }, }; - match (sig, infos.split(':').collect::>()) { - (sig, split2) if split2.len() == 2 => { - let (selector, domain, sig) = - (String::from(*split2.first().unwrap()), String::from(*split2.last().unwrap()), sig); - (selector, domain, sig) - } - _ => { - return Err("DKIM issue, invalid domain, selector.".to_string()); - } - } + (selector, domain, sig) }; Ok(Some(DkimConfig::default_config(config.0, config.1, config.2))) } - (None, None) => Ok(None), - _ => { - Err("DKIM setting is badly implemented. One config is missing (DKIM signature or DKIM infos).".to_string()) - } + (None, None, None) => Ok(None), + _ => Err( + "DKIM setting is badly implemented. One config is missing or invalid (DKIM signature or DKIM infos or DKIM signing key).".to_owned(), + ), } } async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult {