secret-vault 1.16.2

Library provides a secure vault to store securely application secrets in memory from Google/AWS/K8S and environment variables
Documentation
use std::sync::Arc;
use tokio::sync::RwLock;

use crate::common_types::*;
use crate::encryption::*;
use crate::SecretVaultResult;

#[cfg(not(feature = "ahash"))]
type SecretVaultMap = std::collections::HashMap<SecretVaultKey, SecretVaultStoreValue>;

#[cfg(feature = "ahash")]
type SecretVaultMap = ahash::AHashMap<SecretVaultKey, SecretVaultStoreValue>;

#[derive(Debug)]
pub struct SecretVaultStoreValue {
    pub data: EncryptedSecretValue,
    pub metadata: SecretMetadata,
}

#[derive(Debug)]
pub struct SecretVaultStore<E>
where
    E: SecretVaultEncryption,
{
    secrets: Arc<RwLock<SecretVaultMap>>,
    encrypter: E,
}

impl<E> SecretVaultStore<E>
where
    E: SecretVaultEncryption,
{
    pub fn new(encrypter: E) -> Self {
        Self {
            secrets: Arc::new(RwLock::new(SecretVaultMap::new())),
            encrypter,
        }
    }

    pub async fn insert(
        &self,
        secret_ref: SecretVaultRef,
        secret: &Secret,
    ) -> SecretVaultResult<()> {
        let encrypted_secret_value = self
            .encrypter
            .encrypt_value(&secret_ref.key, &secret.value)
            .await?;

        let mut secrets_write = self.secrets.write().await;
        secrets_write.insert(
            secret_ref.key,
            SecretVaultStoreValue {
                data: encrypted_secret_value,
                metadata: secret.metadata.clone(),
            },
        );

        Ok(())
    }

    pub async fn get_secret(
        &self,
        secret_vault_key: &SecretVaultKey,
    ) -> SecretVaultResult<Option<Secret>> {
        let secrets_read = self.secrets.read().await;

        match secrets_read.get(secret_vault_key) {
            Some(stored_value) => {
                let secret_value = self
                    .encrypter
                    .decrypt_value(secret_vault_key, &stored_value.data)
                    .await?;
                Ok(Some(Secret::new(
                    secret_value,
                    stored_value.metadata.clone(),
                )))
            }
            None => Ok(None),
        }
    }

    pub async fn remove(&self, secret_vault_key: &SecretVaultKey) -> SecretVaultResult<()> {
        let mut secrets_write = self.secrets.write().await;
        secrets_write.remove(secret_vault_key);
        Ok(())
    }

    pub async fn contains(&self, secret_refs: &[SecretVaultRef]) -> bool {
        let secrets_read = self.secrets.read().await;
        secret_refs
            .iter()
            .all(|secret_ref| secrets_read.contains_key(&secret_ref.key))
    }

    pub async fn compact(&self, secret_refs: &[SecretVaultRef]) -> SecretVaultResult<()> {
        let mut secrets_write = self.secrets.write().await;
        let to_remove: Vec<SecretVaultKey> = secrets_write
            .keys()
            .filter(|key| !secret_refs.iter().any(|secret_ref| secret_ref.key == **key))
            .cloned()
            .collect();

        for key in to_remove {
            secrets_write.remove(&key);
        }

        Ok(())
    }

    pub async fn exists<'a>(
        &'a self,
        secret_refs: &'a Vec<SecretVaultRef>,
    ) -> (Vec<&'a SecretVaultRef>, Vec<&'a SecretVaultRef>) {
        let secrets_read = self.secrets.read().await;
        let mut missing = Vec::new();
        let mut existing = Vec::new();
        for secret_ref in secret_refs {
            if secrets_read.contains_key(&secret_ref.key) {
                existing.push(secret_ref);
            } else {
                missing.push(secret_ref);
            }
        }
        (existing, missing)
    }

    pub async fn len(&self) -> usize {
        let secrets_read = self.secrets.read().await;
        secrets_read.len()
    }
}