use aws_lc_rs::digest::{SHA256, digest};
use base64::Engine as _;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use super::AuthError;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Pkce {
pub verifier: String,
pub challenge: String,
}
pub fn random_base64url() -> Result<String, AuthError> {
yapi_types::time::try_random_bytes::<32>()
.map(|bytes| URL_SAFE_NO_PAD.encode(bytes))
.map_err(AuthError::random)
}
pub fn generate() -> Result<Pkce, AuthError> {
let verifier = random_base64url()?;
let challenge = challenge(&verifier);
Ok(Pkce {
verifier,
challenge,
})
}
pub fn challenge(verifier: &str) -> String {
URL_SAFE_NO_PAD.encode(digest(&SHA256, verifier.as_bytes()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn matches_rfc_7636_example() {
assert_eq!(
challenge("dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"),
"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
);
let pkce = generate().unwrap();
assert_eq!(pkce.verifier.len(), 43);
assert_eq!(pkce.challenge, challenge(&pkce.verifier));
}
}