use crate::Biscuit;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RevocationId {
inner: Vec<u8>,
}
impl RevocationId {
pub fn new(bytes: Vec<u8>) -> Self {
Self { inner: bytes }
}
pub fn as_bytes(&self) -> &[u8] {
&self.inner
}
pub fn to_hex(&self) -> String {
hex::encode(&self.inner)
}
pub fn from_hex(hex_str: &str) -> Result<Self, hex::FromHexError> {
hex::decode(hex_str).map(Self::new)
}
}
impl fmt::Display for RevocationId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl From<Vec<u8>> for RevocationId {
fn from(bytes: Vec<u8>) -> Self {
Self::new(bytes)
}
}
pub fn get_revocation_ids(biscuit: &Biscuit) -> Vec<RevocationId> {
biscuit
.revocation_identifiers()
.into_iter()
.map(RevocationId::from)
.collect()
}
pub fn get_authority_revocation_id(biscuit: &Biscuit) -> Option<RevocationId> {
biscuit
.revocation_identifiers()
.into_iter()
.next()
.map(RevocationId::from)
}
pub fn get_block_revocation_id(biscuit: &Biscuit, index: usize) -> Option<RevocationId> {
biscuit
.revocation_identifiers()
.into_iter()
.nth(index)
.map(RevocationId::from)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::KeyPair;
use biscuit_auth::macros::biscuit;
#[test]
fn test_revocation_id_hex_conversion() {
let bytes = vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
let rev_id = RevocationId::new(bytes.clone());
assert_eq!(rev_id.to_hex(), "0123456789abcdef");
assert_eq!(rev_id.to_string(), "0123456789abcdef");
let from_hex = RevocationId::from_hex("0123456789abcdef").unwrap();
assert_eq!(from_hex.as_bytes(), &bytes[..]);
assert_eq!(rev_id, from_hex);
}
#[test]
fn test_get_revocation_ids() {
let keypair = KeyPair::new();
let biscuit = biscuit!(
r#"
right("alice", "resource1", "read");
"#
)
.build(&keypair)
.unwrap();
let rev_ids = get_revocation_ids(&biscuit);
assert!(!rev_ids.is_empty());
assert_eq!(rev_ids.len(), 1);
assert!(!rev_ids[0].as_bytes().is_empty());
}
#[test]
fn test_get_authority_revocation_id() {
let keypair = KeyPair::new();
let biscuit = biscuit!(
r#"
right("alice", "resource1", "read");
"#
)
.build(&keypair)
.unwrap();
let auth_id = get_authority_revocation_id(&biscuit);
assert!(auth_id.is_some());
let all_ids = get_revocation_ids(&biscuit);
assert_eq!(auth_id.unwrap(), all_ids[0]);
}
#[test]
fn test_unique_revocation_ids() {
let keypair = KeyPair::new();
let biscuit1 = biscuit!(
r#"
right("alice", "resource1", "read");
"#
)
.build(&keypair)
.unwrap();
let biscuit2 = biscuit!(
r#"
right("alice", "resource1", "read");
"#
)
.build(&keypair)
.unwrap();
let rev_id1 = get_authority_revocation_id(&biscuit1).unwrap();
let rev_id2 = get_authority_revocation_id(&biscuit2).unwrap();
assert_ne!(rev_id1, rev_id2);
}
}