use hessra_token_core::{
Biscuit, PublicKey, RevocationId, TokenError, get_authority_revocation_id, get_revocation_ids,
};
pub fn latest_revocation_id(
token: &str,
public_key: PublicKey,
) -> Result<RevocationId, TokenError> {
let biscuit = Biscuit::from_base64(token, public_key)?;
get_revocation_ids(&biscuit)
.last()
.cloned()
.ok_or_else(|| TokenError::generic("capability has no blocks"))
}
pub fn get_capability_revocation_id(
token: String,
public_key: PublicKey,
) -> Result<RevocationId, TokenError> {
let biscuit = Biscuit::from_base64(&token, public_key)?;
get_authority_revocation_id(&biscuit).ok_or_else(|| {
TokenError::generic("Failed to extract revocation ID from capability token".to_string())
})
}
pub fn get_capability_revocation_id_from_bytes(
token_bytes: Vec<u8>,
public_key: PublicKey,
) -> Result<RevocationId, TokenError> {
let biscuit = Biscuit::from(&token_bytes, public_key)?;
get_authority_revocation_id(&biscuit).ok_or_else(|| {
TokenError::generic("Failed to extract revocation ID from capability token".to_string())
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mint::HessraCapability;
use hessra_token_core::{KeyPair, decode_token};
fn cap(keypair: &KeyPair, operation: &str) -> String {
HessraCapability::new()
.subject("user123")
.resource("resource456")
.operation(operation)
.issue(keypair)
.expect("issue capability")
}
#[test]
fn test_get_capability_revocation_id() {
let keypair = KeyPair::new();
let public_key = keypair.public();
let token_b64 = cap(&keypair, "read");
let token_bytes = decode_token(&token_b64).expect("Failed to decode token");
let rev_id = get_capability_revocation_id(token_b64.clone(), public_key)
.expect("Failed to get revocation ID");
assert!(!rev_id.to_hex().is_empty());
let rev_id_from_bytes = get_capability_revocation_id_from_bytes(token_bytes, public_key)
.expect("Failed to get revocation ID from bytes");
assert_eq!(rev_id.to_hex(), rev_id_from_bytes.to_hex());
let latest = latest_revocation_id(&token_b64, public_key).expect("latest");
assert_eq!(latest.to_hex(), rev_id.to_hex());
}
#[test]
fn test_unique_revocation_ids_for_capability_tokens() {
let keypair = KeyPair::new();
let public_key = keypair.public();
let token1 = cap(&keypair, "read");
let keypair2 = KeyPair::new();
let public_key2 = keypair2.public();
let token2 = cap(&keypair2, "read");
let rev_id1 = get_capability_revocation_id(token1, public_key)
.expect("Failed to get first revocation ID");
let rev_id2 = get_capability_revocation_id(token2, public_key2)
.expect("Failed to get second revocation ID");
assert_ne!(rev_id1.to_hex(), rev_id2.to_hex());
}
#[test]
fn latest_revocation_id_tracks_amendments() {
let keypair = KeyPair::new();
let public_key = keypair.public();
let token = cap(&keypair, "read");
let authority_id = get_capability_revocation_id(token.clone(), public_key).unwrap();
let amended = HessraCapability::amend(&token, public_key)
.unwrap()
.designation("tenant", "t-1")
.attenuate()
.unwrap();
let amended_id = latest_revocation_id(&amended, public_key).unwrap();
assert_ne!(authority_id.to_hex(), amended_id.to_hex());
}
}