use std::time::{SystemTime, UNIX_EPOCH};
use jsonwebtoken::{jwk::Jwk, DecodingKey};
use crate::{DecodingInfo, FetchError, ValidationSettings};
pub(crate) fn decode_jwk(
jwk: &Jwk,
validation: &ValidationSettings,
) -> Result<(String, DecodingInfo), FetchError> {
let kid = jwk.common.key_id.clone();
let alg = jwk.common.algorithm;
let dec_key = match jwk.algorithm {
jsonwebtoken::jwk::AlgorithmParameters::EllipticCurve(ref params) => {
let x_cmp = b64_decode(¶ms.x)?;
let y_cmp = b64_decode(¶ms.y)?;
let mut public_key = Vec::with_capacity(1 + params.x.len() + params.y.len());
public_key.push(0x04);
public_key.extend_from_slice(&x_cmp);
public_key.extend_from_slice(&y_cmp);
Some(DecodingKey::from_ec_der(&public_key))
}
jsonwebtoken::jwk::AlgorithmParameters::RSA(ref params) => {
DecodingKey::from_rsa_components(¶ms.n, ¶ms.e).ok()
}
jsonwebtoken::jwk::AlgorithmParameters::OctetKey(ref params) => {
DecodingKey::from_base64_secret(¶ms.value).ok()
}
jsonwebtoken::jwk::AlgorithmParameters::OctetKeyPair(ref params) => {
let der = b64_decode(¶ms.x)?;
Some(DecodingKey::from_ed_der(&der))
}
};
match (kid, alg, dec_key) {
(Some(kid), Some(alg), Some(dec_key)) => {
let info = DecodingInfo::new(jwk.clone(), dec_key, alg, validation);
Ok((kid, info))
}
_ => Err(FetchError::InvalidJWK),
}
}
fn b64_decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, base64::DecodeError> {
base64::decode_config(input, base64::URL_SAFE_NO_PAD)
}
pub(crate) fn current_time() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time Went Backwards")
.as_secs()
}
pub(crate) fn normalize_url(url: &str) -> String {
let trimmed_url = url.trim_end_matches('/');
let stripped_url = trimmed_url
.strip_suffix(".well-known/openid-configuration")
.map(|i| i.trim_end_matches('/'))
.unwrap_or(trimmed_url);
stripped_url.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize_url() {
assert_eq!(
normalize_url("http://example.com//.well-known/openid-configuration"),
"http://example.com"
);
assert_eq!(
normalize_url("http://example.com/.well-known/openid-configuration"),
"http://example.com"
);
assert_eq!(normalize_url("http://example.com//"), "http://example.com");
assert_eq!(normalize_url("http://example.com/"), "http://example.com");
assert_eq!(normalize_url("http://example.com"), "http://example.com");
}
}