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}