Skip to content

Commit bd6e308

Browse files
committed
refactor: improve sasl config
1 parent 942e293 commit bd6e308

6 files changed

Lines changed: 48 additions & 35 deletions

File tree

‎Cargo.lock‎

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎config.sample.toml‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,10 @@ imap.server = "imaps://imap.example.org"
7373
# to skip authentication entirely (no `AUTHENTICATE` command sent).
7474

7575
# SASL PLAIN (https://www.iana.org/go/rfc4616)
76-
imap.sasl.plain.authcid = "user@example.org"
77-
imap.sasl.plain.passwd.raw = "REPLACE_ME"
76+
imap.sasl.plain.username = "user@example.org"
77+
imap.sasl.plain.password.raw = "REPLACE_ME"
7878
#imap.sasl.plain.authzid = "user@example.org" # optional authorization identity
79-
#imap.sasl.plain.passwd.command = "pass show mirador/example"
80-
#imap.sasl.plain.passwd.command = ["secret-tool", "lookup", "service", "mirador-example"]
79+
#imap.sasl.plain.password.command = "pass show mirador/example"
8180

8281
# SASL LOGIN (https://datatracker.ietf.org/doc/html/draft-murchison-sasl-login-00)
8382
#imap.sasl.login.username = "user@example.org"
@@ -86,11 +85,9 @@ imap.sasl.plain.passwd.raw = "REPLACE_ME"
8685
# SASL ANONYMOUS (https://www.iana.org/go/rfc4505)
8786
#imap.sasl.anonymous.message = "mirador"
8887

89-
# SASL OAUTHBEARER (https://www.iana.org/go/rfc7628). Host/port are echoed
90-
# verbatim in the GS2 header; usually mirror the server you connect to.
88+
# SASL OAUTHBEARER (https://www.iana.org/go/rfc7628). Host/port for the
89+
# GS2 header are derived from the IMAP server URL at connect time.
9190
#imap.sasl.oauthbearer.username = "user@example.org"
92-
#imap.sasl.oauthbearer.host = "imap.example.org"
93-
#imap.sasl.oauthbearer.port = 993
9491
#imap.sasl.oauthbearer.token.command = ["ortie", "token", "read", "example"]
9592

9693
# SASL XOAUTH2 (Google's pre-standard OAuth 2.0 SASL).

‎deny.toml‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
allow-git = [
33
"https://github.com/pimalaya/cli",
44
"https://github.com/pimalaya/config",
5-
"https://github.com/pimalaya/io-discovery",
65
"https://github.com/pimalaya/io-email",
76
"https://github.com/pimalaya/io-http",
87
"https://github.com/pimalaya/io-imap",

‎src/check.rs‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,16 @@ fn check_imap(
108108
let result = (|| -> Result<()> {
109109
let mut tls: Tls = imap_config.tls.clone().into();
110110
tls.rustls.alpn = vec!["imap".into()];
111-
let sasl: Option<Sasl> = imap_config.sasl.clone().map(Sasl::try_from).transpose()?;
112111
let server = crate::client::parse_imap_server(&imap_config.server)?;
112+
let sasl: Option<Sasl> = imap_config
113+
.sasl
114+
.clone()
115+
.and_then(|cfg| {
116+
let host = server.host_str()?;
117+
let port = server.port_or_known_default()?;
118+
Some(cfg.try_into_sasl(host, port))
119+
})
120+
.transpose()?;
113121
let _ = ImapClientStd::connect(&server, &tls, imap_config.starttls, sasl)?;
114122
Ok(())
115123
})();

‎src/client.rs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,15 @@ pub fn open(account: AccountConfig, backend: Backend) -> Result<EmailClientStd>
8787
fn open_imap(config: crate::config::ImapConfig) -> Result<EmailClientStd> {
8888
let mut tls: Tls = config.tls.into();
8989
tls.rustls.alpn = vec!["imap".into()];
90-
let sasl: Option<Sasl> = config.sasl.map(Sasl::try_from).transpose()?;
9190
let server = parse_imap_server(&config.server)?;
91+
let sasl: Option<Sasl> = config
92+
.sasl
93+
.and_then(|cfg| {
94+
let host = server.host_str()?;
95+
let port = server.port_or_known_default()?;
96+
Some(cfg.try_into_sasl(host, port))
97+
})
98+
.transpose()?;
9299

93100
let mut client = EmailClientStd::new().connect_imap(&server, &tls, config.starttls, sasl)?;
94101
if let Some(imap) = client.imap.as_mut() {

‎src/config.rs‎

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,9 @@ pub struct SaslLoginConfig {
283283
pub struct SaslPlainConfig {
284284
pub authzid: Option<String>,
285285
#[serde(deserialize_with = "pimalaya_config::toml::shell_expanded_string")]
286+
#[serde(alias = "username")]
286287
pub authcid: String,
288+
#[serde(alias = "password")]
287289
pub passwd: Secret,
288290
}
289291

@@ -293,8 +295,6 @@ pub struct SaslPlainConfig {
293295
pub struct SaslOauthbearerConfig {
294296
#[serde(deserialize_with = "pimalaya_config::toml::shell_expanded_string")]
295297
pub username: String,
296-
pub host: String,
297-
pub port: u16,
298298
pub token: Secret,
299299
}
300300

@@ -317,11 +317,13 @@ pub struct SaslScramSha256Config {
317317
}
318318

319319
#[cfg(feature = "imap")]
320-
impl TryFrom<SaslConfig> for Sasl {
321-
type Error = anyhow::Error;
322-
323-
fn try_from(config: SaslConfig) -> Result<Self, Self::Error> {
324-
Ok(match config {
320+
impl SaslConfig {
321+
/// Resolves the SASL config into a runtime [`Sasl`]. `host` and
322+
/// `port` come from the live server URL; they are only used by
323+
/// OAUTHBEARER (echoed in the GS2 header) and ignored by every
324+
/// other mechanism.
325+
pub fn try_into_sasl(self, host: impl ToString, port: u16) -> Result<Sasl> {
326+
Ok(match self {
325327
SaslConfig::Anonymous(c) => Sasl::Anonymous(SaslAnonymous { message: c.message }),
326328
SaslConfig::Login(c) => Sasl::Login(SaslLogin {
327329
username: c.username,
@@ -334,8 +336,8 @@ impl TryFrom<SaslConfig> for Sasl {
334336
}),
335337
SaslConfig::Oauthbearer(c) => Sasl::Oauthbearer(SaslOauthbearer {
336338
username: c.username,
337-
host: c.host,
338-
port: c.port,
339+
host: host.to_string(),
340+
port,
339341
token: c.token.get()?,
340342
}),
341343
SaslConfig::Xoauth2(c) => Sasl::Xoauth2(SaslXoauth2 {

0 commit comments

Comments
 (0)