refactor: merge imap_certificate_checks and smtp_certificate_checks

This commit is contained in:
link2xt
2024-08-07 18:08:39 +00:00
committed by GitHub
parent 86ad5506e3
commit 6b4532a08e
11 changed files with 80 additions and 152 deletions

View File

@@ -409,7 +409,7 @@ char* dc_get_blobdir (const dc_context_t* context);
* - `socks5_user` = SOCKS5 proxy username * - `socks5_user` = SOCKS5 proxy username
* - `socks5_password` = SOCKS5 proxy password * - `socks5_password` = SOCKS5 proxy password
* - `imap_certificate_checks` = how to check IMAP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0) * - `imap_certificate_checks` = how to check IMAP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0)
* - `smtp_certificate_checks` = how to check SMTP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0) * - `smtp_certificate_checks` = deprecated option, should be set to the same value as `imap_certificate_checks` but ignored by the new core
* - `displayname` = Own name to use when sending messages. MUAs are allowed to spread this way e.g. using CC, defaults to empty * - `displayname` = Own name to use when sending messages. MUAs are allowed to spread this way e.g. using CC, defaults to empty
* - `selfstatus` = Own status to display, e.g. in e-mail footers, defaults to empty * - `selfstatus` = Own status to display, e.g. in e-mail footers, defaults to empty
* - `selfavatar` = File containing avatar. Will immediately be copied to the * - `selfavatar` = File containing avatar. Will immediately be copied to the

View File

