Skip to main content

auths_core/storage/
memory.rs

1//! In-memory key storage for testing.
2
3// Defauly memory fallback for non-iOS and non-macOS devices
4use crate::error::AgentError;
5use crate::storage::keychain::{IdentityDID, KeyAlias, KeyStorage};
6use once_cell::sync::Lazy;
7use std::collections::HashMap;
8use std::sync::{Arc, Mutex};
9
10/// An in-memory key storage implementation for fallback or testing.
11#[derive(Default)]
12pub struct MemoryStorage {
13    /// Internal mapping of alias -> (identity_did, encrypted_key_bytes)
14    data: HashMap<String, (IdentityDID, Vec<u8>)>,
15}
16
17impl std::fmt::Debug for MemoryStorage {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        f.debug_struct("MemoryStorage")
20            .field("key_count", &self.data.len())
21            .finish()
22    }
23}
24
25/// Global singleton memory store.
26pub static MEMORY_KEYCHAIN: Lazy<Mutex<MemoryStorage>> =
27    Lazy::new(|| Mutex::new(MemoryStorage::default()));
28
29/// A handle that interacts with the global in-memory keychain.
30/// Safe to use in tests or fallback environments.
31#[derive(Debug, Clone, Copy)]
32pub struct MemoryKeychainHandle;
33
34impl MemoryStorage {
35    /// Stores a key under the given alias.
36    pub fn store_key(
37        &mut self,
38        alias: &KeyAlias,
39        identity_did: &IdentityDID,
40        encrypted_key_data: &[u8],
41    ) -> Result<(), AgentError> {
42        self.data.insert(
43            alias.as_str().to_string(),
44            (identity_did.clone(), encrypted_key_data.to_vec()),
45        );
46        Ok(())
47    }
48
49    /// Loads the key data for the given alias.
50    pub fn load_key(&self, alias: &KeyAlias) -> Result<(IdentityDID, Vec<u8>), AgentError> {
51        self.data
52            .get(alias.as_str())
53            .cloned()
54            .ok_or(AgentError::KeyNotFound)
55    }
56
57    /// Deletes the key stored under the given alias.
58    pub fn delete_key(&mut self, alias: &KeyAlias) -> Result<(), AgentError> {
59        self.data.remove(alias.as_str());
60        Ok(())
61    }
62
63    /// Lists all stored aliases.
64    pub fn list_aliases(&self) -> Result<Vec<KeyAlias>, AgentError> {
65        Ok(self
66            .data
67            .keys()
68            .map(|k| KeyAlias::new_unchecked(k.clone()))
69            .collect())
70    }
71
72    /// Lists aliases associated with a specific identity.
73    pub fn list_aliases_for_identity(
74        &self,
75        identity_did: &IdentityDID,
76    ) -> Result<Vec<KeyAlias>, AgentError> {
77        let aliases = self
78            .data
79            .iter()
80            .filter_map(|(alias, (did, _))| {
81                if did == identity_did {
82                    Some(KeyAlias::new_unchecked(alias.clone()))
83                } else {
84                    None
85                }
86            })
87            .collect();
88        Ok(aliases)
89    }
90
91    /// Returns the identity DID associated with the given alias.
92    pub fn get_identity_for_alias(&self, alias: &KeyAlias) -> Result<IdentityDID, AgentError> {
93        self.data
94            .get(alias.as_str())
95            .map(|(did, _)| did.clone())
96            .ok_or(AgentError::KeyNotFound)
97    }
98
99    /// Removes all stored keys.
100    pub fn clear_all(&mut self) -> Result<(), AgentError> {
101        self.data.clear();
102        Ok(())
103    }
104
105    /// Returns the storage backend name.
106    pub fn backend_name(&self) -> &'static str {
107        "Memory"
108    }
109}
110
111impl KeyStorage for MemoryKeychainHandle {
112    fn store_key(
113        &self,
114        alias: &KeyAlias,
115        identity_did: &IdentityDID,
116        encrypted_key_data: &[u8],
117    ) -> Result<(), AgentError> {
118        MEMORY_KEYCHAIN
119            .lock()
120            .unwrap()
121            .store_key(alias, identity_did, encrypted_key_data)
122    }
123
124    fn load_key(&self, alias: &KeyAlias) -> Result<(IdentityDID, Vec<u8>), AgentError> {
125        MEMORY_KEYCHAIN.lock().unwrap().load_key(alias)
126    }
127
128    fn delete_key(&self, alias: &KeyAlias) -> Result<(), AgentError> {
129        MEMORY_KEYCHAIN.lock().unwrap().delete_key(alias)
130    }
131
132    fn list_aliases(&self) -> Result<Vec<KeyAlias>, AgentError> {
133        MEMORY_KEYCHAIN.lock().unwrap().list_aliases()
134    }
135
136    fn list_aliases_for_identity(
137        &self,
138        identity_did: &IdentityDID,
139    ) -> Result<Vec<KeyAlias>, AgentError> {
140        MEMORY_KEYCHAIN
141            .lock()
142            .unwrap()
143            .list_aliases_for_identity(identity_did)
144    }
145
146    fn get_identity_for_alias(&self, alias: &KeyAlias) -> Result<IdentityDID, AgentError> {
147        MEMORY_KEYCHAIN
148            .lock()
149            .unwrap()
150            .get_identity_for_alias(alias)
151    }
152
153    fn backend_name(&self) -> &'static str {
154        "Memory"
155    }
156}
157
158/// A per-instance in-memory keychain that does NOT share the global singleton.
159///
160/// Args:
161/// * (none — carries its own `Arc<Mutex<MemoryStorage>>`)
162///
163/// Usage:
164/// ```rust,ignore
165/// let kc = IsolatedKeychainHandle::new();
166/// kc.store_key(&alias, &did, &data)?;
167/// ```
168#[derive(Debug, Clone)]
169pub struct IsolatedKeychainHandle {
170    store: Arc<Mutex<MemoryStorage>>,
171}
172
173impl IsolatedKeychainHandle {
174    /// Creates a fresh, empty isolated keychain.
175    pub fn new() -> Self {
176        Self {
177            store: Arc::new(Mutex::new(MemoryStorage::default())),
178        }
179    }
180}
181
182impl Default for IsolatedKeychainHandle {
183    fn default() -> Self {
184        Self::new()
185    }
186}
187
188impl KeyStorage for IsolatedKeychainHandle {
189    fn store_key(
190        &self,
191        alias: &KeyAlias,
192        identity_did: &IdentityDID,
193        encrypted_key_data: &[u8],
194    ) -> Result<(), AgentError> {
195        self.store
196            .lock()
197            .unwrap()
198            .store_key(alias, identity_did, encrypted_key_data)
199    }
200
201    fn load_key(&self, alias: &KeyAlias) -> Result<(IdentityDID, Vec<u8>), AgentError> {
202        self.store.lock().unwrap().load_key(alias)
203    }
204
205    fn delete_key(&self, alias: &KeyAlias) -> Result<(), AgentError> {
206        self.store.lock().unwrap().delete_key(alias)
207    }
208
209    fn list_aliases(&self) -> Result<Vec<KeyAlias>, AgentError> {
210        self.store.lock().unwrap().list_aliases()
211    }
212
213    fn list_aliases_for_identity(
214        &self,
215        identity_did: &IdentityDID,
216    ) -> Result<Vec<KeyAlias>, AgentError> {
217        self.store
218            .lock()
219            .unwrap()
220            .list_aliases_for_identity(identity_did)
221    }
222
223    fn get_identity_for_alias(&self, alias: &KeyAlias) -> Result<IdentityDID, AgentError> {
224        self.store.lock().unwrap().get_identity_for_alias(alias)
225    }
226
227    fn backend_name(&self) -> &'static str {
228        "IsolatedMemory"
229    }
230}
231
232/// Returns a cleared memory keychain handle, used in tests.
233#[cfg(any(test, feature = "test-utils"))]
234pub fn get_test_memory_keychain() -> Box<dyn KeyStorage + Send + Sync> {
235    MEMORY_KEYCHAIN.lock().unwrap().clear_all().ok();
236    Box::new(MemoryKeychainHandle)
237}