forked from packages/digest_auth_rs
				
			
							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