Skip to main content

ais_keystore_lib/
lib.rs

1//! High level client helpers for interacting with the keystore server.
2//!
3//! This library wraps the gRPC API exposed by the `ais_keystore` binary and
4//! provides convenience functions for performing common actions.  All functions
5//! are asynchronous and return errors using the [`dusa_collection_utils`] crate
6//! types.
7
8use dusa_collection_utils::core::errors::{ErrorArrayItem, Errors};
9use grpc::keystore::key_store_client::KeyStoreClient;
10use grpc::keystore::{
11    AddKeyRequest, CommandResponse, GenerateKeyRequest, GetKeyRequest, Key, KeyResponse,
12    MigrateKeyRequest,
13};
14use tonic::transport::Channel;
15
16pub mod encryption;
17pub mod grpc;
18pub mod key_store;
19pub mod shared;
20
21/// Generates a new key with a defined length via the gRPC API.
22/// The result is the raw key bytes.
23pub async fn generate_key(
24    client: &mut KeyStoreClient<Channel>,
25    key_length: Option<u32>,
26) -> Result<Vec<u8>, ErrorArrayItem> {
27    let request = GenerateKeyRequest {
28        length: key_length.unwrap_or(32),
29    };
30    let response = client
31        .generate_key(request)
32        .await
33        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
34        .into_inner();
35
36    if !response.success {
37        return Err(ErrorArrayItem::new(Errors::Network, response.key));
38    }
39
40    hex::decode(response.key).map_err(ErrorArrayItem::from)
41}
42
43/// Store a key using the gRPC API.
44pub async fn store_key(
45    client: &mut KeyStoreClient<Channel>,
46    id: String,
47    key_value: Vec<u8>,
48    ttl: Option<u64>,
49) -> Result<(), ErrorArrayItem> {
50    let request = AddKeyRequest {
51        id,
52        value: key_value,
53        ttl: ttl.unwrap_or(0),
54    };
55    let response = client
56        .add_key(request)
57        .await
58        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
59        .into_inner();
60
61    if response.success {
62        Ok(())
63    } else {
64        Err(ErrorArrayItem::new(Errors::Network, response.message))
65    }
66}
67
68/// Retrieve a key and return its data structure using gRPC.
69pub async fn get_key_data(
70    client: &mut KeyStoreClient<Channel>,
71    id: String,
72    version: Option<u32>,
73) -> Result<Key, ErrorArrayItem> {
74    let request = GetKeyRequest {
75        id,
76        version: version.unwrap_or(0),
77    };
78    let response: KeyResponse = client
79        .get_key(request)
80        .await
81        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
82        .into_inner();
83
84    if !response.success {
85        return Err(ErrorArrayItem::new(Errors::Network, response.message));
86    }
87
88    response
89        .key
90        .ok_or_else(|| ErrorArrayItem::new(Errors::Network, "Missing key"))
91}
92
93/// Retrieve a key and return only the raw value.
94pub async fn get_key(
95    client: &mut KeyStoreClient<Channel>,
96    id: String,
97    version: Option<u32>,
98) -> Result<Vec<u8>, ErrorArrayItem> {
99    let key = get_key_data(client, id, version).await?;
100    Ok(key.value)
101}
102
103/// Migrate a key via gRPC.
104pub async fn migrate_key(
105    client: &mut KeyStoreClient<Channel>,
106    id: String,
107) -> Result<(), ErrorArrayItem> {
108    let request = MigrateKeyRequest { id };
109    let response: CommandResponse = client
110        .migrate_key(request)
111        .await
112        .map_err(|e| ErrorArrayItem::new(Errors::Network, format!("{}", e)))?
113        .into_inner();
114    if response.success {
115        Ok(())
116    } else {
117        Err(ErrorArrayItem::new(Errors::Network, response.message))
118    }
119}
120
121/// Basic connectivity test for the gRPC client.
122pub async fn conn_test(client: &mut KeyStoreClient<Channel>) -> bool {
123    client
124        .generate_key(GenerateKeyRequest { length: 0 })
125        .await
126        .is_ok()
127}