artisan_keystore 2.1.1

A keystore server designed for AH
Documentation
//! High level client helpers for interacting with the keystore server.
//!
//! This library wraps the gRPC API exposed by the `ais_keystore` binary and
//! provides convenience functions for performing common actions.  All functions
//! are asynchronous and return errors using the [`dusa_collection_utils`] crate
//! types.

use dusa_collection_utils::core::errors::{ErrorArrayItem, Errors};
use grpc::keystore::key_store_client::KeyStoreClient;
use grpc::keystore::{
    AddKeyRequest, CommandResponse, GenerateKeyRequest, GetKeyRequest, Key, KeyResponse,
    MigrateKeyRequest,
};
use tonic::transport::Channel;

pub mod encryption;
pub mod grpc;
pub mod key_store;
pub mod shared;

/// Generates a new key with a defined length via the gRPC API.
/// The result is the raw key bytes.
pub async fn generate_key(
    client: &mut KeyStoreClient<Channel>,
    key_length: Option<u32>,
) -> Result<Vec<u8>, ErrorArrayItem> {
    let request = GenerateKeyRequest {
        length: key_length.unwrap_or(32),
    };
    let response = client
        .generate_key(request)
        .await
        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
        .into_inner();

    if !response.success {
        return Err(ErrorArrayItem::new(Errors::Network, response.key));
    }

    hex::decode(response.key).map_err(ErrorArrayItem::from)
}

/// Store a key using the gRPC API.
pub async fn store_key(
    client: &mut KeyStoreClient<Channel>,
    id: String,
    key_value: Vec<u8>,
    ttl: Option<u64>,
) -> Result<(), ErrorArrayItem> {
    let request = AddKeyRequest {
        id,
        value: key_value,
        ttl: ttl.unwrap_or(0),
    };
    let response = client
        .add_key(request)
        .await
        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
        .into_inner();

    if response.success {
        Ok(())
    } else {
        Err(ErrorArrayItem::new(Errors::Network, response.message))
    }
}

/// Retrieve a key and return its data structure using gRPC.
pub async fn get_key_data(
    client: &mut KeyStoreClient<Channel>,
    id: String,
    version: Option<u32>,
) -> Result<Key, ErrorArrayItem> {
    let request = GetKeyRequest {
        id,
        version: version.unwrap_or(0),
    };
    let response: KeyResponse = client
        .get_key(request)
        .await
        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
        .into_inner();

    if !response.success {
        return Err(ErrorArrayItem::new(Errors::Network, response.message));
    }

    response
        .key
        .ok_or_else(|| ErrorArrayItem::new(Errors::Network, "Missing key"))
}

/// Retrieve a key and return only the raw value.
pub async fn get_key(
    client: &mut KeyStoreClient<Channel>,
    id: String,
    version: Option<u32>,
) -> Result<Vec<u8>, ErrorArrayItem> {
    let key = get_key_data(client, id, version).await?;
    Ok(key.value)
}

/// Migrate a key via gRPC.
pub async fn migrate_key(
    client: &mut KeyStoreClient<Channel>,
    id: String,
) -> Result<(), ErrorArrayItem> {
    let request = MigrateKeyRequest { id };
    let response: CommandResponse = client
        .migrate_key(request)
        .await
        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
        .into_inner();
    if response.success {
        Ok(())
    } else {
        Err(ErrorArrayItem::new(Errors::Network, response.message))
    }
}

/// Basic connectivity test for the gRPC client.
pub async fn conn_test(client: &mut KeyStoreClient<Channel>) -> bool {
    client
        .generate_key(GenerateKeyRequest { length: 0 })
        .await
        .is_ok()
}