Merge pull request 'Closes #944 Mail server port configuration' (#980) from mail-server-port into main

Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/980
This commit is contained in:
KitaitiMakoto 2022-01-03 10:37:53 +00:00
commit 9d012c8f3c
7 changed files with 75 additions and 19 deletions

3
Cargo.lock generated
View File

@ -2980,7 +2980,6 @@ dependencies = [
"gettext-macros", "gettext-macros",
"gettext-utils", "gettext-utils",
"guid-create", "guid-create",
"lettre",
"lettre_email", "lettre_email",
"multipart", "multipart",
"num_cpus", "num_cpus",
@ -3096,8 +3095,10 @@ dependencies = [
"itertools 0.8.2", "itertools 0.8.2",
"lazy_static", "lazy_static",
"ldap3", "ldap3",
"lettre",
"lindera-tantivy", "lindera-tantivy",
"migrations_internals", "migrations_internals",
"native-tls",
"once_cell", "once_cell",
"openssl", "openssl",
"plume-api", "plume-api",

View File

@ -15,7 +15,6 @@ gettext = { git = "https://github.com/Plume-org/gettext/", rev = "294c54d74c699f
gettext-macros = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" } gettext-macros = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
gettext-utils = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" } gettext-utils = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
guid-create = "0.1" guid-create = "0.1"
lettre = "0.9.2"
lettre_email = "0.9.2" lettre_email = "0.9.2"
num_cpus = "1.10" num_cpus = "1.10"
rocket = "0.4.6" rocket = "0.4.6"

View File

@ -34,6 +34,8 @@ lindera-tantivy = { version = "0.7.1", optional = true }
tracing = "0.1.22" tracing = "0.1.22"
riker = "0.4.2" riker = "0.4.2"
once_cell = "1.5.2" once_cell = "1.5.2"
lettre = "0.9.6"
native-tls = "0.2.8"
[dependencies.chrono] [dependencies.chrono]
features = ["serde"] features = ["serde"]

View File

@ -1,4 +1,5 @@
use crate::search::TokenizerKind as SearchTokenizer; use crate::search::TokenizerKind as SearchTokenizer;
use crate::smtp::{SMTP_PORT, SUBMISSIONS_PORT, SUBMISSION_PORT};
use rocket::config::Limits; use rocket::config::Limits;
use rocket::Config as RocketConfig; use rocket::Config as RocketConfig;
use std::collections::HashSet; use std::collections::HashSet;
@ -21,6 +22,7 @@ pub struct Config {
pub logo: LogoConfig, pub logo: LogoConfig,
pub default_theme: String, pub default_theme: String,
pub media_directory: String, pub media_directory: String,
pub mail: Option<MailConfig>,
pub ldap: Option<LdapConfig>, pub ldap: Option<LdapConfig>,
pub proxy: Option<ProxyConfig>, pub proxy: Option<ProxyConfig>,
} }
@ -245,6 +247,31 @@ impl SearchTokenizerConfig {
} }
} }
pub struct MailConfig {
pub server: String,
pub port: u16,
pub helo_name: String,
pub username: String,
pub password: String,
}
fn get_mail_config() -> Option<MailConfig> {
Some(MailConfig {
server: env::var("MAIL_SERVER").ok()?,
port: env::var("MAIL_PORT").map_or(SUBMISSIONS_PORT, |port| match port.as_str() {
"smtp" => SMTP_PORT,
"submissions" => SUBMISSIONS_PORT,
"submission" => SUBMISSION_PORT,
number => number
.parse()
.expect(r#"MAIL_PORT must be "smtp", "submissions", "submission" or an integer."#),
}),
helo_name: env::var("MAIL_HELO_NAME").unwrap_or_else(|_| "localhost".to_owned()),
username: env::var("MAIL_USER").ok()?,
password: env::var("MAIL_PASSWORD").ok()?,
})
}
pub struct LdapConfig { pub struct LdapConfig {
pub addr: String, pub addr: String,
pub base_dn: String, pub base_dn: String,
@ -347,6 +374,7 @@ lazy_static! {
default_theme: var("DEFAULT_THEME").unwrap_or_else(|_| "default-light".to_owned()), default_theme: var("DEFAULT_THEME").unwrap_or_else(|_| "default-light".to_owned()),
media_directory: var("MEDIA_UPLOAD_DIRECTORY") media_directory: var("MEDIA_UPLOAD_DIRECTORY")
.unwrap_or_else(|_| "static/media".to_owned()), .unwrap_or_else(|_| "static/media".to_owned()),
mail: get_mail_config(),
ldap: get_ldap_config(), ldap: get_ldap_config(),
proxy: get_proxy_config(), proxy: get_proxy_config(),
}; };

29
plume-models/src/lib.rs Executable file → Normal file
View File

@ -16,6 +16,8 @@ extern crate serde_json;
#[macro_use] #[macro_use]
extern crate tantivy; extern crate tantivy;
pub use lettre;
pub use lettre::smtp;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use plume_common::activity_pub::{inbox::InboxError, request, sign}; use plume_common::activity_pub::{inbox::InboxError, request, sign};
use posts::PostEvent; use posts::PostEvent;
@ -300,6 +302,33 @@ pub fn ap_url(url: &str) -> String {
format!("https://{}", url) format!("https://{}", url)
} }
pub trait SmtpNewWithAddr {
fn new_with_addr(
addr: (&str, u16),
) -> std::result::Result<smtp::SmtpClient, smtp::error::Error>;
}
impl SmtpNewWithAddr for smtp::SmtpClient {
// Stolen from lettre::smtp::SmtpClient::new_simple()
fn new_with_addr(addr: (&str, u16)) -> std::result::Result<Self, smtp::error::Error> {
use native_tls::TlsConnector;
use smtp::{
client::net::{ClientTlsParameters, DEFAULT_TLS_PROTOCOLS},
ClientSecurity, SmtpClient,
};
let (domain, port) = addr;
let mut tls_builder = TlsConnector::builder();
tls_builder.min_protocol_version(Some(DEFAULT_TLS_PROTOCOLS[0]));
let tls_parameters =
ClientTlsParameters::new(domain.to_string(), tls_builder.build().unwrap());
SmtpClient::new((domain, port), ClientSecurity::Wrapper(tls_parameters))
}
}
#[cfg(test)] #[cfg(test)]
#[macro_use] #[macro_use]
mod tests { mod tests {

View File

@ -6,7 +6,7 @@ pub use self::mailer::*;
#[cfg(feature = "debug-mailer")] #[cfg(feature = "debug-mailer")]
mod mailer { mod mailer {
use lettre::{SendableEmail, Transport}; use plume_models::smtp::{SendableEmail, Transport};
use std::io::Read; use std::io::Read;
pub struct DebugTransport; pub struct DebugTransport;
@ -46,27 +46,24 @@ mod mailer {
#[cfg(not(feature = "debug-mailer"))] #[cfg(not(feature = "debug-mailer"))]
mod mailer { mod mailer {
use lettre::{ use plume_models::smtp::{
smtp::{ authentication::{Credentials, Mechanism},
authentication::{Credentials, Mechanism}, extension::ClientId,
extension::ClientId, ConnectionReuseParameters, SmtpClient, SmtpTransport,
ConnectionReuseParameters,
},
SmtpClient, SmtpTransport,
}; };
use std::env; use plume_models::{SmtpNewWithAddr, CONFIG};
pub type Mailer = Option<SmtpTransport>; pub type Mailer = Option<SmtpTransport>;
pub fn init() -> Mailer { pub fn init() -> Mailer {
let server = env::var("MAIL_SERVER").ok()?; let config = CONFIG.mail.as_ref()?;
let helo_name = env::var("MAIL_HELO_NAME").unwrap_or_else(|_| "localhost".to_owned()); let mail = SmtpClient::new_with_addr((&config.server, config.port))
let username = env::var("MAIL_USER").ok()?;
let password = env::var("MAIL_PASSWORD").ok()?;
let mail = SmtpClient::new_simple(&server)
.unwrap() .unwrap()
.hello_name(ClientId::Domain(helo_name)) .hello_name(ClientId::Domain(config.helo_name.clone()))
.credentials(Credentials::new(username, password)) .credentials(Credentials::new(
config.username.clone(),
config.password.clone(),
))
.smtp_utf8(true) .smtp_utf8(true)
.authentication_mechanism(Mechanism::Plain) .authentication_mechanism(Mechanism::Plain)
.connection_reuse(ConnectionReuseParameters::NoReuse) .connection_reuse(ConnectionReuseParameters::NoReuse)

View File

@ -1,5 +1,5 @@
use crate::routes::RespondOrRedirect; use crate::routes::RespondOrRedirect;
use lettre::Transport; use plume_models::lettre::Transport;
use rocket::http::ext::IntoOwned; use rocket::http::ext::IntoOwned;
use rocket::{ use rocket::{
http::{uri::Uri, Cookie, Cookies, SameSite}, http::{uri::Uri, Cookie, Cookies, SameSite},