usecrate::b64; usecrate::error::*; usecrate::mac::Mac; use base64::Engine; use std::fmt; use std::str::FromStr; use std::time::{Duration, SystemTime, UNIX_EPOCH};
/// Representation of a Hawk `Authorization` header value (the part following "Hawk "). /// /// Headers can be derived from strings using the `FromStr` trait, and formatted into a /// string using the `fmt_header` method. /// /// All fields are optional, although for specific purposes some fields must be present. #[derive(Clone, PartialEq, Debug)] pubstruct Header { pub id: Option<String>, pub ts: Option<SystemTime>, pub nonce: Option<String>, pub mac: Option<Mac>, pub ext: Option<String>, pub hash: Option<Vec<u8>>, pub app: Option<String>, pub dlg: Option<String>,
}
impl Header { /// Create a new Header with the full set of Hawk fields. /// /// This is a low-level function. Headers are more often created from Requests or Responses. /// /// Note that none of the string-formatted header components can contain the character `\"`. pubfn new<S>(
id: Option<S>,
ts: Option<SystemTime>,
nonce: Option<S>,
mac: Option<Mac>,
ext: Option<S>,
hash: Option<Vec<u8>>,
app: Option<S>,
dlg: Option<S>,
) -> Result<Header> where
S: Into<String>,
{
Ok(Header {
id: Header::check_component(id)?,
ts,
nonce: Header::check_component(nonce)?,
mac,
ext: Header::check_component(ext)?,
hash,
app: Header::check_component(app)?,
dlg: Header::check_component(dlg)?,
})
}
/// Check a header component for validity. fn check_component<S>(value: Option<S>) -> Result<Option<String>> where
S: Into<String>,
{ iflet Some(value) = value { let value = value.into(); if value.contains('\"') { return Err(Error::HeaderParseError( "Hawk headers cannot contain `\\`".into(),
));
}
Ok(Some(value))
} else {
Ok(None)
}
}
while !p.is_empty() { // Skip whitespace and commas used as separators
p = p.trim_start_matches(|c| c == ',' || char::is_whitespace(c)); // Find first '=' which delimits attribute name from value let assign_end = p
.find('=')
.ok_or_else(|| Error::HeaderParseError("Expected '='".into()))?; let attr = &p[..assign_end].trim(); if p.len() < assign_end + 1 { return Err(Error::HeaderParseError( "Missing right hand side of =".into(),
));
}
p = p[assign_end + 1..].trim_start(); if !p.starts_with('\"') { return Err(Error::HeaderParseError("Expected opening quote".into()));
}
p = &p[1..]; // We have poor RFC 7235 compliance here as we ought to support backslash // escaped characters, but hawk doesn't allow this we won't either. All // strings must be surrounded by ".." and contain no such characters. let end = p.find('\"'); let val_end =
end.ok_or_else(|| Error::HeaderParseError("Expected closing quote".into()))?; let val = &p[..val_end]; match *attr { "id" => id = Some(val), "ts" => { let epoch = u64::from_str(val)
.map_err(|_| Error::HeaderParseError("Error parsing `ts` field".into()))?;
ts = Some(UNIX_EPOCH + Duration::new(epoch, 0));
} "mac" => {
mac = Some(b64::STANDARD_ENGINE.decode(val).map_err(|_| {
Error::HeaderParseError("Error parsing `mac` field".into())
})?);
} "nonce" => nonce = Some(val), "ext" => ext = Some(val), "hash" => {
hash = Some(b64::STANDARD_ENGINE.decode(val).map_err(|_| {
Error::HeaderParseError("Error parsing `hash` field".into())
})?);
} "app" => app = Some(val), "dlg" => dlg = Some(val),
_ => { return Err(Error::HeaderParseError(format!( "Invalid Hawk field {}",
*attr
)))
}
}; // Break if we are at end of string, otherwise skip separator if p.len() < val_end + 1 { break;
}
p = p[val_end + 1..].trim_start();
}
#[test] fn to_str_no_fields() { // must supply a type for S, since it is otherwise unused let s = Header::new::<String>(None, None, None, None, None, None, None, None).unwrap(); let formatted = format!("{s}");
println!("got: {formatted}");
assert!(formatted.is_empty())
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.