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                    let file = OpenOptions::new()
171                    .read(true) // Open for reading
172                    .write(true) // Open for writing
173                    .create(true) // Create if it doesn't exist
174                    .truncate(true)// Overwrite if already existing
175                    .open(file_path).map_err(|err| KSMRError::CacheSaveError(format!("Error creating cache file in location mentioned {} and exited with error {}.", file_path,err))).unwrap();
176                    file
177                } else {
178                    panic!("{}", err);
179                }
180            }
181        };
182
183        file_opened.flush().unwrap();
184
185        Ok(FileCache { file_path: path })
186    }
187
188    pub fn save_cached_value(&self, data: &[u8]) -> Result<(), KSMRError> {
189        let data = if data.is_empty() { &[] } else { data };
190        let mut file =
191            File::create(&self.file_path).map_err(|e| KSMRError::CacheSaveError(e.to_string()))?;
192        file.write_all(data)
193            .map_err(|e| KSMRError::CacheSaveError(e.to_string()))?;
194        Ok(())
195    }
196
197    pub fn get_cached_value(&self) -> Result<Vec<u8>, KSMRError> {
198        let mut file = File::open(&self.file_path)
199            .map_err(|e| KSMRError::CacheRetrieveError(e.to_string()))?;
200        let mut data = Vec::new();
201        file.read_to_end(&mut data)
202            .map_err(|e| KSMRError::CacheRetrieveError(e.to_string()))?;
203        Ok(data)
204    }
205
206    pub fn purge(&self) -> Result<(), KSMRError> {
207        if Path::new(&self.file_path).exists() {
208            fs::remove_file(&self.file_path)
209                .map_err(|e| KSMRError::CachePurgeError(e.to_string()))?;
210        }
211        Ok(())
212    }
213}
214
215// In-memory cache
216#[derive(Debug, Clone, Default, Serialize, Deserialize)]
217pub struct MemoryCache {
218    data: Vec<u8>,
219}
220
221impl MemoryCache {
222    pub fn new() -> Self {
223        Self { data: Vec::new() }
224    }
225
226    pub fn save_cached_value(&mut self, data: &[u8]) -> Result<(), KSMRError> {
227        self.data.clear();
228        self.data.extend_from_slice(data);
229        Ok(())
230    }
231
232    pub fn get_cached_value(&self) -> Result<Vec<u8>, KSMRError> {
233        Ok(self.data.clone())
234    }
235
236    pub fn purge(&mut self) -> Result<(), KSMRError> {
237        self.data.clear();
238        Ok(())
239    }
240}