@@ -59,7 +59,10 @@ pub enum Config {
/// IMAP server security (e.g. TLS, STARTTLS). /// IMAP server security (e.g. TLS, STARTTLS).
MailSecurity, MailSecurity,
/// How to check IMAP server TLS certificates. /// How to check TLS certificates.
///
/// "IMAP" in the name is for compatibility,
/// this actually applies to both IMAP and SMTP connections.
ImapCertificateChecks, ImapCertificateChecks,
/// SMTP server hostname. /// SMTP server hostname.
@@ -77,7 +80,9 @@ pub enum Config {
/// SMTP server security (e.g. TLS, STARTTLS). /// SMTP server security (e.g. TLS, STARTTLS).
SendSecurity, SendSecurity,
/// How to check SMTP server TLS certificates. /// Deprecated option for backwards compatibilty.
///
/// Certificate checks for SMTP are actually controlled by `imap_certificate_checks` config.
SmtpCertificateChecks, SmtpCertificateChecks,
/// Whether to use OAuth 2. /// Whether to use OAuth 2.
@@ -210,7 +215,12 @@ pub enum Config {
/// Configured IMAP server security (e.g. TLS, STARTTLS). /// Configured IMAP server security (e.g. TLS, STARTTLS).
ConfiguredMailSecurity, ConfiguredMailSecurity,
/// How to check IMAP server TLS certificates. /// Configured TLS certificate checks.
/// This option is saved on successful configuration
/// and should not be modified manually.
///
/// This actually applies to both IMAP and SMTP connections,
/// but has "IMAP" in the name for backwards compatibility.
ConfiguredImapCertificateChecks, ConfiguredImapCertificateChecks,
/// Configured SMTP server hostname. /// Configured SMTP server hostname.
@@ -225,7 +235,9 @@ pub enum Config {
/// Configured SMTP server port. /// Configured SMTP server port.
ConfiguredSendPort, ConfiguredSendPort,
/// How to check SMTP server TLS certificates. /// Deprecated, stored for backwards compatibility.
///
/// ConfiguredImapCertificateChecks is actually used.
ConfiguredSmtpCertificateChecks, ConfiguredSmtpCertificateChecks,
/// Whether OAuth 2 is used with configured provider. /// Whether OAuth 2 is used with configured provider.

View File

@@ -27,7 +27,7 @@ use crate::config::{self, Config};
use crate::context::Context; use crate::context::Context;
use crate::imap::{session::Session as ImapSession, Imap}; use crate::imap::{session::Session as ImapSession, Imap};
use crate::log::LogExt; use crate::log::LogExt;
use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam}; use crate::login_param::{LoginParam, ServerLoginParam};
use crate::message::{Message, Viewtype}; use crate::message::{Message, Viewtype};
use crate::oauth2::get_oauth2_addr; use crate::oauth2::get_oauth2_addr;
use crate::provider::{Protocol, Socket, UsernamePattern}; use crate::provider::{Protocol, Socket, UsernamePattern};
@@ -263,7 +263,6 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
} }
} }
}, },
strict_tls: Some(provider.opt.strict_tls),
}) })
.collect(); .collect();
@@ -291,6 +290,8 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
param_autoconfig = None; param_autoconfig = None;
} }
let strict_tls = param.strict_tls();
progress!(ctx, 500); progress!(ctx, 500);
let mut servers = param_autoconfig.unwrap_or_default(); let mut servers = param_autoconfig.unwrap_or_default();
@@ -304,7 +305,6 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
port: param.imap.port, port: param.imap.port,
socket: param.imap.security, socket: param.imap.security,
username: param.imap.user.clone(), username: param.imap.user.clone(),
strict_tls: None,
}) })
} }
if !servers if !servers
@@ -317,24 +317,9 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
port: param.smtp.port, port: param.smtp.port,
socket: param.smtp.security, socket: param.smtp.security,
username: param.smtp.user.clone(), username: param.smtp.user.clone(),
strict_tls: None,
}) })
} }
// respect certificate setting from function parameters
for server in &mut servers {
let certificate_checks = match server.protocol {
Protocol::Imap => param.imap.certificate_checks,
Protocol::Smtp => param.smtp.certificate_checks,
};
server.strict_tls = match certificate_checks {
CertificateChecks::AcceptInvalidCertificates
| CertificateChecks::AcceptInvalidCertificates2 => Some(false),
CertificateChecks::Strict => Some(true),
CertificateChecks::Automatic => server.strict_tls,
};
}
let servers = expand_param_vector(servers, &param.addr, &param_domain); let servers = expand_param_vector(servers, &param.addr, &param_domain);
progress!(ctx, 550); progress!(ctx, 550);
@@ -350,9 +335,6 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
.filter(|params| params.protocol == Protocol::Smtp) .filter(|params| params.protocol == Protocol::Smtp)
.cloned() .cloned()
.collect(); .collect();
let provider_strict_tls = param
.provider
.map_or(socks5_config.is_some(), |provider| provider.opt.strict_tls);
let smtp_config_task = task::spawn(async move { let smtp_config_task = task::spawn(async move {
let mut smtp_configured = false; let mut smtp_configured = false;
@@ -362,18 +344,13 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
smtp_param.server.clone_from(&smtp_server.hostname); smtp_param.server.clone_from(&smtp_server.hostname);
smtp_param.port = smtp_server.port; smtp_param.port = smtp_server.port;
smtp_param.security = smtp_server.socket; smtp_param.security = smtp_server.socket;
smtp_param.certificate_checks = match smtp_server.strict_tls {
Some(true) => CertificateChecks::Strict,
Some(false) => CertificateChecks::AcceptInvalidCertificates,
None => CertificateChecks::Automatic,
};
match try_smtp_one_param( match try_smtp_one_param(
&context_smtp, &context_smtp,
&smtp_param, &smtp_param,
&socks5_config, &socks5_config,
&smtp_addr, &smtp_addr,
provider_strict_tls, strict_tls,
&mut smtp, &mut smtp,
) )
.await .await
@@ -409,18 +386,13 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
param.imap.server.clone_from(&imap_server.hostname); param.imap.server.clone_from(&imap_server.hostname);
param.imap.port = imap_server.port; param.imap.port = imap_server.port;
param.imap.security = imap_server.socket; param.imap.security = imap_server.socket;
param.imap.certificate_checks = match imap_server.strict_tls {
Some(true) => CertificateChecks::Strict,
Some(false) => CertificateChecks::AcceptInvalidCertificates,
None => CertificateChecks::Automatic,
};
match try_imap_one_param( match try_imap_one_param(
ctx, ctx,
&param.imap, &param.imap,
&param.socks5_config, &param.socks5_config,
&param.addr, &param.addr,
provider_strict_tls, strict_tls,
) )
.await .await
{ {
@@ -601,15 +573,15 @@ async fn try_imap_one_param(
param: &ServerLoginParam, param: &ServerLoginParam,
socks5_config: &Option<Socks5Config>, socks5_config: &Option<Socks5Config>,
addr: &str, addr: &str,
provider_strict_tls: bool, strict_tls: bool,
) -> Result<(Imap, ImapSession), ConfigurationError> { ) -> Result<(Imap, ImapSession), ConfigurationError> {
let inf = format!( let inf = format!(
"imap: {}@{}:{} security={} certificate_checks={} oauth2={} socks5_config={}", "imap: {}@{}:{} security={} strict_tls={} oauth2={} socks5_config={}",
param.user, param.user,
param.server, param.server,
param.port, param.port,
param.security, param.security,
param.certificate_checks, strict_tls,
param.oauth2, param.oauth2,
if let Some(socks5_config) = socks5_config { if let Some(socks5_config) = socks5_config {
socks5_config.to_string() socks5_config.to_string()
@@ -621,7 +593,7 @@ async fn try_imap_one_param(
let (_s, r) = async_channel::bounded(1); let (_s, r) = async_channel::bounded(1);
let mut imap = match Imap::new(param, socks5_config.clone(), addr, provider_strict_tls, r) { let mut imap = match Imap::new(param, socks5_config.clone(), addr, strict_tls, r) {
Err(err) => { Err(err) => {
info!(context, "failure: {:#}", err); info!(context, "failure: {:#}", err);
return Err(ConfigurationError { return Err(ConfigurationError {
@@ -652,16 +624,16 @@ async fn try_smtp_one_param(
param: &ServerLoginParam, param: &ServerLoginParam,
socks5_config: &Option<Socks5Config>, socks5_config: &Option<Socks5Config>,
addr: &str, addr: &str,
provider_strict_tls: bool, strict_tls: bool,
smtp: &mut Smtp, smtp: &mut Smtp,
) -> Result<(), ConfigurationError> { ) -> Result<(), ConfigurationError> {
let inf = format!( let inf = format!(
"smtp: {}@{}:{} security={} certificate_checks={} oauth2={} socks5_config={}", "smtp: {}@{}:{} security={} strict_tls={} oauth2={} socks5_config={}",
param.user, param.user,
param.server, param.server,
param.port, param.port,
param.security, param.security,
param.certificate_checks, strict_tls,
param.oauth2, param.oauth2,
if let Some(socks5_config) = socks5_config { if let Some(socks5_config) = socks5_config {
socks5_config.to_string() socks5_config.to_string()
@@ -672,7 +644,7 @@ async fn try_smtp_one_param(
info!(context, "Trying: {}", inf); info!(context, "Trying: {}", inf);
if let Err(err) = smtp if let Err(err) = smtp
.connect(context, param, socks5_config, addr, provider_strict_tls) .connect(context, param, socks5_config, addr, strict_tls)
.await .await
{ {
info!(context, "SMTP failure: {err:#}."); info!(context, "SMTP failure: {err:#}.");

View File

@@ -248,7 +248,6 @@ fn parse_serverparams(in_emailaddr: &str, xml_raw: &str) -> Result<Vec<ServerPar
hostname: server.hostname, hostname: server.hostname,
port: server.port, port: server.port,
username: server.username, username: server.username,
strict_tls: None,
}) })
}) })
.collect(); .collect();

View File

@@ -187,7 +187,6 @@ fn protocols_to_serverparams(protocols: Vec<ProtocolTag>) -> Vec<ServerParams> {
hostname: protocol.server, hostname: protocol.server,
port: protocol.port, port: protocol.port,
username: String::new(), username: String::new(),
strict_tls: None,
}) })
}) })
.collect() .collect()

View File

@@ -22,9 +22,6 @@ pub(crate) struct ServerParams {
/// Username, empty if unknown. /// Username, empty if unknown.
pub username: String, pub username: String,
/// Whether TLS certificates should be strictly checked or not, `None` for automatic.
pub strict_tls: Option<bool>,
} }
impl ServerParams { impl ServerParams {
@@ -125,14 +122,6 @@ impl ServerParams {
vec![self] vec![self]
} }
} }
fn expand_strict_tls(self) -> Vec<ServerParams> {
vec![Self {
// Strict if not set by the user or provider database.
strict_tls: Some(self.strict_tls.unwrap_or(true)),
..self
}]
}
} }
/// Expands vector of `ServerParams`, replacing placeholders with /// Expands vector of `ServerParams`, replacing placeholders with
@@ -146,7 +135,6 @@ pub(crate) fn expand_param_vector(
// The order of expansion is important. // The order of expansion is important.
// //
// Ports are expanded the last, so they are changed the first. // Ports are expanded the last, so they are changed the first.
.flat_map(|params| params.expand_strict_tls().into_iter())
.flat_map(|params| params.expand_usernames(addr).into_iter()) .flat_map(|params| params.expand_usernames(addr).into_iter())
.flat_map(|params| params.expand_hostnames(domain).into_iter()) .flat_map(|params| params.expand_hostnames(domain).into_iter())
.flat_map(|params| params.expand_ports().into_iter()) .flat_map(|params| params.expand_ports().into_iter())
@@ -166,7 +154,6 @@ mod tests {
port: 0, port: 0,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true),
}], }],
"foobar@example.net", "foobar@example.net",
"example.net", "example.net",
@@ -180,7 +167,6 @@ mod tests {
port: 993, port: 993,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
}], }],
); );
@@ -191,7 +177,6 @@ mod tests {
port: 123, port: 123,
socket: Socket::Automatic, socket: Socket::Automatic,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: None,
}], }],
"foobar@example.net", "foobar@example.net",
"example.net", "example.net",
@@ -206,7 +191,6 @@ mod tests {
port: 123, port: 123,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true),
}, },
ServerParams { ServerParams {
protocol: Protocol::Smtp, protocol: Protocol::Smtp,
@@ -214,12 +198,10 @@ mod tests {
port: 123, port: 123,
socket: Socket::Starttls, socket: Socket::Starttls,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
}, },
], ],
); );
// Test that strict_tls is not expanded for plaintext connections.
let v = expand_param_vector( let v = expand_param_vector(
vec![ServerParams { vec![ServerParams {
protocol: Protocol::Smtp, protocol: Protocol::Smtp,
@@ -227,7 +209,6 @@ mod tests {
port: 123, port: 123,
socket: Socket::Plain, socket: Socket::Plain,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true),
}], }],
"foobar@example.net", "foobar@example.net",
"example.net", "example.net",
@@ -240,7 +221,6 @@ mod tests {
port: 123, port: 123,
socket: Socket::Plain, socket: Socket::Plain,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
}], }],
); );
@@ -252,7 +232,6 @@ mod tests {
port: 10480, port: 10480,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true),
}], }],
"foobar@example.net", "foobar@example.net",
"example.net", "example.net",
@@ -266,7 +245,6 @@ mod tests {
port: 10480, port: 10480,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
}, },
ServerParams { ServerParams {
protocol: Protocol::Imap, protocol: Protocol::Imap,
@@ -274,7 +252,6 @@ mod tests {
port: 10480, port: 10480,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
}, },
ServerParams { ServerParams {
protocol: Protocol::Imap, protocol: Protocol::Imap,
@@ -282,7 +259,6 @@ mod tests {
port: 10480, port: 10480,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
} }
], ],
); );
@@ -296,7 +272,6 @@ mod tests {
port: 0, port: 0,
socket: Socket::Automatic, socket: Socket::Automatic,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true),
}], }],
"foobar@example.net", "foobar@example.net",
"example.net", "example.net",
@@ -310,7 +285,6 @@ mod tests {
port: 465, port: 465,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
}, },
ServerParams { ServerParams {
protocol: Protocol::Smtp, protocol: Protocol::Smtp,
@@ -318,7 +292,6 @@ mod tests {
port: 587, port: 587,
socket: Socket::Starttls, socket: Socket::Starttls,
username: "foobar".to_string(), username: "foobar".to_string(),
strict_tls: Some(true)
}, },
], ],
); );
@@ -338,7 +311,6 @@ mod tests {
port: 0, port: 0,
socket: Socket::Automatic, socket: Socket::Automatic,
username: "".to_string(), username: "".to_string(),
strict_tls: Some(true),
}], }],
"foobar@example.net", "foobar@example.net",
"example.net", "example.net",
@@ -352,7 +324,6 @@ mod tests {
port: 993, port: 993,
socket: Socket::Ssl, socket: Socket::Ssl,
username: "foobar@example.net".to_string(), username: "foobar@example.net".to_string(),
strict_tls: Some(true)
}, },
ServerParams { ServerParams {
protocol: Protocol::Imap, protocol: Protocol::Imap,
@@ -360,7 +331,6 @@ mod tests {
port: 143, port: 143,
socket: Socket::Starttls, socket: Socket::Starttls,
username: "foobar@example.net".to_string(), username: "foobar@example.net".to_string(),
strict_tls: Some(true)
}, },
], ],
); );

