use crate::error::AgentError;
use crate::storage::keychain::{IdentityDID, KeyAlias, KeyRole, KeyStorage};
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Default)]
pub struct MemoryStorage {
data: HashMap<String, (IdentityDID, KeyRole, Vec<u8>)>,
}
impl std::fmt::Debug for MemoryStorage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MemoryStorage")
.field("key_count", &self.data.len())
.finish()
}
}
pub static MEMORY_KEYCHAIN: Lazy<Mutex<MemoryStorage>> =
Lazy::new(|| Mutex::new(MemoryStorage::default()));
#[derive(Debug, Clone, Copy)]
pub struct MemoryKeychainHandle;
impl MemoryStorage {
pub fn store_key(
&mut self,
alias: &KeyAlias,
identity_did: &IdentityDID,
role: KeyRole,
encrypted_key_data: &[u8],
) -> Result<(), AgentError> {
self.data.insert(
alias.as_str().to_string(),
(identity_did.clone(), role, encrypted_key_data.to_vec()),
);
Ok(())
}
pub fn load_key(
&self,
alias: &KeyAlias,
) -> Result<(IdentityDID, KeyRole, Vec<u8>), AgentError> {
self.data
.get(alias.as_str())
.cloned()
.ok_or(AgentError::KeyNotFound)
}
pub fn delete_key(&mut self, alias: &KeyAlias) -> Result<(), AgentError> {
self.data.remove(alias.as_str());
Ok(())
}
pub fn list_aliases(&self) -> Result<Vec<KeyAlias>, AgentError> {
Ok(self
.data
.keys()
.map(|k| KeyAlias::new_unchecked(k.clone()))
.collect())
}
pub fn list_aliases_for_identity(
&self,
identity_did: &IdentityDID,
) -> Result<Vec<KeyAlias>, AgentError> {
let aliases = self
.data
.iter()
.filter_map(|(alias, (did, _role, _))| {
if did == identity_did {
Some(KeyAlias::new_unchecked(alias.clone()))
} else {
None
}
})
.collect();
Ok(aliases)
}
pub fn get_identity_for_alias(&self, alias: &KeyAlias) -> Result<IdentityDID, AgentError> {
self.data
.get(alias.as_str())
.map(|(did, _role, _)| did.clone())
.ok_or(AgentError::KeyNotFound)
}
pub fn clear_all(&mut self) -> Result<(), AgentError> {
self.data.clear();
Ok(())
}
pub fn backend_name(&self) -> &'static str {
"Memory"
}
}
impl KeyStorage for MemoryKeychainHandle {
fn store_key(
&self,
alias: &KeyAlias,
identity_did: &IdentityDID,
role: KeyRole,
encrypted_key_data: &[u8],
) -> Result<(), AgentError> {
MEMORY_KEYCHAIN
.lock()
.map_err(|_| AgentError::MutexError("global memory keychain".into()))?
.store_key(alias, identity_did, role, encrypted_key_data)
}
fn load_key(&self, alias: &KeyAlias) -> Result<(IdentityDID, KeyRole, Vec<u8>), AgentError> {
MEMORY_KEYCHAIN
.lock()
.map_err(|_| AgentError::MutexError("global memory keychain".into()))?
.load_key(alias)
}
fn delete_key(&self, alias: &KeyAlias) -> Result<(), AgentError> {
MEMORY_KEYCHAIN
.lock()
.map_err(|_| AgentError::MutexError("global memory keychain".into()))?
.delete_key(alias)
}
fn list_aliases(&self) -> Result<Vec<KeyAlias>, AgentError> {
MEMORY_KEYCHAIN
.lock()
.map_err(|_| AgentError::MutexError("global memory keychain".into()))?
.list_aliases()
}
fn list_aliases_for_identity(
&self,
identity_did: &IdentityDID,
) -> Result<Vec<KeyAlias>, AgentError> {
MEMORY_KEYCHAIN
.lock()
.map_err(|_| AgentError::MutexError("global memory keychain".into()))?
.list_aliases_for_identity(identity_did)
}
fn get_identity_for_alias(&self, alias: &KeyAlias) -> Result<IdentityDID, AgentError> {
MEMORY_KEYCHAIN
.lock()
.map_err(|_| AgentError::MutexError("global memory keychain".into()))?
.get_identity_for_alias(alias)
}
fn backend_name(&self) -> &'static str {
"Memory"
}
}
#[derive(Debug, Clone)]
pub struct IsolatedKeychainHandle {
store: Arc<Mutex<MemoryStorage>>,
}
impl IsolatedKeychainHandle {
pub fn new() -> Self {
Self {
store: Arc::new(Mutex::new(MemoryStorage::default())),
}
}
}
impl Default for IsolatedKeychainHandle {
fn default() -> Self {
Self::new()
}
}
impl KeyStorage for IsolatedKeychainHandle {
fn store_key(
&self,
alias: &KeyAlias,
identity_did: &IdentityDID,
role: KeyRole,
encrypted_key_data: &[u8],
) -> Result<(), AgentError> {
self.store
.lock()
.map_err(|_| AgentError::MutexError("isolated memory keychain".into()))?
.store_key(alias, identity_did, role, encrypted_key_data)
}
fn load_key(&self, alias: &KeyAlias) -> Result<(IdentityDID, KeyRole, Vec<u8>), AgentError> {
self.store
.lock()
.map_err(|_| AgentError::MutexError("isolated memory keychain".into()))?
.load_key(alias)
}
fn delete_key(&self, alias: &KeyAlias) -> Result<(), AgentError> {
self.store
.lock()
.map_err(|_| AgentError::MutexError("isolated memory keychain".into()))?
.delete_key(alias)
}
fn list_aliases(&self) -> Result<Vec<KeyAlias>, AgentError> {
self.store
.lock()
.map_err(|_| AgentError::MutexError("isolated memory keychain".into()))?
.list_aliases()
}
fn list_aliases_for_identity(
&self,
identity_did: &IdentityDID,
) -> Result<Vec<KeyAlias>, AgentError> {
self.store
.lock()
.map_err(|_| AgentError::MutexError("isolated memory keychain".into()))?
.list_aliases_for_identity(identity_did)
}
fn get_identity_for_alias(&self, alias: &KeyAlias) -> Result<IdentityDID, AgentError> {
self.store
.lock()
.map_err(|_| AgentError::MutexError("isolated memory keychain".into()))?
.get_identity_for_alias(alias)
}
fn backend_name(&self) -> &'static str {
"IsolatedMemory"
}
}
#[cfg(any(test, feature = "test-utils"))]
pub fn get_test_memory_keychain() -> Box<dyn KeyStorage + Send + Sync> {
MEMORY_KEYCHAIN
.lock()
.unwrap_or_else(|e| e.into_inner())
.clear_all()
.ok();
Box::new(MemoryKeychainHandle)
}