mod serde_utils;
mod source;
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use bon::Builder;
use serde::{Deserialize, Serialize};
use sha2::{Digest as _, Sha256};
pub use source::JwksSource;
use zeroize::Zeroize;
use crate::jwk::serde_utils::{
base64url, base64url_uint, option_base64url, option_base64url_uint, trim_leading_zeros,
};
mod key;
mod private;
mod public;
pub use key::*;
pub use private::*;
pub use public::*;
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, Builder, PartialEq, Clone)]
#[builder(derive(Into))]
pub struct Jwk {
#[builder(into)]
#[serde(flatten)]
pub key: Key,
#[serde(rename = "use", skip_serializing_if = "Option::is_none")]
pub key_use: Option<KeyUse>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(with = <_>::from_iter)]
#[serde(rename = "key_ops")]
pub key_operations: Option<Vec<KeyOperation>>,
#[builder(into)]
#[serde(rename = "alg", skip_serializing_if = "Option::is_none")]
pub algorithm: Option<String>,
#[builder(into)]
#[serde(skip_serializing_if = "Option::is_none")]
pub kid: Option<String>,
#[builder(skip)]
#[serde(rename = "x5u", default, skip_serializing)]
pub x5u: Option<String>,
}
impl Jwk {
#[must_use]
pub fn public_jwk(&self) -> Option<PublicJwk> {
self.key.public_key().map(|key| PublicJwk {
key,
key_use: self.key_use,
key_operations: self.key_operations.clone(),
algorithm: self.algorithm.clone(),
kid: self.kid.clone(),
x5u: self.x5u.clone(),
})
}
#[must_use]
pub fn private_key(&self) -> Option<PrivateKey> {
self.key.private_key()
}
#[must_use]
pub fn private_jwk(&self) -> Option<PrivateJwk> {
self.key.private_key().map(|key| PrivateJwk {
key,
key_use: self.key_use,
key_operations: self.key_operations.clone(),
algorithm: self.algorithm.clone(),
kid: self.kid.clone(),
x5u: self.x5u.clone(),
})
}
}
#[non_exhaustive]
#[derive(Debug, Builder, PartialEq, Clone)]
#[builder(derive(Into))]
pub struct PrivateJwk {
#[builder(into)]
pub key: PrivateKey,
pub key_use: Option<KeyUse>,
#[builder(with = <_>::from_iter)]
pub key_operations: Option<Vec<KeyOperation>>,
#[builder(into)]
pub algorithm: Option<String>,
#[builder(into)]
pub kid: Option<String>,
#[builder(skip)]
pub x5u: Option<String>,
}
impl PrivateJwk {
#[must_use]
pub fn public_jwk(&self) -> PublicJwk {
PublicJwk {
key: self.key.public_key(),
key_use: self.key_use,
key_operations: self.key_operations.clone(),
algorithm: self.algorithm.clone(),
kid: self.kid.clone(),
x5u: self.x5u.clone(),
}
}
#[must_use]
pub fn thumbprint(&self) -> String {
self.public_jwk().thumbprint()
}
}
impl From<PrivateJwk> for Jwk {
fn from(pjwk: PrivateJwk) -> Self {
Self {
key: pjwk.key.into(),
key_use: pjwk.key_use,
key_operations: pjwk.key_operations,
algorithm: pjwk.algorithm,
kid: pjwk.kid,
x5u: pjwk.x5u,
}
}
}
impl From<PrivateJwk> for PublicJwk {
fn from(pjwk: PrivateJwk) -> Self {
pjwk.public_jwk()
}
}
#[non_exhaustive]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Jwks {
pub keys: Vec<Jwk>,
}
impl Jwks {
#[must_use]
pub fn new(keys: Vec<Jwk>) -> Self {
Self { keys }
}
}
impl From<Jwks> for PublicJwks {
fn from(jwks: Jwks) -> Self {
PublicJwks::new(jwks.keys.iter().filter_map(Jwk::public_jwk).collect())
}
}
#[cfg(test)]
mod tests;