View File

@@ -32,7 +32,7 @@ use crate::contact::{Contact, ContactId, Modifier, Origin};
use crate::context::Context; use crate::context::Context;
use crate::events::EventType; use crate::events::EventType;
use crate::headerdef::{HeaderDef, HeaderDefMap}; use crate::headerdef::{HeaderDef, HeaderDefMap};
use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam}; use crate::login_param::{LoginParam, ServerLoginParam};
use crate::message::{self, Message, MessageState, MessengerMessage, MsgId, Viewtype}; use crate::message::{self, Message, MessageState, MessengerMessage, MsgId, Viewtype};
use crate::mimeparser; use crate::mimeparser;
use crate::oauth2::get_oauth2_access_token; use crate::oauth2::get_oauth2_access_token;
@@ -231,20 +231,13 @@ impl Imap {
lp: &ServerLoginParam, lp: &ServerLoginParam,
socks5_config: Option<Socks5Config>, socks5_config: Option<Socks5Config>,
addr: &str, addr: &str,
provider_strict_tls: bool, strict_tls: bool,
idle_interrupt_receiver: Receiver<()>, idle_interrupt_receiver: Receiver<()>,
) -> Result<Self> { ) -> Result<Self> {
if lp.server.is_empty() || lp.user.is_empty() || lp.password.is_empty() { if lp.server.is_empty() || lp.user.is_empty() || lp.password.is_empty() {
bail!("Incomplete IMAP connection parameters"); bail!("Incomplete IMAP connection parameters");
} }
let strict_tls = match lp.certificate_checks {
CertificateChecks::Automatic => provider_strict_tls,
CertificateChecks::Strict => true,
CertificateChecks::AcceptInvalidCertificates
| CertificateChecks::AcceptInvalidCertificates2 => false,
};
let imap = Imap { let imap = Imap {
idle_interrupt_receiver, idle_interrupt_receiver,
addr: addr.to_string(), addr: addr.to_string(),
@@ -272,17 +265,11 @@ impl Imap {
} }
let param = LoginParam::load_configured_params(context).await?; let param = LoginParam::load_configured_params(context).await?;
// the trailing underscore is correct
let imap = Self::new( let imap = Self::new(
&param.imap, &param.imap,
param.socks5_config.clone(), param.socks5_config.clone(),
&param.addr, &param.addr,
param param.strict_tls(),
.provider
.map_or(param.socks5_config.is_some(), |provider| {
provider.opt.strict_tls
}),
idle_interrupt_receiver, idle_interrupt_receiver,
)?; )?;
Ok(imap) Ok(imap)

View File

@@ -51,10 +51,6 @@ pub struct ServerLoginParam {
pub port: u16, pub port: u16,
pub security: Socket, pub security: Socket,
pub oauth2: bool, pub oauth2: bool,
/// TLS options: whether to allow invalid certificates and/or
/// invalid hostnames
pub certificate_checks: CertificateChecks,
} }
#[derive(Default, Debug, Clone, PartialEq, Eq)] #[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -64,6 +60,10 @@ pub struct LoginParam {
pub smtp: ServerLoginParam, pub smtp: ServerLoginParam,
pub provider: Option<&'static Provider>, pub provider: Option<&'static Provider>,
pub socks5_config: Option<Socks5Config>, pub socks5_config: Option<Socks5Config>,
/// TLS options: whether to allow invalid certificates and/or
/// invalid hostnames
pub certificate_checks: CertificateChecks,
} }
impl LoginParam { impl LoginParam {
@@ -125,8 +125,12 @@ impl LoginParam {
.and_then(num_traits::FromPrimitive::from_i32) .and_then(num_traits::FromPrimitive::from_i32)
.unwrap_or_default(); .unwrap_or_default();
// The setting is named `imap_certificate_checks`
// for backwards compatibility,
// but now it is a global setting applied to all protocols,
// while `smtp_certificate_checks` is ignored.
let key = &format!("{prefix}imap_certificate_checks"); let key = &format!("{prefix}imap_certificate_checks");
let imap_certificate_checks = let certificate_checks =
if let Some(certificate_checks) = sql.get_raw_config_int(key).await? { if let Some(certificate_checks) = sql.get_raw_config_int(key).await? {
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap() num_traits::FromPrimitive::from_i32(certificate_checks).unwrap()
} else { } else {
@@ -152,14 +156,6 @@ impl LoginParam {
.and_then(num_traits::FromPrimitive::from_i32) .and_then(num_traits::FromPrimitive::from_i32)
.unwrap_or_default(); .unwrap_or_default();
let key = &format!("{prefix}smtp_certificate_checks");
let smtp_certificate_checks =
if let Some(certificate_checks) = sql.get_raw_config_int(key).await? {
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap_or_default()
} else {
Default::default()
};
let key = &format!("{prefix}server_flags"); let key = &format!("{prefix}server_flags");
let server_flags = sql.get_raw_config_int(key).await?.unwrap_or_default(); let server_flags = sql.get_raw_config_int(key).await?.unwrap_or_default();
let oauth2 = matches!(server_flags & DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2); let oauth2 = matches!(server_flags & DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2);
@@ -181,7 +177,6 @@ impl LoginParam {
port: mail_port as u16, port: mail_port as u16,
security: mail_security, security: mail_security,
oauth2, oauth2,
certificate_checks: imap_certificate_checks,
}, },
smtp: ServerLoginParam { smtp: ServerLoginParam {
server: send_server, server: send_server,
@@ -190,8 +185,8 @@ impl LoginParam {
port: send_port as u16, port: send_port as u16,
security: send_security, security: send_security,
oauth2, oauth2,
certificate_checks: smtp_certificate_checks,
}, },
certificate_checks,
provider, provider,
socks5_config, socks5_config,
}) })
@@ -222,7 +217,7 @@ impl LoginParam {
.await?; .await?;
let key = &format!("{prefix}imap_certificate_checks"); let key = &format!("{prefix}imap_certificate_checks");
sql.set_raw_config_int(key, self.imap.certificate_checks as i32) sql.set_raw_config_int(key, self.certificate_checks as i32)
.await?; .await?;
let key = &format!("{prefix}send_server"); let key = &format!("{prefix}send_server");
@@ -242,8 +237,9 @@ impl LoginParam {
sql.set_raw_config_int(key, self.smtp.security as i32) sql.set_raw_config_int(key, self.smtp.security as i32)
.await?; .await?;
// This is only saved for compatibility reasons, but never loaded.
let key = &format!("{prefix}smtp_certificate_checks"); let key = &format!("{prefix}smtp_certificate_checks");
sql.set_raw_config_int(key, self.smtp.certificate_checks as i32) sql.set_raw_config_int(key, self.certificate_checks as i32)
.await?; .await?;
// The OAuth2 flag is either set for both IMAP and SMTP or not at all. // The OAuth2 flag is either set for both IMAP and SMTP or not at all.
@@ -260,6 +256,19 @@ impl LoginParam {
Ok(()) Ok(())
} }
pub fn strict_tls(&self) -> bool {
let user_strict_tls = match self.certificate_checks {
CertificateChecks::Automatic => None,
CertificateChecks::Strict => Some(true),
CertificateChecks::AcceptInvalidCertificates
| CertificateChecks::AcceptInvalidCertificates2 => Some(false),
};
let provider_strict_tls = self.provider.map(|provider| provider.opt.strict_tls);
user_strict_tls
.or(provider_strict_tls)
.unwrap_or(self.socks5_config.is_some())
}
} }
impl fmt::Display for LoginParam { impl fmt::Display for LoginParam {
@@ -269,7 +278,7 @@ impl fmt::Display for LoginParam {
write!( write!(
f, f,
"{} imap:{}:{}:{}:{}:{}:cert_{}:{} smtp:{}:{}:{}:{}:{}:cert_{}:{}", "{} imap:{}:{}:{}:{}:{}:{} smtp:{}:{}:{}:{}:{}:{} cert_{}",
unset_empty(&self.addr), unset_empty(&self.addr),
unset_empty(&self.imap.user), unset_empty(&self.imap.user),
if !self.imap.password.is_empty() { if !self.imap.password.is_empty() {
@@ -280,7 +289,6 @@ impl fmt::Display for LoginParam {
unset_empty(&self.imap.server), unset_empty(&self.imap.server),
self.imap.port, self.imap.port,
self.imap.security, self.imap.security,
self.imap.certificate_checks,
if self.imap.oauth2 { if self.imap.oauth2 {
"OAUTH2" "OAUTH2"
} else { } else {
@@ -295,12 +303,12 @@ impl fmt::Display for LoginParam {
unset_empty(&self.smtp.server), unset_empty(&self.smtp.server),
self.smtp.port, self.smtp.port,
self.smtp.security, self.smtp.security,
self.smtp.certificate_checks,
if self.smtp.oauth2 { if self.smtp.oauth2 {
"OAUTH2" "OAUTH2"
} else { } else {
"AUTH_NORMAL" "AUTH_NORMAL"
}, },
self.certificate_checks
) )
} }
} }
@@ -341,7 +349,6 @@ mod tests {
port: 123, port: 123,
security: Socket::Starttls, security: Socket::Starttls,
oauth2: false, oauth2: false,
certificate_checks: CertificateChecks::Strict,
}, },
smtp: ServerLoginParam { smtp: ServerLoginParam {
server: "smtp.example.com".to_string(), server: "smtp.example.com".to_string(),
@@ -350,11 +357,11 @@ mod tests {
port: 456, port: 456,
security: Socket::Ssl, security: Socket::Ssl,
oauth2: false, oauth2: false,
certificate_checks: CertificateChecks::AcceptInvalidCertificates,
}, },
provider: get_provider_by_id("example.com"), provider: get_provider_by_id("example.com"),
// socks5_config is not saved by `save_to_database`, using default value // socks5_config is not saved by `save_to_database`, using default value
socks5_config: None, socks5_config: None,
certificate_checks: CertificateChecks::Strict,
}; };
param.save_as_configured_params(&t).await?; param.save_as_configured_params(&t).await?;

View File

@@ -1405,9 +1405,12 @@ mod tests {
ctx.ctx.get_config(Config::SendUser).await?, ctx.ctx.get_config(Config::SendUser).await?,
Some("SendUser".to_owned()) Some("SendUser".to_owned())
); );
// `sc` option is actually ignored and `ic` is used instead
// because `smtp_certificate_checks` is deprecated.
assert_eq!( assert_eq!(
ctx.ctx.get_config(Config::SmtpCertificateChecks).await?, ctx.ctx.get_config(Config::SmtpCertificateChecks).await?,
Some("3".to_owned()) Some("1".to_owned())
); );
assert_eq!( assert_eq!(
ctx.ctx.get_config(Config::SendSecurity).await?, ctx.ctx.get_config(Config::SendSecurity).await?,

View File

@@ -39,9 +39,6 @@ pub enum LoginOptions {
/// IMAP socket security. /// IMAP socket security.
imap_security: Option<Socket>, imap_security: Option<Socket>,
/// IMAP certificate checks.
imap_certificate_checks: Option<CertificateChecks>,
/// SMTP host. /// SMTP host.
smtp_host: Option<String>, smtp_host: Option<String>,
@@ -57,8 +54,8 @@ pub enum LoginOptions {
/// SMTP socket security. /// SMTP socket security.
smtp_security: Option<Socket>, smtp_security: Option<Socket>,
/// SMTP certificate checks. /// Certificate checks.
smtp_certificate_checks: Option<CertificateChecks>, certificate_checks: Option<CertificateChecks>,
}, },
} }
@@ -107,14 +104,13 @@ pub(super) fn decode_login(qr: &str) -> Result<Qr> {
imap_username: parameter_map.get("iu").map(|s| s.to_owned()), imap_username: parameter_map.get("iu").map(|s| s.to_owned()),
imap_password: parameter_map.get("ipw").map(|s| s.to_owned()), imap_password: parameter_map.get("ipw").map(|s| s.to_owned()),
imap_security: parse_socket_security(parameter_map.get("is"))?, imap_security: parse_socket_security(parameter_map.get("is"))?,
imap_certificate_checks: parse_certificate_checks(parameter_map.get("ic"))?,
smtp_host: parameter_map.get("sh").map(|s| s.to_owned()), smtp_host: parameter_map.get("sh").map(|s| s.to_owned()),
smtp_port: parse_port(parameter_map.get("sp")) smtp_port: parse_port(parameter_map.get("sp"))
.context("could not parse smtp port")?, .context("could not parse smtp port")?,
smtp_username: parameter_map.get("su").map(|s| s.to_owned()), smtp_username: parameter_map.get("su").map(|s| s.to_owned()),
smtp_password: parameter_map.get("spw").map(|s| s.to_owned()), smtp_password: parameter_map.get("spw").map(|s| s.to_owned()),
smtp_security: parse_socket_security(parameter_map.get("ss"))?, smtp_security: parse_socket_security(parameter_map.get("ss"))?,
smtp_certificate_checks: parse_certificate_checks(parameter_map.get("sc"))?, certificate_checks: parse_certificate_checks(parameter_map.get("ic"))?,
}, },
Some(Ok(v)) => LoginOptions::UnsuportedVersion(v), Some(Ok(v)) => LoginOptions::UnsuportedVersion(v),
Some(Err(_)) => bail!("version could not be parsed as number E6"), Some(Err(_)) => bail!("version could not be parsed as number E6"),
@@ -177,13 +173,12 @@ pub(crate) async fn configure_from_login_qr(
imap_username, imap_username,
imap_password, imap_password,
imap_security, imap_security,
imap_certificate_checks,
smtp_host, smtp_host,
smtp_port, smtp_port,
smtp_username, smtp_username,
smtp_password, smtp_password,
smtp_security, smtp_security,
smtp_certificate_checks, certificate_checks,
} => { } => {
context context
.set_config_internal(Config::MailPw, Some(&mail_pw)) .set_config_internal(Config::MailPw, Some(&mail_pw))
@@ -216,14 +211,6 @@ pub(crate) async fn configure_from_login_qr(
.set_config_internal(Config::MailSecurity, Some(&code.to_string())) .set_config_internal(Config::MailSecurity, Some(&code.to_string()))
.await?; .await?;
} }
if let Some(value) = imap_certificate_checks {
let code = value
.to_u32()
.context("could not convert imap certificate checks value to number")?;
context
.set_config_internal(Config::ImapCertificateChecks, Some(&code.to_string()))
.await?;
}
if let Some(value) = smtp_host { if let Some(value) = smtp_host {
context context
.set_config_internal(Config::SendServer, Some(&value)) .set_config_internal(Config::SendServer, Some(&value))
@@ -252,10 +239,13 @@ pub(crate) async fn configure_from_login_qr(
.set_config_internal(Config::SendSecurity, Some(&code.to_string())) .set_config_internal(Config::SendSecurity, Some(&code.to_string()))
.await?; .await?;
} }
if let Some(value) = smtp_certificate_checks { if let Some(value) = certificate_checks {
let code = value let code = value
.to_u32() .to_u32()
.context("could not convert smtp certificate checks value to number")?; .context("could not convert certificate checks value to number")?;
context
.set_config_internal(Config::ImapCertificateChecks, Some(&code.to_string()))
.await?;
context context
.set_config_internal(Config::SmtpCertificateChecks, Some(&code.to_string())) .set_config_internal(Config::SmtpCertificateChecks, Some(&code.to_string()))
.await?; .await?;
@@ -284,13 +274,12 @@ mod test {
imap_username: None, imap_username: None,
imap_password: None, imap_password: None,
imap_security: None, imap_security: None,
imap_certificate_checks: None,
smtp_host: None, smtp_host: None,
smtp_port: None, smtp_port: None,
smtp_username: None, smtp_username: None,
smtp_password: None, smtp_password: None,
smtp_security: None, smtp_security: None,
smtp_certificate_checks: None, certificate_checks: None,
} }
}; };
} }
@@ -392,13 +381,12 @@ mod test {
imap_username: Some("max".to_owned()), imap_username: Some("max".to_owned()),
imap_password: Some("87654".to_owned()), imap_password: Some("87654".to_owned()),
imap_security: Some(Socket::Ssl), imap_security: Some(Socket::Ssl),
imap_certificate_checks: Some(CertificateChecks::Strict),
smtp_host: Some("mail.host.tld".to_owned()), smtp_host: Some("mail.host.tld".to_owned()),
smtp_port: Some(3000), smtp_port: Some(3000),
smtp_username: Some("max@host.tld".to_owned()), smtp_username: Some("max@host.tld".to_owned()),
smtp_password: Some("3242HS".to_owned()), smtp_password: Some("3242HS".to_owned()),
smtp_security: Some(Socket::Plain), smtp_security: Some(Socket::Plain),
smtp_certificate_checks: Some(CertificateChecks::AcceptInvalidCertificates), certificate_checks: Some(CertificateChecks::Strict),
} }
); );
} else { } else {

View File

@@ -13,7 +13,7 @@ use crate::config::Config;
use crate::contact::{Contact, ContactId}; use crate::contact::{Contact, ContactId};
use crate::context::Context; use crate::context::Context;
use crate::events::EventType; use crate::events::EventType;
use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam}; use crate::login_param::{LoginParam, ServerLoginParam};
use crate::message::Message; use crate::message::Message;
use crate::message::{self, MsgId}; use crate::message::{self, MsgId};
use crate::mimefactory::MimeFactory; use crate::mimefactory::MimeFactory;
@@ -94,9 +94,7 @@ impl Smtp {
&lp.smtp, &lp.smtp,
&lp.socks5_config, &lp.socks5_config,
&lp.addr, &lp.addr,
lp.provider.map_or(lp.socks5_config.is_some(), |provider| { lp.strict_tls(),
provider.opt.strict_tls
}),
) )
.await .await
} }
@@ -108,7 +106,7 @@ impl Smtp {
lp: &ServerLoginParam, lp: &ServerLoginParam,
socks5_config: &Option<Socks5Config>, socks5_config: &Option<Socks5Config>,
addr: &str, addr: &str,
provider_strict_tls: bool, strict_tls: bool,
) -> Result<()> { ) -> Result<()> {
if self.is_connected() { if self.is_connected() {
warn!(context, "SMTP already connected."); warn!(context, "SMTP already connected.");
@@ -127,13 +125,6 @@ impl Smtp {
let domain = &lp.server; let domain = &lp.server;
let port = lp.port; let port = lp.port;
let strict_tls = match lp.certificate_checks {
CertificateChecks::Automatic => provider_strict_tls,
CertificateChecks::Strict => true,
CertificateChecks::AcceptInvalidCertificates
| CertificateChecks::AcceptInvalidCertificates2 => false,
};
let session_stream = connect::connect_stream( let session_stream = connect::connect_stream(
context, context,
domain, domain,