mod registered;
use std::borrow::Cow;
use chrono::Utc;
pub use registered::*;
mod mixed;
pub use mixed::*;
mod matching;
pub use matching::*;
mod any;
pub use any::*;
use serde::{de::DeserializeOwned, Serialize};
use ssi_claims_core::{ClaimsValidity, DateTimeProvider, InvalidClaims};
#[derive(Debug, thiserror::Error)]
#[error("invalid claim value")]
pub struct InvalidClaimValue(String);
impl InvalidClaimValue {
pub fn new(e: impl ToString) -> Self {
Self(e.to_string())
}
}
impl From<serde_json::Error> for InvalidClaimValue {
fn from(value: serde_json::Error) -> Self {
Self::new(value)
}
}
pub trait Claim: 'static + Clone + Serialize + DeserializeOwned {
const JWT_CLAIM_NAME: &'static str;
}
pub trait ClaimSet {
fn contains<C: Claim>(&self) -> bool {
false
}
fn try_get<C: Claim>(&'_ self) -> Result<Option<Cow<'_, C>>, InvalidClaimValue> {
Ok(None)
}
fn try_set<C: Claim>(&mut self, claim: C) -> Result<Result<(), C>, InvalidClaimValue> {
Ok(Err(claim))
}
fn try_remove<C: Claim>(&mut self) -> Result<Option<C>, InvalidClaimValue> {
Ok(None)
}
fn validate_registered_claims<E>(&self, env: &E) -> ClaimsValidity
where
E: DateTimeProvider,
{
let now = env.date_time();
if let Some(iat) = self.try_get::<IssuedAt>().map_err(InvalidClaims::other)? {
let valid_from: chrono::DateTime<Utc> = iat.0.into();
if valid_from > now {
return Err(InvalidClaims::Premature { now, valid_from });
}
}
if let Some(nbf) = self.try_get::<NotBefore>().map_err(InvalidClaims::other)? {
let valid_from: chrono::DateTime<Utc> = nbf.0.into();
if valid_from > now {
return Err(InvalidClaims::Premature { now, valid_from });
}
}
if let Some(exp) = self
.try_get::<ExpirationTime>()
.map_err(InvalidClaims::other)?
{
let valid_until: chrono::DateTime<Utc> = exp.0.into();
if valid_until <= now {
return Err(InvalidClaims::Expired { now, valid_until });
}
}
Ok(())
}
}
pub trait InfallibleClaimSet: ClaimSet {
fn get<C: Claim>(&'_ self) -> Option<Cow<'_, C>> {
Self::try_get(self).unwrap()
}
fn set<C: Claim>(&mut self, claim: C) -> Result<(), C> {
Self::try_set(self, claim).unwrap()
}
fn remove<C: Claim>(&mut self) -> Option<C> {
Self::try_remove(self).unwrap()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ClaimKind<U = String> {
Registered(RegisteredClaimKind),
Unregistered(U),
}
impl ClaimKind {
pub fn as_ref(&self) -> ClaimKind<&str> {
match self {
Self::Registered(r) => ClaimKind::Registered(*r),
Self::Unregistered(u) => ClaimKind::Unregistered(u),
}
}
}
impl<'de> serde::Deserialize<'de> for ClaimKind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let name = String::deserialize(deserializer)?;
match RegisteredClaimKind::new(&name) {
Some(r) => Ok(Self::Registered(r)),
None => Ok(Self::Unregistered(name)),
}
}
}
impl ClaimKind<&str> {
pub fn into_owned(self) -> ClaimKind {
match self {
Self::Registered(r) => ClaimKind::Registered(r),
Self::Unregistered(u) => ClaimKind::Unregistered(u.to_owned()),
}
}
}
impl hashbrown::Equivalent<ClaimKind<String>> for ClaimKind<&str> {
fn equivalent(&self, key: &ClaimKind<String>) -> bool {
*self == key.as_ref()
}
}