use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::crypto::{EncryptedSecret, PlaintextSecret};
use crate::error::CryptoResult;
#[async_trait]
pub trait SecretStore: Send + Sync {
async fn store(&self, key: &str, secret: EncryptedSecret) -> CryptoResult<()>;
async fn retrieve(&self, key: &str) -> CryptoResult<Option<EncryptedSecret>>;
async fn delete(&self, key: &str) -> CryptoResult<()>;
async fn list(&self) -> CryptoResult<Vec<String>>;
}
#[derive(Debug, Clone)]
pub struct MemorySecretStore {
secrets: Arc<RwLock<HashMap<String, EncryptedSecret>>>,
}
impl MemorySecretStore {
pub fn new() -> Self {
Self {
secrets: Arc::new(RwLock::new(HashMap::new())),
}
}
}
impl Default for MemorySecretStore {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl SecretStore for MemorySecretStore {
async fn store(&self, key: &str, secret: EncryptedSecret) -> CryptoResult<()> {
let mut secrets = self.secrets.write().await;
secrets.insert(key.to_string(), secret);
Ok(())
}
async fn retrieve(&self, key: &str) -> CryptoResult<Option<EncryptedSecret>> {
let secrets = self.secrets.read().await;
Ok(secrets.get(key).cloned())
}
async fn delete(&self, key: &str) -> CryptoResult<()> {
let mut secrets = self.secrets.write().await;
secrets.remove(key);
Ok(())
}
async fn list(&self) -> CryptoResult<Vec<String>> {
let secrets = self.secrets.read().await;
Ok(secrets.keys().cloned().collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_memory_store() {
let store = MemorySecretStore::new();
let secret = EncryptedSecret::default();
store.store("test", secret.clone()).await.unwrap();
let retrieved = store.retrieve("test").await.unwrap();
assert!(retrieved.is_some());
let keys = store.list().await.unwrap();
assert_eq!(keys.len(), 1);
assert_eq!(keys[0], "test");
store.delete("test").await.unwrap();
let retrieved = store.retrieve("test").await.unwrap();
assert!(retrieved.is_none());
}
}