use std::{borrow::Cow, fmt};
use serde::Deserialize;
use crate::{Alg, Error, VerifyingKey};
#[derive(Debug, Deserialize)]
pub struct Jwks<'a> {
pub keys: Vec<Jwk<'a>>,
}
#[derive(Debug, Deserialize)]
pub struct Jwk<'a> {
#[serde(rename = "use")]
pub usage: Option<KeyUsage<'a>>,
pub key_ops: Option<Vec<KeyOp<'a>>>,
pub alg: Option<Alg<'a>>,
pub kid: Option<Cow<'a, str>>,
#[serde(flatten)]
pub key_data: KeyData<'a>,
}
#[derive(Deserialize)]
#[serde(tag = "kty")]
pub enum KeyData<'a> {
#[serde(rename = "EC")]
Ec {
crv: EcCurve<'a>,
x: Cow<'a, str>,
y: Option<Cow<'a, str>>,
d: Option<Cow<'a, str>>,
},
#[serde(rename = "RSA")]
Rsa {
n: Cow<'a, str>,
e: Cow<'a, str>,
d: Option<Cow<'a, str>>,
},
#[serde(rename = "oct")]
Oct {
k: Cow<'a, str>,
},
#[serde(rename = "OKP")]
Okp {
crv: OkpCurve<'a>,
x: Cow<'a, str>,
d: Option<Cow<'a, str>>,
},
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub enum KeyUsage<'a> {
#[serde(rename = "sig")]
Signature,
#[serde(rename = "enc")]
Encryption,
#[serde(untagged)]
Other(Cow<'a, str>),
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum KeyOp<'a> {
Sign,
Verify,
Encrypt,
Decrypt,
WrapKey,
UnwrapKey,
DeriveKey,
DeriveBits,
#[serde(untagged)]
Other(Cow<'a, str>),
}
crate::make_string_enum!(
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub enum EcCurve<'a> {
P256 = "P-256",
P384 = "P-384",
P521 = "P-521",
}
);
crate::make_string_enum!(
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub enum OkpCurve<'a> {
Ed25519,
Ed448,
}
);
impl<'a> Jwk<'a> {
pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
pub fn to_verifying_key(&self) -> Result<VerifyingKey, Error> {
VerifyingKey::from_jwk(self)
}
}
impl<'a> Jwks<'a> {
pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
pub fn to_verifying_keys(&self) -> impl Iterator<Item = Result<VerifyingKey, Error>> {
self.keys.iter().map(VerifyingKey::from_jwk)
}
}
impl fmt::Debug for KeyData<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Redacted;
impl fmt::Debug for Redacted {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "REDACTED")
}
}
match self {
Self::Ec { crv, x, y, .. } => f.debug_struct("Ec")
.field("crv", crv)
.field("x", x)
.field("y", y)
.field("d", &Redacted)
.finish(),
Self::Rsa { n, e, .. } => f.debug_struct("Rsa")
.field("n", n)
.field("e", e)
.field("d", &Redacted)
.finish(),
Self::Oct { .. } => f.debug_struct("Oct")
.field("k", &Redacted)
.finish(),
Self::Okp { crv, x, .. } => f.debug_struct("Okp")
.field("crv", crv)
.field("x", x)
.field("d", &Redacted)
.finish(),
}
}
}