platform/aid/credential/
validator.rs1use super::error::AidError;
8use super::verifier::AIdCredentialVerifier;
9use crate::aid::key_cache::KeyCache;
10use actr_protocol::{AIdCredential, IdentityClaims};
11use ed25519_dalek::VerifyingKey;
12use once_cell::sync::OnceCell;
13use std::sync::Arc;
14
15static KEY_CACHE: OnceCell<Arc<KeyCache>> = OnceCell::new();
16
17pub struct AIdCredentialValidator;
19
20impl AIdCredentialValidator {
21 pub async fn init(sqlite_path: &std::path::Path) -> Result<(), AidError> {
25 if KEY_CACHE.get().is_some() {
26 return Ok(());
27 }
28 let cache_db = sqlite_path.join("signaling_key_cache.db");
29 let cache = KeyCache::new(&cache_db).await?;
30 let _ = KEY_CACHE.set(Arc::new(cache));
32 Ok(())
33 }
34
35 fn get_cache() -> Result<Arc<KeyCache>, AidError> {
37 KEY_CACHE.get().cloned().ok_or(AidError::InvalidFormat)
38 }
39
40 pub async fn check(
45 credential: &AIdCredential,
46 realm_id: u32,
47 ) -> Result<(IdentityClaims, bool), AidError> {
48 let cache = Self::get_cache()?;
49 let key_id = credential.key_id;
50
51 let (verifying_key, _expires_at) = cache
52 .get_cached_key(key_id)
53 .await?
54 .ok_or(AidError::InvalidFormat)?; let claims = AIdCredentialVerifier::verify(credential, &verifying_key)?;
57
58 if claims.realm_id != realm_id {
59 return Err(AidError::InvalidFormat);
60 }
61
62 Ok((claims, false))
63 }
64
65 pub async fn get_key_bytes(key_id: u32) -> Result<Option<Vec<u8>>, AidError> {
67 let cache = Self::get_cache()?;
68 let result = cache.get_cached_key(key_id).await?;
69 Ok(result.map(|(verifying_key, _expires_at)| verifying_key.as_bytes().to_vec()))
70 }
71
72 pub async fn populate_key(
77 key_id: u32,
78 verifying_key: &VerifyingKey,
79 expires_at: u64,
80 ) -> Result<(), AidError> {
81 let cache = Self::get_cache()?;
82 cache.cache_key(key_id, verifying_key, expires_at).await
83 }
84
85 pub async fn persist_key(
90 sqlite_path: &std::path::Path,
91 key_id: u32,
92 verifying_key: &VerifyingKey,
93 expires_at: u64,
94 ) -> Result<(), AidError> {
95 let cache_db = sqlite_path.join("signaling_key_cache.db");
96 let cache = KeyCache::new(&cache_db).await?;
97 cache.cache_key(key_id, verifying_key, expires_at).await?;
98
99 if let Some(global_cache) = KEY_CACHE.get() {
101 let _ = global_cache
102 .cache_key(key_id, verifying_key, expires_at)
103 .await;
104 }
105
106 Ok(())
107 }
108
109 pub fn check_sync(
111 credential: &AIdCredential,
112 realm_id: u32,
113 ) -> Result<IdentityClaims, AidError> {
114 tokio::task::block_in_place(|| {
115 let handle =
116 tokio::runtime::Handle::try_current().map_err(|_| AidError::InvalidFormat)?;
117 let (claims, _) = handle.block_on(Self::check(credential, realm_id))?;
118 Ok(claims)
119 })
120 }
121}