use crate::header::CborValue;
use std::collections::BTreeMap;
pub mod keys {
use crate::constants::cwt_keys;
pub const ISS: i32 = cwt_keys::ISS;
pub const SUB: i32 = cwt_keys::SUB;
pub const AUD: i32 = cwt_keys::AUD;
pub const EXP: i32 = cwt_keys::EXP;
pub const NBF: i32 = cwt_keys::NBF;
pub const IAT: i32 = cwt_keys::IAT;
pub const CTI: i32 = cwt_keys::CTI;
}
pub type ClaimsMap = BTreeMap<i32, CborValue>;
#[derive(Debug, Clone, Default)]
pub struct RegisteredClaims {
pub iss: Option<String>,
pub sub: Option<String>,
pub aud: Option<String>,
pub exp: Option<u64>,
pub nbf: Option<u64>,
pub iat: Option<u64>,
pub cti: Option<Vec<u8>>,
}
impl RegisteredClaims {
pub fn new() -> Self {
Self::default()
}
pub fn with_issuer<S: Into<String>>(mut self, iss: S) -> Self {
self.iss = Some(iss.into());
self
}
pub fn with_subject<S: Into<String>>(mut self, sub: S) -> Self {
self.sub = Some(sub.into());
self
}
pub fn with_audience<S: Into<String>>(mut self, aud: S) -> Self {
self.aud = Some(aud.into());
self
}
pub fn with_expiration(mut self, exp: u64) -> Self {
self.exp = Some(exp);
self
}
pub fn with_not_before(mut self, nbf: u64) -> Self {
self.nbf = Some(nbf);
self
}
pub fn with_issued_at(mut self, iat: u64) -> Self {
self.iat = Some(iat);
self
}
pub fn with_cti<T: Into<Vec<u8>>>(mut self, cti: T) -> Self {
self.cti = Some(cti.into());
self
}
pub fn with_lifetime_secs(mut self, seconds: u64) -> Self {
let now = crate::utils::current_timestamp();
self.iat = Some(now);
self.nbf = Some(now);
self.exp = Some(now + seconds);
self
}
pub fn with_lifetime(self, duration: std::time::Duration) -> Self {
self.with_lifetime_secs(duration.as_secs())
}
pub fn is_expired(&self) -> bool {
if let Some(exp) = self.exp {
crate::utils::current_timestamp() >= exp
} else {
false
}
}
pub fn is_valid_yet(&self) -> bool {
if let Some(nbf) = self.nbf {
crate::utils::current_timestamp() >= nbf
} else {
true
}
}
pub fn to_map(&self) -> ClaimsMap {
let mut map = ClaimsMap::new();
if let Some(iss) = &self.iss {
map.insert(keys::ISS, CborValue::Text(iss.clone()));
}
if let Some(sub) = &self.sub {
map.insert(keys::SUB, CborValue::Text(sub.clone()));
}
if let Some(aud) = &self.aud {
map.insert(keys::AUD, CborValue::Text(aud.clone()));
}
if let Some(exp) = self.exp {
map.insert(keys::EXP, CborValue::Integer(exp as i64));
}
if let Some(nbf) = self.nbf {
map.insert(keys::NBF, CborValue::Integer(nbf as i64));
}
if let Some(iat) = self.iat {
map.insert(keys::IAT, CborValue::Integer(iat as i64));
}
if let Some(cti) = &self.cti {
map.insert(keys::CTI, CborValue::Bytes(cti.clone()));
}
map
}
pub fn from_map(map: &ClaimsMap) -> Self {
let mut claims = Self::new();
if let Some(CborValue::Text(iss)) = map.get(&keys::ISS) {
claims.iss = Some(iss.clone());
}
if let Some(CborValue::Text(sub)) = map.get(&keys::SUB) {
claims.sub = Some(sub.clone());
}
if let Some(CborValue::Text(aud)) = map.get(&keys::AUD) {
claims.aud = Some(aud.clone());
}
if let Some(CborValue::Integer(exp)) = map.get(&keys::EXP) {
claims.exp = Some(*exp as u64);
}
if let Some(CborValue::Integer(nbf)) = map.get(&keys::NBF) {
claims.nbf = Some(*nbf as u64);
}
if let Some(CborValue::Integer(iat)) = map.get(&keys::IAT) {
claims.iat = Some(*iat as u64);
}
if let Some(CborValue::Bytes(cti)) = map.get(&keys::CTI) {
claims.cti = Some(cti.clone());
}
claims
}
}
#[derive(Debug, Clone, Default)]
pub struct Claims {
pub registered: RegisteredClaims,
pub custom: ClaimsMap,
}
impl Claims {
pub fn new() -> Self {
Self::default()
}
pub fn with_registered_claims(mut self, registered: RegisteredClaims) -> Self {
self.registered = registered;
self
}
pub fn with_custom_string<S: Into<String>>(mut self, key: i32, value: S) -> Self {
self.custom.insert(key, CborValue::Text(value.into()));
self
}
pub fn with_custom_binary<B: Into<Vec<u8>>>(mut self, key: i32, value: B) -> Self {
self.custom.insert(key, CborValue::Bytes(value.into()));
self
}
pub fn with_custom_int(mut self, key: i32, value: i64) -> Self {
self.custom.insert(key, CborValue::Integer(value));
self
}
pub fn with_custom_map(mut self, key: i32, value: BTreeMap<i32, CborValue>) -> Self {
self.custom.insert(key, CborValue::Map(value));
self
}
pub fn get_custom_string(&self, key: i32) -> Option<&str> {
match self.custom.get(&key) {
Some(CborValue::Text(s)) => Some(s.as_str()),
_ => None,
}
}
pub fn get_custom_int(&self, key: i32) -> Option<i64> {
match self.custom.get(&key) {
Some(CborValue::Integer(i)) => Some(*i),
_ => None,
}
}
pub fn get_custom_binary(&self, key: i32) -> Option<&[u8]> {
match self.custom.get(&key) {
Some(CborValue::Bytes(b)) => Some(b.as_slice()),
_ => None,
}
}
pub fn get_custom_claim(&self, key: i32) -> Option<&CborValue> {
self.custom.get(&key)
}
pub fn has_custom_claim(&self, key: i32) -> bool {
self.custom.contains_key(&key)
}
pub fn to_map(&self) -> ClaimsMap {
let mut map = self.registered.to_map();
for (key, value) in &self.custom {
map.insert(*key, value.clone());
}
map
}
pub fn from_map(map: &ClaimsMap) -> Self {
let registered = RegisteredClaims::from_map(map);
let mut custom = ClaimsMap::new();
for (key, value) in map {
if !matches!(
*key,
keys::ISS | keys::SUB | keys::AUD | keys::EXP | keys::NBF | keys::IAT | keys::CTI
) {
custom.insert(*key, value.clone());
}
}
Self { registered, custom }
}
}