format code, version bump
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "digest_auth"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
||||
edition = "2018"
|
||||
description = "Implementation of the Digest Auth algorithm as defined in IETF RFC 2069, 2617, and 7616, intended for HTTP clients"
|
||||
|
||||
+63
-42
@@ -41,7 +41,7 @@ fn join_vec<T : ToString>(vec : &Vec<T>, sep : &str) -> String {
|
||||
|
||||
enum NamedTag<'a> {
|
||||
Quoted(&'a str, Cow<'a, str>),
|
||||
Plain(&'a str, Cow<'a, str>)
|
||||
Plain(&'a str, Cow<'a, str>),
|
||||
}
|
||||
|
||||
impl Display for NamedTag<'_> {
|
||||
@@ -50,13 +50,10 @@ impl Display for NamedTag<'_> {
|
||||
NamedTag::Quoted(name, content) => {
|
||||
write!(f, "{}=\"{}\"", name, content.quote_for_digest())
|
||||
}
|
||||
NamedTag::Plain(name, content) => {
|
||||
write!(f, "{}={}", name, content)
|
||||
NamedTag::Plain(name, content) => write!(f, "{}={}", name, content),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Helper func that parses the key-value string received from server
|
||||
fn parse_header_map(input: &str) -> Result<HashMap<String, String>> {
|
||||
@@ -148,7 +145,6 @@ fn parse_header_map(input: &str) -> Result<HashMap<String, String>> {
|
||||
Ok(parsed)
|
||||
}
|
||||
|
||||
|
||||
/// Login attempt context
|
||||
///
|
||||
/// All fields are borrowed to reduce runtime overhead; this struct should not be stored anywhere,
|
||||
@@ -174,22 +170,25 @@ impl<'a> AuthContext<'a> {
|
||||
/// Construct a new context with the GET verb and no payload body.
|
||||
/// See the other constructors if this does not fit your situation.
|
||||
pub fn new<UN, PW, UR>(username: UN, password: PW, uri: UR) -> Self
|
||||
where UN: Into<Cow<'a, str>>,
|
||||
where
|
||||
UN: Into<Cow<'a, str>>,
|
||||
PW: Into<Cow<'a, str>>,
|
||||
UR: Into<Cow<'a, str>>
|
||||
UR: Into<Cow<'a, str>>,
|
||||
{
|
||||
Self::new_with_method(username, password, uri, Option::<&'a[u8]>::None, HttpMethod::GET)
|
||||
Self::new_with_method(
|
||||
username,
|
||||
password,
|
||||
uri,
|
||||
Option::<&'a [u8]>::None,
|
||||
HttpMethod::GET,
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct a new context with the POST verb and a payload body (may be None).
|
||||
/// See the other constructors if this does not fit your situation.
|
||||
pub fn new_post<UN, PW, UR, BD>(
|
||||
username: UN,
|
||||
password: PW,
|
||||
uri: UR,
|
||||
body: Option<BD>,
|
||||
) -> Self
|
||||
where UN: Into<Cow<'a, str>>,
|
||||
pub fn new_post<UN, PW, UR, BD>(username: UN, password: PW, uri: UR, body: Option<BD>) -> Self
|
||||
where
|
||||
UN: Into<Cow<'a, str>>,
|
||||
PW: Into<Cow<'a, str>>,
|
||||
UR: Into<Cow<'a, str>>,
|
||||
BD: Into<Cow<'a, [u8]>>,
|
||||
@@ -205,10 +204,11 @@ impl<'a> AuthContext<'a> {
|
||||
body: Option<BD>,
|
||||
method: HttpMethod,
|
||||
) -> Self
|
||||
where UN: Into<Cow<'a, str>>,
|
||||
where
|
||||
UN: Into<Cow<'a, str>>,
|
||||
PW: Into<Cow<'a, str>>,
|
||||
UR: Into<Cow<'a, str>>,
|
||||
BD: Into<Cow<'a, [u8]>>
|
||||
BD: Into<Cow<'a, [u8]>>,
|
||||
{
|
||||
Self {
|
||||
username: username.into(),
|
||||
@@ -223,7 +223,7 @@ impl<'a> AuthContext<'a> {
|
||||
/// Set cnonce to the given value
|
||||
pub fn set_custom_cnonce<CN>(&mut self, cnonce: CN)
|
||||
where
|
||||
CN: Into<Cow<'a, str>>
|
||||
CN: Into<Cow<'a, str>>,
|
||||
{
|
||||
self.cnonce = Some(cnonce.into());
|
||||
}
|
||||
@@ -269,10 +269,7 @@ impl FromStr for WwwAuthenticateHeader {
|
||||
impl WwwAuthenticateHeader {
|
||||
/// Generate an [`AuthorizationHeader`](struct.AuthorizationHeader.html) to be sent to the server in a new request.
|
||||
/// The [`self.nc`](struct.AuthorizationHeader.html#structfield.nc) field is incremented.
|
||||
pub fn respond(
|
||||
&mut self,
|
||||
secrets: &AuthContext,
|
||||
) -> Result<AuthorizationHeader> {
|
||||
pub fn respond(&mut self, secrets: &AuthContext) -> Result<AuthorizationHeader> {
|
||||
AuthorizationHeader::from_prompt(self, secrets)
|
||||
}
|
||||
|
||||
@@ -357,7 +354,10 @@ impl Display for WwwAuthenticateHeader {
|
||||
entries.push(NamedTag::Plain("stale", "true".into()));
|
||||
}
|
||||
|
||||
entries.push(NamedTag::Plain("algorithm", self.algorithm.to_string().into()));
|
||||
entries.push(NamedTag::Plain(
|
||||
"algorithm",
|
||||
self.algorithm.to_string().into(),
|
||||
));
|
||||
entries.push(NamedTag::Quoted("nonce", (&self.nonce).into()));
|
||||
if let Some(ref opaque) = self.opaque {
|
||||
entries.push(NamedTag::Quoted("opaque", (opaque).into()));
|
||||
@@ -369,7 +369,9 @@ impl Display for WwwAuthenticateHeader {
|
||||
}
|
||||
|
||||
for (i, e) in entries.iter().enumerate() {
|
||||
if i > 0 { f.write_str(", ")?; }
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
f.write_str(&e.to_string())?;
|
||||
}
|
||||
|
||||
@@ -428,7 +430,6 @@ impl AuthorizationHeader {
|
||||
prompt: &mut WwwAuthenticateHeader,
|
||||
context: &AuthContext,
|
||||
) -> Result<AuthorizationHeader> {
|
||||
|
||||
let qop = match &prompt.qop {
|
||||
None => None,
|
||||
Some(vec) => {
|
||||
@@ -457,7 +458,11 @@ impl AuthorizationHeader {
|
||||
username: String::default(),
|
||||
uri: context.uri.as_ref().into(),
|
||||
qop,
|
||||
cnonce: context.cnonce.as_ref().map(AsRef::as_ref).map(ToOwned::to_owned), // Will be generated if needed, if build_hash is set and this is None
|
||||
cnonce: context
|
||||
.cnonce
|
||||
.as_ref()
|
||||
.map(AsRef::as_ref)
|
||||
.map(ToOwned::to_owned), // Will be generated if needed, if build_hash is set and this is None
|
||||
nc: prompt.nc,
|
||||
};
|
||||
|
||||
@@ -479,8 +484,7 @@ impl AuthorizationHeader {
|
||||
/// - cnonce (if it was None before)
|
||||
/// - username copied from context
|
||||
/// - response
|
||||
pub fn digest(&mut self, context : &AuthContext)
|
||||
{
|
||||
pub fn digest(&mut self, context: &AuthContext) {
|
||||
// figure out which QOP option to use
|
||||
let qop_algo = match self.qop {
|
||||
None => QopAlgo::NONE,
|
||||
@@ -492,9 +496,7 @@ impl AuthorizationHeader {
|
||||
QopAlgo::AUTH
|
||||
}
|
||||
}
|
||||
Some(Qop::AUTH) => {
|
||||
QopAlgo::AUTH
|
||||
}
|
||||
Some(Qop::AUTH) => QopAlgo::AUTH,
|
||||
};
|
||||
|
||||
let h = &self.algorithm;
|
||||
@@ -653,7 +655,7 @@ impl AuthorizationHeader {
|
||||
|
||||
if auth.qop.is_some() {
|
||||
if !auth.cnonce.is_some() {
|
||||
return Err(MissingRequired("cnonce", input.into()))
|
||||
return Err(MissingRequired("cnonce", input.into()));
|
||||
}
|
||||
} else {
|
||||
// cnonce must not be set if qop is not given, clear it.
|
||||
@@ -676,9 +678,15 @@ impl Display for AuthorizationHeader {
|
||||
entries.push(NamedTag::Quoted("uri", (&self.uri).into()));
|
||||
|
||||
if self.qop.is_some() && self.cnonce.is_some() {
|
||||
entries.push(NamedTag::Plain("qop", self.qop.as_ref().unwrap().to_string().into()));
|
||||
entries.push(NamedTag::Plain(
|
||||
"qop",
|
||||
self.qop.as_ref().unwrap().to_string().into(),
|
||||
));
|
||||
entries.push(NamedTag::Plain("nc", format!("{:08x}", self.nc).into()));
|
||||
entries.push(NamedTag::Quoted("cnonce", self.cnonce.as_ref().unwrap().into()));
|
||||
entries.push(NamedTag::Quoted(
|
||||
"cnonce",
|
||||
self.cnonce.as_ref().unwrap().into(),
|
||||
));
|
||||
}
|
||||
|
||||
entries.push(NamedTag::Quoted("response", (&self.response).into()));
|
||||
@@ -689,7 +697,10 @@ impl Display for AuthorizationHeader {
|
||||
|
||||
// algorithm can be omitted if it is the default value (or in legacy compat mode)
|
||||
if self.qop.is_some() || self.algorithm.algo != AlgorithmType::MD5 {
|
||||
entries.push(NamedTag::Plain("algorithm", self.algorithm.to_string().into()));
|
||||
entries.push(NamedTag::Plain(
|
||||
"algorithm",
|
||||
self.algorithm.to_string().into(),
|
||||
));
|
||||
}
|
||||
|
||||
if self.userhash {
|
||||
@@ -697,7 +708,9 @@ impl Display for AuthorizationHeader {
|
||||
}
|
||||
|
||||
for (i, e) in entries.iter().enumerate() {
|
||||
if i > 0 { f.write_str(", ")?; }
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
f.write_str(&e.to_string())?;
|
||||
}
|
||||
|
||||
@@ -756,8 +769,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_header_map2()
|
||||
{
|
||||
fn test_parse_header_map2() {
|
||||
let src = r#"realm="api@example.org""#;
|
||||
let map = parse_header_map(src).unwrap();
|
||||
assert_eq!(map.get("realm").unwrap(), "api@example.org");
|
||||
@@ -843,7 +855,10 @@ r#"Digest realm="api@example.org",
|
||||
nonce="5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK",
|
||||
opaque="HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS",
|
||||
charset=UTF-8,
|
||||
userhash=true"#.replace(",\n ", ", "), hdr.to_string());
|
||||
userhash=true"#
|
||||
.replace(",\n ", ", "),
|
||||
hdr.to_string()
|
||||
);
|
||||
|
||||
hdr.stale = true;
|
||||
hdr.userhash = false;
|
||||
@@ -856,7 +871,10 @@ r#"Digest realm="api@example.org",
|
||||
stale=true,
|
||||
algorithm=SHA-512-256,
|
||||
nonce="5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK",
|
||||
charset=UTF-8"#.replace(",\n ", ", "), hdr.to_string());
|
||||
charset=UTF-8"#
|
||||
.replace(",\n ", ", "),
|
||||
hdr.to_string()
|
||||
);
|
||||
|
||||
hdr.qop = Some(vec![Qop::AUTH, Qop::AUTH_INT]);
|
||||
|
||||
@@ -867,7 +885,10 @@ r#"Digest realm="api@example.org",
|
||||
stale=true,
|
||||
algorithm=SHA-512-256,
|
||||
nonce="5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK",
|
||||
charset=UTF-8"#.replace(",\n ", ", "), hdr.to_string());
|
||||
charset=UTF-8"#
|
||||
.replace(",\n ", ", "),
|
||||
hdr.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user