keeper_secrets_manager_core/
config_keys.rs

1// -*- coding: utf-8 -*-
2//  _  __
3// | |/ /___ ___ _ __  ___ _ _ (R)
4// | ' </ -_) -_) '_ \/ -_) '_|
5// |_|\_\___\___| .__/\___|_|
6//              |_|
7//
8// Keeper Secrets Manager
9// Copyright 2024 Keeper Security Inc.
10// Contact: sm@keepersecurity.com
11//
12
13use serde::Serialize;
14use serde_json;
15use std::collections::HashMap;
16use strum_macros::{Display, EnumString};
17
18use crate::custom_error::KSMRError;
19
20#[derive(Debug, Clone, Display, EnumString, Eq, PartialEq, Hash, serde::Deserialize, Serialize)]
21pub enum ConfigKeys {
22    #[serde(rename = "url")]
23    KeyUrl, // base url for the Secrets Manager service
24    #[serde(rename = "clientId")]
25    KeyClientId,
26    #[serde(rename = "clientKey")]
27    KeyClientKey, // The key that is used to identify the client before public key. This is token.   
28    #[serde(rename = "appKey")]
29    KeyAppKey,    // The application key with which all secrets are encrypted
30    #[serde(rename = "appOwnerPublicKey")]
31    KeyOwnerPublicKey, // The application owner public key, to create records
32    #[serde(rename = "privateKey")]
33    KeyPrivateKey, // The client's private key
34    #[serde(rename = "serverPublicKeyId")]
35    KeyServerPublicKeyId, // Which public key should be using?
36
37    #[serde(rename = "bat")]
38    KeyBindingToken,
39    #[serde(rename = "bindingKey")]
40    KeyBindingKey,
41    #[serde(rename = "hostname")]
42    KeyHostname,
43}
44
45impl ConfigKeys {
46    /// Returns the string value associated with the enum variant.
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use keeper_secrets_manager_core::config_keys::ConfigKeys;
52    /// let key = ConfigKeys::KeyUrl;
53    /// assert_eq!(key.value(), "url");
54    /// ```
55    ///
56    /// # Panics
57    ///
58    /// This method does not panic under normal circumstances. However, if you modify
59    /// the match statement without providing all cases, it could lead to a panic.
60    pub fn value(&self) -> &str {
61        match self {
62            ConfigKeys::KeyUrl => "url",
63            ConfigKeys::KeyClientId => "clientId",
64            ConfigKeys::KeyClientKey => "clientKey",
65            ConfigKeys::KeyAppKey => "appKey",
66            ConfigKeys::KeyOwnerPublicKey => "appOwnerPublicKey",
67            ConfigKeys::KeyPrivateKey => "privateKey",
68            ConfigKeys::KeyServerPublicKeyId => "serverPublicKeyId",
69            ConfigKeys::KeyBindingToken => "bat",
70            ConfigKeys::KeyBindingKey => "bindingKey",
71            ConfigKeys::KeyHostname => "hostname",
72        }
73    }
74
75    /// Returns an optional `ConfigKeys` enum variant corresponding to the provided string value.
76    ///
77    /// # Parameters
78    ///
79    /// - `value`: The string representation of the key.
80    ///
81    /// # Returns
82    ///
83    /// An `Option<ConfigKeys>` that will be `Some` if the string corresponds to a valid key,
84    /// and `None` otherwise.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use keeper_secrets_manager_core::config_keys::ConfigKeys;
90    /// assert_eq!(ConfigKeys::key_from_str("url"), Some(ConfigKeys::KeyUrl));
91    /// assert_eq!(ConfigKeys::key_from_str("clientId"), Some(ConfigKeys::KeyClientId));
92    /// assert_eq!(ConfigKeys::key_from_str("unknown"), None);
93    /// ```
94    pub fn key_from_str(value: &str) -> Option<Self> {
95        match value {
96            "url" => Some(ConfigKeys::KeyUrl),
97            "clientId" => Some(ConfigKeys::KeyClientId),
98            "clientKey" => Some(ConfigKeys::KeyClientKey),
99            "appKey" => Some(ConfigKeys::KeyAppKey),
100            "appOwnerPublicKey" => Some(ConfigKeys::KeyOwnerPublicKey),
101            "privateKey" => Some(ConfigKeys::KeyPrivateKey),
102            "serverPublicKeyId" => Some(ConfigKeys::KeyServerPublicKeyId),
103            "bat" => Some(ConfigKeys::KeyBindingToken),
104            "bindingKey" => Some(ConfigKeys::KeyBindingKey),
105            "hostname" => Some(ConfigKeys::KeyHostname),
106            _ => None,
107        }
108    }
109
110    /// Returns an optional `ConfigKeys` enum variant from a string value,
111    /// allowing for additional variants using both the key name and the enum variant name.
112    ///
113    /// # Parameters
114    ///
115    /// - `value`: The string representation of the key.
116    ///
117    /// # Returns
118    ///
119    /// An `Option<ConfigKeys>` that will be `Some` if the string corresponds to a valid key,
120    /// and `None` otherwise.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use keeper_secrets_manager_core::config_keys::ConfigKeys;
126    /// assert_eq!(ConfigKeys::get_enum("url"), Some(ConfigKeys::KeyUrl));
127    /// assert_eq!(ConfigKeys::get_enum("clientId"), Some(ConfigKeys::KeyClientId));
128    /// assert_eq!(ConfigKeys::get_enum("invalidKey"), None);
129    /// ```
130    pub fn get_enum(value: &str) -> Option<Self> {
131        match value {
132            "url"  => Some(ConfigKeys::KeyUrl),
133            "clientId"  => Some(ConfigKeys::KeyClientId),
134            "clientKey"  => Some(ConfigKeys::KeyClientKey),
135            "appKey" => Some(ConfigKeys::KeyAppKey),
136            "appOwnerPublicKey" => Some(ConfigKeys::KeyOwnerPublicKey),
137            "privateKey" => Some(ConfigKeys::KeyPrivateKey),
138            "serverPublicKeyId"  => Some(ConfigKeys::KeyServerPublicKeyId),
139            "bat"  => Some(ConfigKeys::KeyBindingToken),
140            "bindingKey"  => Some(ConfigKeys::KeyBindingKey),
141            "hostname"  => Some(ConfigKeys::KeyHostname),
142            _ => None,
143        }
144    }
145}
146
147/// Custom deserialization function for a `HashMap<ConfigKeys, String>`.
148///
149/// This function deserializes a map from a JSON string into a `HashMap` where the keys
150/// are of type `ConfigKeys`. If an invalid key is encountered, it returns an error.
151///
152/// # Parameters
153///
154/// - `json_data`: A string containing the JSON structure that represents the map.
155///
156/// # Returns
157///
158/// A `Result<HashMap<ConfigKeys, String>, serde_json::Error>` that contains the deserialized
159/// `HashMap` if successful, or an error if an invalid key is found or if the input JSON is invalid.
160///
161/// # Examples
162///
163/// ```
164/// use keeper_secrets_manager_core::config_keys::{ConfigKeys, deserialize_map_from_str};
165/// use std::collections::HashMap;
166///
167/// let json_data = r#"{"url": "http://example.com"}"#;
168///
169/// // Use the function to deserialize the JSON string directly into a HashMap<ConfigKeys, String>
170/// let result: HashMap<ConfigKeys, String> = deserialize_map_from_str(json_data).unwrap();
171/// assert_eq!(result.get(&ConfigKeys::KeyUrl), Some(&"http://example.com".to_string()));
172/// ```
173///
174/// # Errors
175///
176/// This function will return a `serde_json::Error` if any key in the input map is not valid
177/// according to the `ConfigKeys` enum or if the JSON structure is malformed.
178///
179/// # Panics
180///
181/// This function does not panic under normal circumstances.
182pub fn deserialize_map_from_str(json_data: &str) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
183    let map: HashMap<String, String> = serde_json::from_str(json_data)
184        .map_err(|e| KSMRError::SerializationError(format!("JSON deserialization error: {}", e)))?;
185    let mut result = HashMap::new();
186
187    for (key, value) in map {
188        if let Some(enum_key) = ConfigKeys::key_from_str(&key) {
189            result.insert(enum_key, value);
190        } else {
191            return Err(KSMRError::SerializationError(format!(
192                "Failed to parse JSON: {}",
193                key
194            )));
195        }
196    }
197    Ok(result)
198}