keeper_secrets_manager_core/
storage.rs1use crate::config_keys::ConfigKeys;
14use crate::custom_error::KSMRError;
15use crate::enums::KvStoreType;
16use base64::{
17 engine::general_purpose::{STANDARD, STANDARD_NO_PAD},
18 Engine as _,
19};
20use serde_json::{self};
21use std::collections::HashMap;
22use std::fs::{File, OpenOptions};
23use std::io::{BufReader, Read, Write};
24use std::path::Path;
25use std::{env, fs};
26
27pub trait KeyValueStorage {
28 fn read_storage(&self) -> Result<HashMap<ConfigKeys, String>, KSMRError>;
29 fn save_storage(
30 &mut self,
31 updated_config: HashMap<ConfigKeys, String>,
32 ) -> Result<bool, KSMRError>;
33 fn get(&self, key: ConfigKeys) -> Result<Option<String>, KSMRError>;
34 fn set(
35 &mut self,
36 key: ConfigKeys,
37 value: String,
38 ) -> Result<HashMap<ConfigKeys, String>, KSMRError>;
39 fn delete(&mut self, key: ConfigKeys) -> Result<HashMap<ConfigKeys, String>, KSMRError>;
40 fn delete_all(&mut self) -> Result<HashMap<ConfigKeys, String>, KSMRError>;
41 fn contains(&self, key: ConfigKeys) -> Result<bool, KSMRError>;
42 fn create_config_file_if_missing(&self) -> Result<(), KSMRError>;
43 fn is_empty(&self) -> Result<bool, KSMRError>;
44}
45
46#[derive(Clone)]
47pub struct FileKeyValueStorage {
48 config_file_location: String,
49}
50
51impl FileKeyValueStorage {
52 const DEFAULT_CONFIG_FILE_LOCATION: &str = "client-config.json";
53 pub fn new(config_file_location: Option<String>) -> Result<Self, KSMRError> {
54 let location = config_file_location
55 .or_else(|| env::var("KSM_CONFIG_FILE").ok())
56 .unwrap_or_else(|| Self::DEFAULT_CONFIG_FILE_LOCATION.to_string());
57
58 Ok(FileKeyValueStorage {
59 config_file_location: location,
60 })
61 }
62
63 pub fn new_config_storage(file_name: String) -> Result<KvStoreType, KSMRError> {
64 let file_storage = FileKeyValueStorage::new(Some(file_name.to_string()))?;
65 Ok(KvStoreType::File(file_storage))
66 }
67}
68
69impl KeyValueStorage for FileKeyValueStorage {
70 fn read_storage(&self) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
71 self.create_config_file_if_missing().map_err(|err| {
73 KSMRError::StorageError(format!("Failed to ensure config file exists: {}", err))
74 })?;
75
76 let file = File::open(&self.config_file_location).map_err(|err| {
78 KSMRError::StorageError(format!(
79 "Unable to open config file {}: {}",
80 self.config_file_location, err
81 ))
82 })?;
83
84 let mut reader = BufReader::new(file);
86 let mut contents = String::new();
87 reader
88 .read_to_string(&mut contents)
89 .map_err(|err| KSMRError::StorageError(format!("Failed to read file: {}", err)))?;
90
91 let config_result: Result<HashMap<ConfigKeys, String>, KSMRError> =
93 serde_json::from_str(&contents)
94 .map_err(|err| KSMRError::StorageError(format!("Failed to parse JSON: {}", err)));
95
96 match config_result {
97 Ok(config) => Ok(config),
98 Err(err) => {
99 eprintln!("Failed to parse JSON: {}", err);
101 Err(KSMRError::StorageError(format!(
102 "Failed to parse JSON: {}",
103 err
104 )))
105 }
106 }
107 }
108
109 fn save_storage(
110 &mut self,
111 updated_config: HashMap<ConfigKeys, String>,
112 ) -> Result<bool, KSMRError> {
113 self.create_config_file_if_missing().map_err(|err| {
115 KSMRError::StorageError(format!("Failed to ensure config file exists: {}", err))
116 })?;
117
118 let mut file = OpenOptions::new()
120 .write(true)
121 .truncate(true) .open(&self.config_file_location)
123 .map_err(|err| {
124 KSMRError::StorageError(format!("Failed to open config file for writing: {}", err))
125 })?;
126
127 let json_data = serde_json::to_string_pretty(&updated_config).map_err(|err| {
129 KSMRError::StorageError(format!("Failed to serialize config to JSON: {}", err))
130 })?;
131
132 file.write_all(json_data.as_bytes()).map_err(|err| {
134 KSMRError::StorageError(format!("Failed to write JSON to config file: {}", err))
135 })?;
136
137 Ok(true)
138 }
139
140 fn get(&self, key: ConfigKeys) -> Result<Option<String>, KSMRError> {
141 let config: HashMap<ConfigKeys, String> = self
142 .read_storage()
143 .map_err(|err| KSMRError::StorageError(format!("Failed to Read storage: {}", err)))?;
144
145 Ok(config.get(&key).cloned())
147 }
148
149 fn set(
150 &mut self,
151 key: ConfigKeys,
152 value: String,
153 ) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
154 if ConfigKeys::get_enum(key.value()).is_none() {
156 return Err(KSMRError::StorageError(format!("Invalid key: {:?}", key)));
157 }
158
159 let mut config = self
161 .read_storage()
162 .map_err(|err| KSMRError::StorageError(format!("Failed to read storage: {}", err)))?;
163
164 config.insert(key, value);
166
167 self.save_storage(config.clone()).map_err(|err| {
169 KSMRError::StorageError(format!("Failed to save updated config: {}", err))
170 })?;
171
172 Ok(config) }
174
175 fn delete(&mut self, key: ConfigKeys) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
176 let mut config = self
178 .read_storage()
179 .map_err(|err| KSMRError::StorageError(format!("Failed to read storage: {}", err)))?;
180
181 if config.remove(&key).is_some() {
183 log::debug!("Removed key {}", key);
184 } else {
185 log::debug!("No key {} was found in config", key);
186 }
187
188 self.save_storage(config.clone()).map_err(|err| {
190 KSMRError::StorageError(format!("Failed to save updated config: {}", err))
191 })?;
192
193 Ok(config) }
195
196 fn delete_all(&mut self) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
197 let mut config = self
199 .read_storage()
200 .map_err(|e| KSMRError::StorageError(format!("Failed to read storage: {}", e)))?;
201
202 config.clear();
204
205 self.save_storage(config.clone()).map_err(|e| {
207 KSMRError::StorageError(format!("Failed to save cleared config: {}", e))
208 })?;
209
210 Ok(config) }
212
213 fn contains(&self, key: ConfigKeys) -> Result<bool, KSMRError> {
214 let config = self
216 .read_storage()
217 .map_err(|e| KSMRError::StorageError(format!("Failed to read storage: {}", e)))?;
218
219 Ok(config.contains_key(&key))
221 }
222
223 fn create_config_file_if_missing(&self) -> Result<(), KSMRError> {
224 if let Some(parent) = Path::new(&self.config_file_location).parent() {
226 fs::create_dir_all(parent)
227 .map_err(|e| KSMRError::DirectoryCreationError(parent.display().to_string(), e))?;
228 }
229
230 let config_path = Path::new(&self.config_file_location);
232 if !config_path.exists() {
233 #[cfg(unix)]
235 {
236 use std::fs::OpenOptions;
237 use std::os::unix::fs::OpenOptionsExt;
238
239 let mut file = OpenOptions::new()
240 .write(true)
241 .create(true)
242 .truncate(true)
243 .mode(0o600)
244 .open(config_path)
245 .map_err(|e| {
246 KSMRError::FileCreationError(config_path.display().to_string(), e)
247 })?;
248
249 let empty_json_string = b"{}";
251 file.write_all(empty_json_string)
252 .map_err(|e| KSMRError::FileWriteError(config_path.display().to_string(), e))?;
253 }
254
255 #[cfg(not(unix))]
257 {
258 let mut file = File::create(config_path).map_err(|e| {
259 KSMRError::FileCreationError(config_path.display().to_string(), e)
260 })?;
261
262 let empty_json_string = b"{}";
264 file.write_all(empty_json_string)
265 .map_err(|e| KSMRError::FileWriteError(config_path.display().to_string(), e))?;
266 }
267 }
268
269 Ok(())
270 }
271
272 fn is_empty(&self) -> Result<bool, KSMRError> {
273 let config = self
275 .read_storage()
276 .map_err(|e| KSMRError::StorageError(format!("Failed to read storage: {}", e)))?;
277
278 Ok(config.is_empty())
280 }
281}
282
283#[derive(Clone)]
284pub struct InMemoryKeyValueStorage {
285 config: HashMap<ConfigKeys, String>,
286}
287
288impl InMemoryKeyValueStorage {
289 pub fn new(config: Option<String>) -> Result<Self, KSMRError> {
290 let mut config_map: HashMap<ConfigKeys, String> = HashMap::new();
291
292 if let Some(cfg) = config {
293 if Self::is_base64(&cfg) {
294 let decoded_bytes = STANDARD
296 .decode(&cfg)
297 .or_else(|_| STANDARD_NO_PAD.decode(&cfg))
298 .map_err(|e| {
299 KSMRError::DecodeError(format!("Failed to decode Base64 string: {}", e))
300 })?;
301
302 let decoded_string = String::from_utf8(decoded_bytes).map_err(|e| {
303 KSMRError::StringConversionError(format!(
304 "Failed to convert decoded bytes to string: {}",
305 e
306 ))
307 })?;
308
309 config_map = Self::json_to_dict(&decoded_string)?;
310 } else {
311 config_map = Self::json_to_dict(&cfg)?;
313 }
314 }
315 Ok(InMemoryKeyValueStorage { config: config_map })
316 }
317
318 pub fn new_config_storage(config: Option<String>) -> Result<KvStoreType, KSMRError> {
319 let in_memory = InMemoryKeyValueStorage::new(config)?;
320 Ok(KvStoreType::InMemory(in_memory))
321 }
322
323 fn is_base64(s: &str) -> bool {
324 STANDARD.decode(s).is_ok() || STANDARD_NO_PAD.decode(s).is_ok()
326 }
327
328 pub fn json_to_dict(json_str: &str) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
329 let json_str = if json_str.is_empty() { "{}" } else { json_str };
331
332 let value: serde_json::Value = serde_json::from_str(json_str)
334 .map_err(|e| KSMRError::SerializationError(format!("Failed to parse JSON: {}", e)))?;
335
336 let mut result = HashMap::new();
337
338 if let serde_json::Value::Object(obj) = value {
340 for (k, v) in obj {
341 if let serde_json::Value::String(s) = v {
342 if let Some(key) = ConfigKeys::get_enum(&k) {
344 result.insert(key, s);
345 } else {
346 return Err(KSMRError::SerializationError(format!(
347 "Invalid key in JSON: {}",
348 k
349 )));
350 }
351 } else {
352 return Err(KSMRError::SerializationError(format!(
353 "Expected string value for key: {}",
354 k
355 )));
356 }
357 }
358 } else {
359 return Err(KSMRError::SerializationError(
360 "Expected JSON object".to_string(),
361 ));
362 }
363
364 Ok(result) }
366}
367
368impl KeyValueStorage for InMemoryKeyValueStorage {
369 fn read_storage(&self) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
370 Ok(self.config.clone()) }
372
373 fn save_storage(
374 &mut self,
375 _updated_config: HashMap<ConfigKeys, String>,
376 ) -> Result<bool, KSMRError> {
377 self.config = _updated_config;
379 Ok(true)
380 }
381
382 fn get(&self, key: ConfigKeys) -> Result<Option<String>, KSMRError> {
383 Ok(self.config.get(&key).cloned()) }
385
386 fn set(
387 &mut self,
388 key: ConfigKeys,
389 value: String,
390 ) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
391 self.config.insert(key, value.clone()); Ok(self.config.clone()) }
394
395 fn delete(&mut self, key: ConfigKeys) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
396 self.config.remove(&key); Ok(self.config.clone()) }
399
400 fn delete_all(&mut self) -> Result<HashMap<ConfigKeys, String>, KSMRError> {
401 self.config.clear(); Ok(self.config.clone()) }
404
405 fn contains(&self, key: ConfigKeys) -> Result<bool, KSMRError> {
406 Ok(self.config.contains_key(&key)) }
408
409 fn create_config_file_if_missing(&self) -> Result<(), KSMRError> {
410 Ok(())
412 }
413
414 fn is_empty(&self) -> Result<bool, KSMRError> {
415 Ok(self.config.is_empty()) }
417}