use alloc::string::{String, ToString};
use alloc::vec::Vec;
use chio_core_types::capability::{CapabilityToken, ChioScope};
use chio_core_types::crypto::PublicKey;
use crate::clock::Clock;
use crate::normalized::{NormalizationError, NormalizedVerifiedCapability};
#[derive(Debug, Clone)]
pub struct VerifiedCapability {
pub id: String,
pub subject_hex: String,
pub issuer_hex: String,
pub scope: ChioScope,
pub issued_at: u64,
pub expires_at: u64,
pub evaluated_at: u64,
}
impl VerifiedCapability {
pub fn normalized(&self) -> Result<NormalizedVerifiedCapability, NormalizationError> {
NormalizedVerifiedCapability::try_from(self)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CapabilityError {
UntrustedIssuer,
InvalidSignature,
NotYetValid,
Expired,
Internal(String),
}
pub fn verify_capability(
token: &CapabilityToken,
trusted_issuers: &[PublicKey],
clock: &dyn Clock,
) -> Result<VerifiedCapability, CapabilityError> {
if !trusted_issuers.contains(&token.issuer) {
return Err(CapabilityError::UntrustedIssuer);
}
match token.verify_signature() {
Ok(true) => {}
Ok(false) => return Err(CapabilityError::InvalidSignature),
Err(error) => {
return Err(CapabilityError::Internal(error.to_string()));
}
}
let now = clock.now_unix_secs();
if now < token.issued_at {
return Err(CapabilityError::NotYetValid);
}
if now >= token.expires_at {
return Err(CapabilityError::Expired);
}
Ok(VerifiedCapability {
id: token.id.clone(),
subject_hex: token.subject.to_hex(),
issuer_hex: token.issuer.to_hex(),
scope: token.scope.clone(),
issued_at: token.issued_at,
expires_at: token.expires_at,
evaluated_at: now,
})
}
pub fn verify_capability_with_trusted<I>(
token: &CapabilityToken,
trusted_issuers: I,
clock: &dyn Clock,
) -> Result<VerifiedCapability, CapabilityError>
where
I: IntoIterator<Item = PublicKey>,
{
let trusted: Vec<PublicKey> = trusted_issuers.into_iter().collect();
verify_capability(token, &trusted, clock)
}