From c5034324d21d70bcb96cbedea426de75dcae127d Mon Sep 17 00:00:00 2001 From: Alexis Mousset Date: Sat, 17 Jun 2017 16:05:59 +0200 Subject: [PATCH] style(all): Fix LOGIN auth detection and improve response tests --- lettre/src/smtp/extension.rs | 6 +- lettre/src/smtp/mod.rs | 8 +-- lettre/src/smtp/response.rs | 109 ++++++++++++++++++++++++++++++++--- 3 files changed, 110 insertions(+), 13 deletions(-) diff --git a/lettre/src/smtp/extension.rs b/lettre/src/smtp/extension.rs index f797187..00d71c6 100644 --- a/lettre/src/smtp/extension.rs +++ b/lettre/src/smtp/extension.rs @@ -67,7 +67,7 @@ impl Display for ServerInfo { } impl ServerInfo { - /// Parses a response to create a `ServerInfo` + /// Parses a EHLO response to create a `ServerInfo` pub fn from_response(response: &Response) -> Result { let name = match response.first_word() { Some(name) => name, @@ -77,7 +77,6 @@ impl ServerInfo { let mut features: HashSet = HashSet::new(); for line in response.message() { - let splitted: Vec<&str> = line.split_whitespace().collect(); match splitted[0] { "8BITMIME" => { @@ -95,6 +94,9 @@ impl ServerInfo { "PLAIN" => { features.insert(Extension::Authentication(Mechanism::Plain)); } + "LOGIN" => { + features.insert(Extension::Authentication(Mechanism::Login)); + } "CRAM-MD5" => { features.insert(Extension::Authentication(Mechanism::CramMd5)); } diff --git a/lettre/src/smtp/mod.rs b/lettre/src/smtp/mod.rs index e0b5d8e..1760d7a 100644 --- a/lettre/src/smtp/mod.rs +++ b/lettre/src/smtp/mod.rs @@ -156,13 +156,13 @@ pub enum SecurityLevel { EncryptedWrapper, /// Only send an email on encrypted connection (with STARTTLS) /// - /// Recommended mode, prevents MITM when used with verified certificates. + /// Default mode, prevents MITM when used with verified certificates. AlwaysEncrypt, /// Use TLS when available (with STARTTLS) /// - /// Default mode. + /// Should be used when not possible to always encrypt the connection Opportunistic, - /// Never use TLS + /// Never use encryption NeverEncrypt, } @@ -460,7 +460,7 @@ impl EmailTransport for SmtpTransport { // Login is obsolete so try it last vec![Mechanism::Plain, Mechanism::CramMd5, Mechanism::Login] } else { - // If not encrypted, do not allow clear-text passwords + // If not encrypted, do not allow clear-text passwords by default vec![Mechanism::CramMd5] } } diff --git a/lettre/src/smtp/response.rs b/lettre/src/smtp/response.rs index 6059ff0..9526637 100644 --- a/lettre/src/smtp/response.rs +++ b/lettre/src/smtp/response.rs @@ -150,6 +150,10 @@ impl FromStr for Code { impl Code { /// Creates a new `Code` structure pub fn new(severity: Severity, category: Category, detail: u8) -> Code { + if detail > 9 { + panic!("The detail code must be between 0 and 9"); + } + Code { severity: severity, category: category, @@ -174,7 +178,7 @@ impl ResponseParser { if line.len() < 3 { return Err(Error::ResponseParsing( - "Wrong code length (should be 3 digit)", + "Incorrect response code (should be 3 digits)", )); } @@ -283,13 +287,9 @@ impl Response { } } - /// Returns only the line word of the message if possible + /// Returns only the line of the message if possible pub fn first_line(&self) -> Option<&str> { - if self.message.is_empty() { - None - } else { - Some(&self.message[0]) - } + self.message.first().map(String::as_str) } } @@ -308,6 +308,7 @@ mod test { Severity::TransientNegativeCompletion ); assert!("1".parse::().is_err()); + assert!("51".parse::().is_err()); } #[test] @@ -343,6 +344,16 @@ mod test { ); } + #[test] + #[should_panic] + fn test_code_new_panic() { + let _ = Code::new( + Severity::TransientNegativeCompletion, + Category::Connections, + 11, + ); + } + #[test] fn test_code_from_str() { assert_eq!( @@ -353,6 +364,12 @@ mod test { detail: 1, } ); + assert!("2222".parse::().is_err()); + assert!("aaa".parse::().is_err()); + assert!("-32".parse::().is_err()); + assert!("-333".parse::().is_err()); + assert!("".parse::().is_err()); + assert!("292".parse::().is_err()); } #[test] @@ -707,4 +724,82 @@ mod test { None ); } + + #[test] + fn test_response_first_line() { + assert_eq!( + Response::new( + Code { + severity: "2".parse::().unwrap(), + category: "4".parse::().unwrap(), + detail: 1, + }, + vec![ + "me".to_string(), + "8BITMIME".to_string(), + "SIZE 42".to_string(), + ], + ).first_line(), + Some("me") + ); + assert_eq!( + Response::new( + Code { + severity: "2".parse::().unwrap(), + category: "4".parse::().unwrap(), + detail: 1, + }, + vec![ + "me mo".to_string(), + "8BITMIME".to_string(), + "SIZE 42".to_string(), + ], + ).first_line(), + Some("me mo") + ); + assert_eq!( + Response::new( + Code { + severity: "2".parse::().unwrap(), + category: "4".parse::().unwrap(), + detail: 1, + }, + vec![], + ).first_line(), + None + ); + assert_eq!( + Response::new( + Code { + severity: "2".parse::().unwrap(), + category: "4".parse::().unwrap(), + detail: 1, + }, + vec![" ".to_string()], + ).first_line(), + Some(" ") + ); + assert_eq!( + Response::new( + Code { + severity: "2".parse::().unwrap(), + category: "4".parse::().unwrap(), + detail: 1, + }, + vec![" ".to_string()], + ).first_line(), + Some(" ") + ); + assert_eq!( + Response::new( + Code { + severity: "2".parse::().unwrap(), + category: "4".parse::().unwrap(), + detail: 1, + }, + vec!["".to_string()], + ).first_line(), + Some("") + ); + } }