Skip to main content

keeper_secrets_manager_core/
cache.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 crate::custom_error::KSMRError;
14use serde::{Deserialize, Serialize};
15use std::fs::{File, OpenOptions};
16use std::io::{Read, Write};
17use std::path::{Path, PathBuf};
18use std::{env, fs};
19
20const DEFAULT_FILE_PATH: &str = "ksm_cache.bin";
21
22#[derive(Clone, Debug)]
23pub enum KSMCache {
24    File(FileCache),
25    Memory(MemoryCache),
26    None,
27}
28
29impl KSMCache {
30    pub fn is_none(&self) -> bool {
31        // match self {
32        //     KSMCache::None => true,
33        //     _ => false,
34        // }
35
36        matches!(self, KSMCache::None)
37    }
38}
39
40#[derive(Debug)]
41pub struct KSMRCache {
42    cache: KSMCache,
43}
44
45impl KSMCache {
46    pub fn save_cached_value(&mut self, data: &[u8]) -> Result<(), KSMRError> {
47        match self {
48            KSMCache::File(file_cache) => file_cache.save_cached_value(data),
49            KSMCache::Memory(memory_cache) => memory_cache.save_cached_value(data),
50            KSMCache::None => Err(KSMRError::CacheSaveError(
51                "No cache available for saving data.".to_string(),
52            )),
53        }
54    }
55
56    pub fn get_cached_value(&self) -> Result<Vec<u8>, KSMRError> {
57        match self {
58            KSMCache::File(file_cache) => file_cache.get_cached_value(),
59            KSMCache::Memory(memory_cache) => memory_cache.get_cached_value(),
60            KSMCache::None => Err(KSMRError::CacheRetrieveError(
61                "No cache available for retrieving data.".to_string(),
62            )),
63        }
64    }
65
66    pub fn purge(&mut self) -> Result<(), KSMRError> {
67        match self {
68            KSMCache::File(file_cache) => file_cache.purge(),
69            KSMCache::Memory(memory_cache) => memory_cache.purge(),
70            KSMCache::None => Ok(()), // No-op for None cache
71        }
72    }
73}
74
75impl KSMRCache {
76    pub fn new_file_cache(file_path: Option<&str>) -> Result<Self, KSMRError> {
77        let file_cache = FileCache::new(file_path.unwrap_or(DEFAULT_FILE_PATH))?;
78        Ok(Self {
79            cache: KSMCache::File(file_cache),
80        })
81    }
82
83    /// This is not persistent and is not useful for most use cases, please prefer `new_file_cache` over this implementation.
84    pub fn new_memory_cache() -> Result<Self, KSMRError> {
85        Ok(Self {
86            cache: KSMCache::Memory(MemoryCache::new()),
87        })
88    }
89
90    pub fn new_none() -> Self {
91        Self {
92            cache: KSMCache::None,
93        }
94    }
95
96    pub fn save_cached_value(&mut self, data: &[u8]) -> Result<(), KSMRError> {
97        match &mut self.cache {
98            KSMCache::File(file_cache) => file_cache.save_cached_value(data),
99            KSMCache::Memory(memory_cache) => memory_cache.save_cached_value(data),
100            KSMCache::None => Err(KSMRError::CacheSaveError(
101                "No cache available for saving data.".to_string(),
102            )),
103        }
104    }
105
106    pub fn get_cached_value(&self) -> Result<Vec<u8>, KSMRError> {
107        match &self.cache {
108            KSMCache::File(file_cache) => file_cache.get_cached_value(),
109            KSMCache::Memory(memory_cache) => memory_cache.get_cached_value(),
110            KSMCache::None => Err(KSMRError::CacheRetrieveError(
111                "No cache available for retrieving data.".to_string(),
112            )),
113        }
114    }
115
116    pub fn purge(&mut self) -> Result<(), KSMRError> {
117        match &mut self.cache {
118            KSMCache::File(file_cache) => file_cache.purge(),
119            KSMCache::Memory(memory_cache) => memory_cache.purge(),
120            KSMCache::None => Ok(()), // No-op for None cache
121        }
122    }
123}
124
125impl From<KSMRCache> for KSMCache {
126    fn from(ksmr_cache: KSMRCache) -> Self {
127        ksmr_cache.cache
128    }
129}
130
131impl From<KSMCache> for KSMRCache {
132    fn from(ksm_cache: KSMCache) -> Self {
133        KSMRCache { cache: ksm_cache }
134    }
135}
136
137// File-based cache
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct FileCache {
140    file_path: String,
141}
142
143impl FileCache {
144    pub fn new(file_path: &str) -> Result<Self, KSMRError> {
145        let mut path = file_path.trim().to_string();
146
147        if path.is_empty() {
148            path = DEFAULT_FILE_PATH.to_string();
149        }
150
151        if !Path::new(&path).is_absolute() {
152            if let Ok(ksm_cache_dir) = env::var("KSM_CACHE_DIR") {
153                let ksm_cache_dir = ksm_cache_dir.trim();
154                if !ksm_cache_dir.is_empty() {
155                    path = PathBuf::from(ksm_cache_dir)
156                        .join(&path)
157                        .to_string_lossy()
158                        .to_string();
159                }
160            }
161        }
162        let mut file_opened = match File::open(path.clone()) {
163            Ok(resp) => resp,
164            Err(err) => {
165                if err.to_string().contains("No such file or directory")
166                    || err
167                        .to_string()
168                        .contains("The system cannot find the file specified")
169                {
170                    OpenOptions::new()
171                        .read(true)
172                        .write(true)
173                        .create(true)
174                        .truncate(true)
175                        .open(file_path)
176                        .map_err(|err| {
177                            KSMRError::CacheSaveError(format!(
178                                "Error creating cache file at {}: {}",
179                                file_path, err
180                            ))
181                        })?
182                } else {
183                    return Err(KSMRError::CacheSaveError(format!(
184                        "Error opening cache file at {}: {}",
185                        path, err
186                    )));
187                }
188            }
189        };
190
191        file_opened.flush().map_err(|e| {
192            KSMRError::CacheSaveError(format!("Error flushing cache file at {}: {}", path, e))
193        })?;
194
195        Ok(FileCache { file_path: path })
196    }
197
198    pub fn save_cached_value(&self, data: &[u8]) -> Result<(), KSMRError> {
199        let data = if data.is_empty() { &[] } else { data };
200        let mut file =
201            File::create(&self.file_path).map_err(|e| KSMRError::CacheSaveError(e.to_string()))?;
202        file.write_all(data)
203            .map_err(|e| KSMRError::CacheSaveError(e.to_string()))?;
204        Ok(())
205    }
206
207    pub fn get_cached_value(&self) -> Result<Vec<u8>, KSMRError> {
208        let mut file = File::open(&self.file_path)
209            .map_err(|e| KSMRError::CacheRetrieveError(e.to_string()))?;
210        let mut data = Vec::new();
211        file.read_to_end(&mut data)
212            .map_err(|e| KSMRError::CacheRetrieveError(e.to_string()))?;
213        Ok(data)
214    }
215
216    pub fn purge(&self) -> Result<(), KSMRError> {
217        if Path::new(&self.file_path).exists() {
218            fs::remove_file(&self.file_path)
219                .map_err(|e| KSMRError::CachePurgeError(e.to_string()))?;
220        }
221        Ok(())
222    }
223}
224
225// In-memory cache
226#[derive(Debug, Clone, Default, Serialize, Deserialize)]
227pub struct MemoryCache {
228    data: Vec<u8>,
229}
230
231impl MemoryCache {
232    pub fn new() -> Self {
233        Self { data: Vec::new() }
234    }
235
236    pub fn save_cached_value(&mut self, data: &[u8]) -> Result<(), KSMRError> {
237        self.data.clear();
238        self.data.extend_from_slice(data);
239        Ok(())
240    }
241
242    pub fn get_cached_value(&self) -> Result<Vec<u8>, KSMRError> {
243        Ok(self.data.clone())
244    }
245
246    pub fn purge(&mut self) -> Result<(), KSMRError> {
247        self.data.clear();
248        Ok(())
249    }
250}