diff --git a/src/imap/client.rs b/src/imap/client.rs index 5e8d0895d..265a9287a 100644 --- a/src/imap/client.rs +++ b/src/imap/client.rs @@ -11,9 +11,9 @@ use tokio::io::BufWriter; use super::capabilities::Capabilities; use super::session::Session; use crate::context::Context; -use crate::login_param::build_tls; use crate::net::connect_tcp; use crate::net::session::SessionStream; +use crate::net::tls::wrap_tls; use crate::socks::Socks5Config; /// IMAP write and read timeout. @@ -95,8 +95,7 @@ impl Client { strict_tls: bool, ) -> Result { let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT, strict_tls).await?; - let tls = build_tls(strict_tls); - let tls_stream = tls.connect(hostname, tcp_stream).await?; + let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream).await?; let buffered_stream = BufWriter::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); let mut client = ImapClient::new(session_stream); @@ -142,9 +141,7 @@ impl Client { .context("STARTTLS command failed")?; let tcp_stream = client.into_inner(); - let tls = build_tls(strict_tls); - let tls_stream = tls - .connect(hostname, tcp_stream) + let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream) .await .context("STARTTLS upgrade failed")?; @@ -165,8 +162,7 @@ impl Client { let socks5_stream = socks5_config .connect(context, domain, port, IMAP_TIMEOUT, strict_tls) .await?; - let tls = build_tls(strict_tls); - let tls_stream = tls.connect(domain, socks5_stream).await?; + let tls_stream = wrap_tls(strict_tls, domain, socks5_stream).await?; let buffered_stream = BufWriter::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); let mut client = ImapClient::new(session_stream); @@ -221,9 +217,7 @@ impl Client { .context("STARTTLS command failed")?; let socks5_stream = client.into_inner(); - let tls = build_tls(strict_tls); - let tls_stream = tls - .connect(hostname, socks5_stream) + let tls_stream = wrap_tls(strict_tls, hostname, socks5_stream) .await .context("STARTTLS upgrade failed")?; let buffered_stream = BufWriter::new(tls_stream); diff --git a/src/login_param.rs b/src/login_param.rs index ee674c1fc..e01e43a0f 100644 --- a/src/login_param.rs +++ b/src/login_param.rs @@ -3,8 +3,6 @@ use std::fmt; use anyhow::{ensure, Result}; -use async_native_tls::Certificate; -use once_cell::sync::Lazy; use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2}; use crate::provider::{get_provider_by_id, Provider}; @@ -306,28 +304,6 @@ fn unset_empty(s: &str) -> &str { } } -// this certificate is missing on older android devices (eg. lg with android6 from 2017) -// certificate downloaded from https://letsencrypt.org/certificates/ -static LETSENCRYPT_ROOT: Lazy = Lazy::new(|| { - Certificate::from_der(include_bytes!( - "../assets/root-certificates/letsencrypt/isrgrootx1.der" - )) - .unwrap() -}); - -pub fn build_tls(strict_tls: bool) -> async_native_tls::TlsConnector { - let tls_builder = - async_native_tls::TlsConnector::new().add_root_certificate(LETSENCRYPT_ROOT.clone()); - - if strict_tls { - tls_builder - } else { - tls_builder - .danger_accept_invalid_hostnames(true) - .danger_accept_invalid_certs(true) - } -} - #[cfg(test)] mod tests { use super::*; @@ -378,13 +354,4 @@ mod tests { assert_eq!(param, loaded); Ok(()) } - - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn test_build_tls() -> Result<()> { - // we are using some additional root certificates. - // make sure, they do not break construction of TlsConnector - let _ = build_tls(true); - let _ = build_tls(false); - Ok(()) - } } diff --git a/src/net.rs b/src/net.rs index 2fb9cb6b6..2d36e90aa 100644 --- a/src/net.rs +++ b/src/net.rs @@ -13,6 +13,7 @@ use crate::context::Context; use crate::tools::time; pub(crate) mod session; +pub(crate) mod tls; async fn connect_tcp_inner(addr: SocketAddr, timeout_val: Duration) -> Result { let tcp_stream = timeout(timeout_val, TcpStream::connect(addr)) diff --git a/src/net/tls.rs b/src/net/tls.rs new file mode 100644 index 000000000..980504416 --- /dev/null +++ b/src/net/tls.rs @@ -0,0 +1,50 @@ +//! TLS support. + +use anyhow::Result; +use async_native_tls::{Certificate, TlsConnector, TlsStream}; +use once_cell::sync::Lazy; +use tokio::io::{AsyncRead, AsyncWrite}; + +// this certificate is missing on older android devices (eg. lg with android6 from 2017) +// certificate downloaded from https://letsencrypt.org/certificates/ +static LETSENCRYPT_ROOT: Lazy = Lazy::new(|| { + Certificate::from_der(include_bytes!( + "../../assets/root-certificates/letsencrypt/isrgrootx1.der" + )) + .unwrap() +}); + +pub fn build_tls(strict_tls: bool) -> TlsConnector { + let tls_builder = TlsConnector::new().add_root_certificate(LETSENCRYPT_ROOT.clone()); + + if strict_tls { + tls_builder + } else { + tls_builder + .danger_accept_invalid_hostnames(true) + .danger_accept_invalid_certs(true) + } +} + +pub async fn wrap_tls( + strict_tls: bool, + hostname: &str, + stream: T, +) -> Result> { + let tls = build_tls(strict_tls); + let tls_stream = tls.connect(hostname, stream).await?; + Ok(tls_stream) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_build_tls() { + // we are using some additional root certificates. + // make sure, they do not break construction of TlsConnector + let _ = build_tls(true); + let _ = build_tls(false); + } +} diff --git a/src/smtp.rs b/src/smtp.rs index cda3aff05..ca0e69ff8 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -13,12 +13,13 @@ use tokio::task; use crate::config::Config; use crate::contact::{Contact, ContactId}; use crate::events::EventType; -use crate::login_param::{build_tls, CertificateChecks, LoginParam, ServerLoginParam}; +use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam}; use crate::message::Message; use crate::message::{self, MsgId}; use crate::mimefactory::MimeFactory; use crate::net::connect_tcp; use crate::net::session::SessionStream; +use crate::net::tls::wrap_tls; use crate::oauth2::get_oauth2_access_token; use crate::provider::Socket; use crate::socks::Socks5Config; @@ -119,8 +120,7 @@ impl Smtp { let socks5_stream = socks5_config .connect(context, hostname, port, SMTP_TIMEOUT, strict_tls) .await?; - let tls = build_tls(strict_tls); - let tls_stream = tls.connect(hostname, socks5_stream).await?; + let tls_stream = wrap_tls(strict_tls, hostname, socks5_stream).await?; let buffered_stream = BufWriter::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); let client = smtp::SmtpClient::new().smtp_utf8(true); @@ -144,9 +144,7 @@ impl Smtp { let client = smtp::SmtpClient::new().smtp_utf8(true); let transport = SmtpTransport::new(client, socks5_stream).await?; let tcp_stream = transport.starttls().await?; - let tls = build_tls(strict_tls); - let tls_stream = tls - .connect(hostname, tcp_stream) + let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream) .await .context("STARTTLS upgrade failed")?; let buffered_stream = BufWriter::new(tls_stream); @@ -181,8 +179,7 @@ impl Smtp { strict_tls: bool, ) -> Result>> { let tcp_stream = connect_tcp(context, hostname, port, SMTP_TIMEOUT, false).await?; - let tls = build_tls(strict_tls); - let tls_stream = tls.connect(hostname, tcp_stream).await?; + let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream).await?; let buffered_stream = BufWriter::new(tls_stream); let session_stream: Box = Box::new(buffered_stream); let client = smtp::SmtpClient::new().smtp_utf8(true); @@ -203,9 +200,7 @@ impl Smtp { let client = smtp::SmtpClient::new().smtp_utf8(true); let transport = SmtpTransport::new(client, tcp_stream).await?; let tcp_stream = transport.starttls().await?; - let tls = build_tls(strict_tls); - let tls_stream = tls - .connect(hostname, tcp_stream) + let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream) .await .context("STARTTLS upgrade failed")?; let buffered_stream = BufWriter::new(tls_stream);