summaryrefslogtreecommitdiffstats
path: root/melib
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-11-30 03:25:57 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-11-30 06:52:16 +0200
commit453bb0b2b2c4eaf20de59844217e00024ce077bb (patch)
treea0b7851269cfee64efba89dc96665d582ad71505 /melib
parent4914f29e20d14b323032fe46b77bc803dcd48624 (diff)
melib/smtp: implement gmail XOAUTH2 authentication method
Diffstat (limited to 'melib')
-rw-r--r--melib/src/smtp.rs44
1 files changed, 43 insertions, 1 deletions
diff --git a/melib/src/smtp.rs b/melib/src/smtp.rs
index 6c14e63c..5246a440 100644
--- a/melib/src/smtp.rs
+++ b/melib/src/smtp.rs
@@ -140,6 +140,12 @@ pub enum SmtpAuth {
#[serde(skip_serializing, skip_deserializing, default)]
auth_type: SmtpAuthType,
},
+ #[serde(alias = "xoauth2")]
+ XOAuth2 {
+ token_command: String,
+ #[serde(default = "true_val")]
+ require_auth: bool,
+ },
// md5, sasl, etc
}
@@ -162,7 +168,7 @@ impl SmtpAuth {
use SmtpAuth::*;
match self {
None => false,
- Auto { require_auth, .. } => *require_auth,
+ Auto { require_auth, .. } | XOAuth2 { require_auth, .. } => *require_auth,
}
}
}
@@ -505,6 +511,39 @@ impl SmtpConnection {
.chain_err_kind(crate::error::ErrorKind::Authentication)?;
ret.send_command(&[b"EHLO meli.delivery"]).await?;
}
+ SmtpAuth::XOAuth2 { token_command, .. } => {
+ let password_token = {
+ let _token_command = token_command.clone();
+ let mut output = unblock(move || {
+ Command::new("sh")
+ .args(&["-c", &_token_command])
+ .stdin(std::process::Stdio::piped())
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped())
+ .output()
+ })
+ .await?;
+ if !output.status.success() {
+ return Err(MeliError::new(format!(
+ "SMTP XOAUTH2 token evaluation command `{}` returned {}: {}",
+ &token_command,
+ output.status,
+ String::from_utf8_lossy(&output.stderr)
+ )));
+ }
+ if output.stdout.ends_with(b"\n") {
+ output.stdout.pop();
+ }
+ output.stdout
+ };
+ // https://developers.google.com/gmail/imap/xoauth2-protocol#smtp_protocol_exchange
+ ret.send_command(&[b"AUTH XOAUTH2 ", &password_token])
+ .await?;
+ ret.read_lines(&mut res, Some((ReplyCode::_235, &[])))
+ .await
+ .chain_err_kind(crate::error::ErrorKind::Authentication)?;
+ ret.send_command(&[b"EHLO meli.delivery"]).await?;
+ }
}
{
let extensions_reply = ret
@@ -966,6 +1005,9 @@ async fn read_lines<'r>(
}
}
}
+ if ret.len() < 3 {
+ return Err(MeliError::new(format!("Invalid SMTP reply: {}", ret)));
+ }
let code = ReplyCode::try_from(&ret[..3])?;
let reply = Reply::new(ret, code);
//debug!(&reply);