Adding initial work for authentication
This commit is contained in:
parent
a9d59209e3
commit
8653a02b87
5 changed files with 52 additions and 3 deletions
3
src/authenticator.rs
Normal file
3
src/authenticator.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub trait Authenticator {
|
||||||
|
fn process(&self, String) -> String;
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,8 @@ use openssl::ssl::{SslContext, SslStream};
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
use super::mailbox::Mailbox;
|
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};
|
use super::error::{Error, Result};
|
||||||
|
|
||||||
static TAG_PREFIX: &'static str = "a";
|
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.
|
/// Log in to the IMAP server.
|
||||||
pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
|
pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
|
||||||
self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
|
self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,9 @@ pub enum ParseError {
|
||||||
// Indicates an error parsing the status response. Such as OK, NO, and BAD.
|
// Indicates an error parsing the status response. Such as OK, NO, and BAD.
|
||||||
StatusResponse(Vec<String>),
|
StatusResponse(Vec<String>),
|
||||||
// Error parsing the cabability response.
|
// Error parsing the cabability response.
|
||||||
Capability(Vec<String>)
|
Capability(Vec<String>),
|
||||||
|
// Authentication errors.
|
||||||
|
Authentication(Vec<String>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ParseError {
|
impl fmt::Display for ParseError {
|
||||||
|
|
@ -84,7 +86,8 @@ impl StdError for ParseError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
ParseError::StatusResponse(_) => "Unable to parse status response",
|
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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
extern crate openssl;
|
extern crate openssl;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
|
pub mod authenticator;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod mailbox;
|
pub mod mailbox;
|
||||||
|
|
|
||||||
15
src/parse.rs
15
src/parse.rs
|
|
@ -3,6 +3,21 @@ use regex::Regex;
|
||||||
use super::mailbox::Mailbox;
|
use super::mailbox::Mailbox;
|
||||||
use super::error::{Error, ParseError, Result};
|
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>> {
|
pub fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
|
||||||
let capability_regex = Regex::new(r"^\* CAPABILITY (.*)\r\n").unwrap();
|
let capability_regex = Regex::new(r"^\* CAPABILITY (.*)\r\n").unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue