use core::fmt;
use core::str::FromStr;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[non_exhaustive]
pub enum JwsAlgorithm {
EdDSA,
ES256,
ES256K,
ES384,
RS256,
PS256,
}
impl JwsAlgorithm {
pub const ALL: &'static [JwsAlgorithm] = &[
Self::EdDSA,
Self::ES256,
Self::ES256K,
Self::ES384,
Self::RS256,
Self::PS256,
];
pub const fn as_str(self) -> &'static str {
match self {
Self::EdDSA => "EdDSA",
Self::ES256 => "ES256",
Self::ES256K => "ES256K",
Self::ES384 => "ES384",
Self::RS256 => "RS256",
Self::PS256 => "PS256",
}
}
pub const fn is_ecdsa(self) -> bool {
matches!(self, Self::ES256 | Self::ES256K | Self::ES384)
}
}
impl fmt::Display for JwsAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("unknown or unsupported JWS algorithm `{0}`")]
pub struct UnknownAlgorithm(String);
impl UnknownAlgorithm {
pub fn name(&self) -> &str {
&self.0
}
}
impl FromStr for JwsAlgorithm {
type Err = UnknownAlgorithm;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::ALL
.iter()
.copied()
.find(|alg| alg.as_str() == s)
.ok_or_else(|| UnknownAlgorithm(s.to_owned()))
}
}
impl TryFrom<jsonwebtoken::Algorithm> for JwsAlgorithm {
type Error = UnknownAlgorithm;
fn try_from(alg: jsonwebtoken::Algorithm) -> Result<Self, Self::Error> {
use jsonwebtoken::Algorithm as A;
match alg {
A::EdDSA => Ok(Self::EdDSA),
A::ES256 => Ok(Self::ES256),
A::ES384 => Ok(Self::ES384),
A::RS256 => Ok(Self::RS256),
A::PS256 => Ok(Self::PS256),
other => Err(UnknownAlgorithm(format!("{other:?}"))),
}
}
}
impl TryFrom<JwsAlgorithm> for jsonwebtoken::Algorithm {
type Error = UnknownAlgorithm;
fn try_from(alg: JwsAlgorithm) -> Result<Self, Self::Error> {
match alg {
JwsAlgorithm::EdDSA => Ok(Self::EdDSA),
JwsAlgorithm::ES256 => Ok(Self::ES256),
JwsAlgorithm::ES384 => Ok(Self::ES384),
JwsAlgorithm::RS256 => Ok(Self::RS256),
JwsAlgorithm::PS256 => Ok(Self::PS256),
other => Err(UnknownAlgorithm(other.as_str().to_owned())),
}
}
}