use ic_agent::{export::Principal, identity::SignedDelegation};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use web_sys::js_sys::Date;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct DelegationChain {
pub delegations: Vec<SignedDelegation>,
pub public_key: Vec<u8>,
}
impl DelegationChain {
pub fn new(delegations: Vec<SignedDelegation>, public_key: Vec<u8>) -> Self {
DelegationChain {
delegations,
public_key,
}
}
pub fn from_json(json: &str) -> Self {
serde_json::from_str(json).expect("Failed to parse delegation chain")
}
pub fn to_json(&self) -> String {
serde_json::to_string(self).expect("Failed to serialize delegation chain")
}
pub fn is_delegation_valid(&self, checks: Option<Vec<Principal>>) -> bool {
let now = (Date::now() * 1_000_000.0) as u64;
if self
.delegations
.iter()
.any(|signed_delegation| signed_delegation.delegation.expiration <= now)
{
return false;
}
if let Some(checks) = checks {
let checks: HashSet<_> = checks.into_iter().collect();
for signed_delegation in self.delegations.iter() {
let delegation = &signed_delegation.delegation;
if let Some(targets) = delegation.targets.clone() {
if targets.iter().all(|target| !checks.contains(target)) {
return false;
}
}
}
}
true
}
}
#[allow(dead_code)]
#[cfg(test)]
mod tests {
use super::*;
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
fn test_delegation_chain() {
let delegation_chain = DelegationChain {
delegations: vec![],
public_key: vec![1, 2, 3],
};
let json = delegation_chain.to_json();
let delegation_chain2 = DelegationChain::from_json(&json);
let json2 = delegation_chain2.to_json();
assert_eq!(json, json2);
}
#[wasm_bindgen_test]
fn test_is_delegation_valid() {
let delegation_chain = DelegationChain {
delegations: vec![],
public_key: vec![1, 2, 3],
};
assert!(delegation_chain.is_delegation_valid(None));
}
#[wasm_bindgen_test]
fn test_is_delegation_valid_expired() {
let delegation_chain = DelegationChain {
delegations: vec![SignedDelegation {
delegation: ic_agent::identity::Delegation {
pubkey: vec![],
expiration: 0,
targets: None,
},
signature: vec![],
}],
public_key: vec![1, 2, 3],
};
assert!(!delegation_chain.is_delegation_valid(None));
}
}