Ensures that some operations don't accept invalid data.
Invalid characters in input strings are \r and \n, according to RFC3501 section 4.3.
This commit is contained in:
parent
c899986685
commit
5acf34c3b4
2 changed files with 79 additions and 6 deletions
|
|
@ -8,7 +8,7 @@ use super::mailbox::Mailbox;
|
|||
use super::authenticator::Authenticator;
|
||||
use super::parse::{parse_authenticate_response, parse_capability, parse_response,
|
||||
parse_response_ok, parse_select_or_examine};
|
||||
use super::error::{Error, Result, ParseError};
|
||||
use super::error::{Error, Result, ParseError, ValidateError};
|
||||
|
||||
static TAG_PREFIX: &'static str = "a";
|
||||
const INITIAL_TAG: u32 = 0;
|
||||
|
|
@ -21,6 +21,17 @@ macro_rules! quote {
|
|||
)
|
||||
}
|
||||
|
||||
fn validate_str(value: &str) -> Result<String> {
|
||||
let quoted = quote!(value);
|
||||
if let Some(_) = quoted.find("\n") {
|
||||
return Err(Error::Validate(ValidateError('\n')));
|
||||
}
|
||||
if let Some(_) = quoted.find("\r") {
|
||||
return Err(Error::Validate(ValidateError('\r')));
|
||||
}
|
||||
Ok(quoted)
|
||||
}
|
||||
|
||||
/// Stream to interface with the IMAP server. This interface is only for the command stream.
|
||||
#[derive(Debug)]
|
||||
pub struct Client<T: Read + Write> {
|
||||
|
|
@ -284,18 +295,22 @@ impl<T: Read + Write> Client<T> {
|
|||
|
||||
/// Log in to the IMAP server.
|
||||
pub fn login(&mut self, username: &str, password: &str) -> Result<()> {
|
||||
self.run_command_and_check_ok(&format!("LOGIN {} {}", quote!(username), quote!(password)))
|
||||
self.run_command_and_check_ok(&format!(
|
||||
"LOGIN {} {}",
|
||||
validate_str(username)?,
|
||||
validate_str(password)?
|
||||
))
|
||||
}
|
||||
|
||||
/// Selects a mailbox
|
||||
pub fn select(&mut self, mailbox_name: &str) -> Result<Mailbox> {
|
||||
let lines = try!(self.run_command_and_read_response(&format!("SELECT {}", quote!(mailbox_name))));
|
||||
let lines = try!(self.run_command_and_read_response(&format!("SELECT {}", validate_str(mailbox_name)?)));
|
||||
parse_select_or_examine(lines)
|
||||
}
|
||||
|
||||
/// Examine is identical to Select, but the selected mailbox is identified as read-only
|
||||
pub fn examine(&mut self, mailbox_name: &str) -> Result<Mailbox> {
|
||||
let lines = try!(self.run_command_and_read_response(&format!("EXAMINE {}", quote!(mailbox_name))));
|
||||
let lines = try!(self.run_command_and_read_response(&format!("EXAMINE {}", validate_str(mailbox_name)?)));
|
||||
parse_select_or_examine(lines)
|
||||
}
|
||||
|
||||
|
|
@ -320,12 +335,12 @@ impl<T: Read + Write> Client<T> {
|
|||
|
||||
/// Create creates a mailbox with the given name.
|
||||
pub fn create(&mut self, mailbox_name: &str) -> Result<()> {
|
||||
self.run_command_and_check_ok(&format!("CREATE {}", quote!(mailbox_name)))
|
||||
self.run_command_and_check_ok(&format!("CREATE {}", validate_str(mailbox_name)?))
|
||||
}
|
||||
|
||||
/// Delete permanently removes the mailbox with the given name.
|
||||
pub fn delete(&mut self, mailbox_name: &str) -> Result<()> {
|
||||
self.run_command_and_check_ok(&format!("DELETE {}", quote!(mailbox_name)))
|
||||
self.run_command_and_check_ok(&format!("DELETE {}", validate_str(mailbox_name)?))
|
||||
}
|
||||
|
||||
/// Rename changes the name of a mailbox.
|
||||
|
|
@ -926,4 +941,37 @@ mod tests {
|
|||
fn quote_dquote() {
|
||||
assert_eq!("\"test\\\"text\"", quote!("test\"text"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_random() {
|
||||
assert_eq!("\"~iCQ_k;>[&\\\"sVCvUW`e<<P!wJ\"",
|
||||
&validate_str("~iCQ_k;>[&\"sVCvUW`e<<P!wJ").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_newline() {
|
||||
if let Err(ref e) = validate_str("test\nstring") {
|
||||
if let &Error::Validate(ref ve) = e {
|
||||
if ve.0 == '\n' {
|
||||
return;
|
||||
}
|
||||
}
|
||||
panic!("Wrong error: {:?}", e);
|
||||
}
|
||||
panic!("No error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn validate_carriage_return() {
|
||||
if let Err(ref e) = validate_str("test\rstring") {
|
||||
if let &Error::Validate(ref ve) = e {
|
||||
if ve.0 == '\r' {
|
||||
return;
|
||||
}
|
||||
}
|
||||
panic!("Wrong error: {:?}", e);
|
||||
}
|
||||
panic!("No error");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/error.rs
25
src/error.rs
|
|
@ -28,6 +28,8 @@ pub enum Error {
|
|||
ConnectionLost,
|
||||
// Error parsing a server response.
|
||||
Parse(ParseError),
|
||||
// Error validating input data
|
||||
Validate(ValidateError),
|
||||
// Error appending a mail
|
||||
Append,
|
||||
}
|
||||
|
|
@ -62,6 +64,7 @@ impl fmt::Display for Error {
|
|||
Error::Io(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::Tls(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::TlsHandshake(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::Validate(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::BadResponse(ref data) => {
|
||||
write!(f, "{}: {}", &String::from(self.description()), &data.join("\n"))
|
||||
}
|
||||
|
|
@ -77,6 +80,7 @@ impl StdError for Error {
|
|||
Error::Tls(ref e) => e.description(),
|
||||
Error::TlsHandshake(ref e) => e.description(),
|
||||
Error::Parse(ref e) => e.description(),
|
||||
Error::Validate(ref e) => e.description(),
|
||||
Error::BadResponse(_) => "Bad Response",
|
||||
Error::NoResponse(_) => "No Response",
|
||||
Error::ConnectionLost => "Connection lost",
|
||||
|
|
@ -130,3 +134,24 @@ impl StdError for ParseError {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid character found. Expand as needed
|
||||
#[derive(Debug)]
|
||||
pub struct ValidateError(pub char);
|
||||
|
||||
impl fmt::Display for ValidateError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// print character in debug form because invalid ones are often whitespaces
|
||||
write!(f, "{}: {:?}", self.description(), self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for ValidateError {
|
||||
fn description(&self) -> &str {
|
||||
"Invalid character in input"
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue