use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
pub fn basic_auth(username: &str, password: &str) -> String {
let plain = format!("{}:{}", username, password);
let encoded = BASE64.encode(plain);
format!("Basic {}", encoded)
}
pub fn parse_basic_auth(header: &str) -> Option<(String, String)> {
let encoded = header.strip_prefix("Basic ")?.trim();
let decoded_vec = BASE64.decode(encoded).ok()?;
let decoded = String::from_utf8(decoded_vec).ok()?;
let (username, password) = decoded.split_once(':')?;
Some((username.to_string(), password.to_string()))
}
#[allow(clippy::too_many_arguments)]
pub fn digest_auth(
username: &str,
password: &str,
method: &str,
uri: &str,
realm: &str,
nonce: &str,
cnonce: &str,
nc: &str,
qop: &str,
algorithm: &str,
opaque: &str,
) -> String {
use sha2::{Digest, Sha256};
let hash = |data: &str| -> String {
if algorithm.to_uppercase().starts_with("SHA-256") {
let res = Sha256::digest(data.as_bytes());
hex::encode(res)
} else {
let res = Sha256::digest(data.as_bytes()); hex::encode(res)
}
};
let a1 = format!("{}:{}:{}", username, realm, password);
let ha1 = hash(&a1);
println!("A1: '{}'", a1);
println!("HA1: {}", ha1);
let a2 = format!("{}:{}", method, uri);
let ha2 = hash(&a2);
println!("A2: '{}'", a2);
println!("HA2: {}", ha2);
let response_str = format!("{}:{}:{}:{}:{}:{}", ha1, nonce, nc, cnonce, qop, ha2);
println!("Response String: '{}'", response_str);
let response = hash(&response_str);
let mut header = format!(
"Digest username=\"{}\", realm=\"{}\", nonce=\"{}\", uri=\"{}\", qop={}, nc={}, cnonce=\"{}\", response=\"{}\", algorithm={}",
username, realm, nonce, uri, qop, nc, cnonce, response, algorithm
);
if !opaque.is_empty() {
header.push_str(&format!(", opaque=\"{}\"", opaque));
}
header
}
pub fn parse_digest_challenge(header: &str) -> std::collections::HashMap<String, String> {
let mut map = std::collections::HashMap::new();
let content = header.strip_prefix("Digest ").unwrap_or(header).trim();
for part in content.split(',') {
if let Some((key, val)) = part.trim().split_once('=') {
let key = key.trim().to_lowercase();
let val = val.trim().trim_matches('"');
map.insert(key, val.to_string());
}
}
map
}