parent
c81e3caf17
commit
f4c6e4ab3d
@ -0,0 +1,182 @@ |
||||
use crate::{Error, Error::*, Result}; |
||||
use crypto::{digest::Digest, md5::Md5, sha2::Sha256, sha2::Sha512Trunc256}; |
||||
use std::fmt; |
||||
use std::fmt::{Display, Formatter}; |
||||
use std::str::FromStr; |
||||
|
||||
/// Algorithm type
|
||||
#[derive(Debug, PartialEq)] |
||||
#[allow(non_camel_case_types)] |
||||
pub enum AlgorithmType { |
||||
MD5, |
||||
SHA2_256, |
||||
SHA2_512_256, |
||||
} |
||||
|
||||
/// Algorithm and the -sess flag pair
|
||||
#[derive(Debug, PartialEq)] |
||||
pub struct Algorithm { |
||||
pub algo: AlgorithmType, |
||||
pub sess: bool, |
||||
} |
||||
|
||||
impl Algorithm { |
||||
/// Compose from algorithm type and the -sess flag
|
||||
pub fn new(algo: AlgorithmType, sess: bool) -> Algorithm { |
||||
Algorithm { algo, sess } |
||||
} |
||||
|
||||
/// Calculate a hash of bytes using the selected algorithm
|
||||
pub fn hash(&self, bytes: &[u8]) -> String { |
||||
let mut hash: Box<dyn Digest> = match self.algo { |
||||
AlgorithmType::MD5 => Box::new(Md5::new()), |
||||
AlgorithmType::SHA2_256 => Box::new(Sha256::new()), |
||||
AlgorithmType::SHA2_512_256 => Box::new(Sha512Trunc256::new()), |
||||
}; |
||||
|
||||
hash.input(bytes); |
||||
hash.result_str() |
||||
} |
||||
|
||||
/// Calculate a hash of string's bytes using the selected algorithm
|
||||
pub fn hash_str(&self, bytes: &str) -> String { |
||||
self.hash(bytes.as_bytes()) |
||||
} |
||||
} |
||||
|
||||
impl FromStr for Algorithm { |
||||
type Err = Error; |
||||
|
||||
/// Parse from the format used in WWW-Authorization
|
||||
fn from_str(s: &str) -> Result<Self> { |
||||
match s { |
||||
"MD5" => Ok(Algorithm::new(AlgorithmType::MD5, false)), |
||||
"MD5-sess" => Ok(Algorithm::new(AlgorithmType::MD5, true)), |
||||
"SHA-256" => Ok(Algorithm::new(AlgorithmType::SHA2_256, false)), |
||||
"SHA-256-sess" => Ok(Algorithm::new(AlgorithmType::SHA2_256, true)), |
||||
"SHA-512-256" => Ok(Algorithm::new(AlgorithmType::SHA2_512_256, false)), |
||||
"SHA-512-256-sess" => Ok(Algorithm::new(AlgorithmType::SHA2_512_256, true)), |
||||
_ => Err(UnknownAlgorithm(s.into())), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Default for Algorithm { |
||||
/// Get a MD5 instance
|
||||
fn default() -> Self { |
||||
Algorithm::new(AlgorithmType::MD5, false) |
||||
} |
||||
} |
||||
|
||||
impl Display for Algorithm { |
||||
/// Format to the form used in HTTP headers
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
||||
f.write_str(match self.algo { |
||||
AlgorithmType::MD5 => "MD5", |
||||
AlgorithmType::SHA2_256 => "SHA-256", |
||||
AlgorithmType::SHA2_512_256 => "SHA-512-256", |
||||
})?; |
||||
|
||||
if self.sess { |
||||
f.write_str("-sess")?; |
||||
} |
||||
|
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
/// QOP field values
|
||||
#[derive(Debug, PartialEq)] |
||||
#[allow(non_camel_case_types)] |
||||
pub enum Qop { |
||||
AUTH, |
||||
AUTH_INT, |
||||
} |
||||
|
||||
impl FromStr for Qop { |
||||
type Err = Error; |
||||
|
||||
/// Parse from "auth" or "auth-int" as used in HTTP headers
|
||||
fn from_str(s: &str) -> Result<Self> { |
||||
match s { |
||||
"auth" => Ok(Qop::AUTH), |
||||
"auth-int" => Ok(Qop::AUTH_INT), |
||||
_ => Err(BadQop(s.into())), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Display for Qop { |
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
||||
f.write_str(match self { |
||||
Qop::AUTH => "auth", |
||||
Qop::AUTH_INT => "auth-int", |
||||
}) |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
#[allow(non_camel_case_types)] |
||||
pub enum QopAlgo<'a> { |
||||
NONE, |
||||
AUTH, |
||||
AUTH_INT(&'a [u8]), |
||||
} |
||||
|
||||
// casting back...
|
||||
impl<'a> Into<Option<Qop>> for QopAlgo<'a> { |
||||
/// Convert to ?Qop
|
||||
fn into(self) -> Option<Qop> { |
||||
match self { |
||||
QopAlgo::NONE => None, |
||||
QopAlgo::AUTH => Some(Qop::AUTH), |
||||
QopAlgo::AUTH_INT(_) => Some(Qop::AUTH_INT), |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// Charset field value as specified by the server
|
||||
#[derive(Debug, PartialEq)] |
||||
pub enum Charset { |
||||
ASCII, |
||||
UTF8, |
||||
} |
||||
|
||||
impl FromStr for Charset { |
||||
type Err = Error; |
||||
|
||||
/// Parse from string (only UTF-8 supported, as prescribed by the specification)
|
||||
fn from_str(s: &str) -> Result<Self> { |
||||
match s { |
||||
"UTF-8" => Ok(Charset::UTF8), |
||||
_ => Err(BadCharset(s.into())), |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// HTTP method (used when generating the response hash for some Qop options)
|
||||
#[derive(Debug)] |
||||
pub enum HttpMethod { |
||||
GET, |
||||
POST, |
||||
HEAD, |
||||
OTHER(&'static str), |
||||
} |
||||
|
||||
impl Default for HttpMethod { |
||||
fn default() -> Self { |
||||
HttpMethod::GET |
||||
} |
||||
} |
||||
|
||||
impl Display for HttpMethod { |
||||
/// Convert to uppercase string
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
||||
f.write_str(match self { |
||||
HttpMethod::GET => "GET", |
||||
HttpMethod::POST => "POST", |
||||
HttpMethod::HEAD => "HEAD", |
||||
HttpMethod::OTHER(s) => s, |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
use std::fmt::{self, Display, Formatter}; |
||||
use std::result; |
||||
|
||||
#[derive(Debug)] |
||||
pub enum Error { |
||||
BadCharset(String), |
||||
UnknownAlgorithm(String), |
||||
BadQop(String), |
||||
MissingRealm(String), |
||||
MissingNonce(String), |
||||
InvalidHeaderSyntax(String), |
||||
BadQopOptions(String), |
||||
} |
||||
|
||||
pub type Result<T> = result::Result<T, Error>; |
||||
|
||||
use Error::*; |
||||
|
||||
impl Display for Error { |
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
||||
match self { |
||||
BadCharset(ctx) => write!(f, "Bad charset: {}", ctx), |
||||
UnknownAlgorithm(ctx) => write!(f, "Unknown algorithm: {}", ctx), |
||||
BadQop(ctx) => write!(f, "Bad Qop option: {}", ctx), |
||||
MissingRealm(ctx) => write!(f, "Missing 'realm' in WWW-Authenticate: {}", ctx), |
||||
MissingNonce(ctx) => write!(f, "Missing 'nonce' in WWW-Authenticate: {}", ctx), |
||||
InvalidHeaderSyntax(ctx) => write!(f, "Invalid header syntax: {}", ctx), |
||||
BadQopOptions(ctx) => write!(f, "Illegal Qop in prompt: {}", ctx), |
||||
} |
||||
} |
||||
} |
@ -1,18 +0,0 @@ |
||||
use std::string::ToString; |
||||
|
||||
/// slash quoting for digest strings
|
||||
pub trait QuoteForDigest { |
||||
fn quote_for_digest(&self) -> String; |
||||
} |
||||
|
||||
impl QuoteForDigest for &str { |
||||
fn quote_for_digest(&self) -> String { |
||||
self.to_string().quote_for_digest() |
||||
} |
||||
} |
||||
|
||||
impl QuoteForDigest for String { |
||||
fn quote_for_digest(&self) -> String { |
||||
self.replace("\\", "\\\\").replace("\"", "\\\"") |
||||
} |
||||
} |
Loading…
Reference in new issue