Adding initial work for authentication

This commit is contained in:
Matt McCoy 2016-06-26 22:40:15 -04:00
parent a9d59209e3
commit 8653a02b87
5 changed files with 52 additions and 3 deletions

3
src/authenticator.rs Normal file
View file

@ -0,0 +1,3 @@
pub trait Authenticator {
fn process(&self, String) -> String;
}

View file

@ -3,7 +3,8 @@ use openssl::ssl::{SslContext, SslStream};
use std::io::{self, Read, Write};
use super::mailbox::Mailbox;
use super::parse::{parse_response_ok, parse_capability, parse_select_or_examine, parse_response};
use super::authenticator::Authenticator;
use super::parse::{parse_response_ok, parse_capability, parse_select_or_examine, parse_response, parse_authenticate_response};
use super::error::{Error, Result};
static TAG_PREFIX: &'static str = "a";
@ -59,6 +60,32 @@ impl<T: Read+Write> Client<T> {
}
}
pub fn authenticate<A: Authenticator>(&mut self, auth_type: &str, authenticator: A) -> Result<()> {
match self.run_command(&format!("AUTHENTICATE {}\r\n", auth_type).to_string()) {
Ok(lines) => {
// TODO test this for the many authentication use cases
let data = match parse_authenticate_response(lines) {
Ok(d) => d,
Err(e) => return Err(e)
};
let auth_response = authenticator.process(data);
match self.stream.write_all(auth_response.into_bytes().as_slice()) {
Err(e) => return Err(Error::Io(e)),
_ => {}
};
match self.stream.write(vec![0x0d, 0x0a].as_slice()) {
Err(e) => return Err(Error::Io(e)),
_ => {}
};
match self.read_response() {
Ok(_) => Ok(()),
Err(e) => return Err(e)
}
},
Err(e) => Err(e)
}
}
/// Log in to the IMAP server.
pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())

View file

@ -69,7 +69,9 @@ pub enum ParseError {
// Indicates an error parsing the status response. Such as OK, NO, and BAD.
StatusResponse(Vec<String>),
// Error parsing the cabability response.
Capability(Vec<String>)
Capability(Vec<String>),
// Authentication errors.
Authentication(Vec<String>)
}
impl fmt::Display for ParseError {
@ -84,7 +86,8 @@ impl StdError for ParseError {
fn description(&self) -> &str {
match *self {
ParseError::StatusResponse(_) => "Unable to parse status response",
ParseError::Capability(_) => "Unable to parse capability response"
ParseError::Capability(_) => "Unable to parse capability response",
ParseError::Authentication(_) => "Unable to parse authentication response"
}
}

View file

@ -6,6 +6,7 @@
extern crate openssl;
extern crate regex;
pub mod authenticator;
pub mod client;
pub mod error;
pub mod mailbox;

View file

@ -3,6 +3,21 @@ use regex::Regex;
use super::mailbox::Mailbox;
use super::error::{Error, ParseError, Result};
pub fn parse_authenticate_response(lines: Vec<String>) -> Result<String> {
let authenticate_regex = Regex::new("^+ (.*)\r\n").unwrap();
let last_line = match lines.last() {
Some(l) => l,
None => return Err(Error::Parse(ParseError::Authentication(lines.clone())))
};
for cap in authenticate_regex.captures_iter(last_line) {
let data = cap.at(1).unwrap_or("");
return Ok(String::from(data));
}
Err(Error::Parse(ParseError::Authentication(lines.clone())))
}
pub fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
let capability_regex = Regex::new(r"^\* CAPABILITY (.*)\r\n").unwrap();