quick_flash/
credentials_manager.rs

1use crate::credentials::Credentials;
2use anyhow::{self, Context};
3use chrono::Utc;
4use std::{
5    hash::{DefaultHasher, Hash, Hasher},
6    path::PathBuf,
7};
8
9pub struct CredentialsManager {
10    base_path: PathBuf,
11}
12
13impl CredentialsManager {
14    pub fn new(base_path: PathBuf) -> Self {
15        CredentialsManager { base_path }
16    }
17
18    pub fn get_all(&self) -> anyhow::Result<Vec<Credentials>> {
19        if !self.base_path.exists() {
20            return Ok(vec![]);
21        }
22
23        self.base_path
24            .read_dir()
25            .context("Failed to read from credentials directory")?
26            .map(|entry| {
27                let path = entry?.path();
28                Credentials::read_from_path(&path)
29            })
30            .collect()
31    }
32
33    pub fn remove(&self, user_storage_name: &str) -> anyhow::Result<()> {
34        self.base_path
35            .read_dir()
36            .context("Failed to read from credentials directory")?
37            .find(|entry| {
38                let path = entry.as_ref().map_or_else(|_| PathBuf::new(), |e| e.path());
39                Credentials::read_from_path(&path)
40                    .ok()
41                    .map_or(false, |c| c.user_storage_name == user_storage_name)
42            })
43            .context("Credentials not found")?
44            .and_then(|path| std::fs::remove_file(path.path()))
45            .context("Failed to remove credentials file")?;
46        Ok(())
47    }
48
49    pub fn add(&self, creds: Credentials) -> anyhow::Result<()> {
50        if !self.base_path.exists() {
51            std::fs::create_dir_all(&self.base_path)
52                .context("Failed to create credentials directory")?;
53        }
54
55        if creds.user_storage_name.is_empty() {
56            anyhow::bail!("User storage name cannot be empty");
57        }
58
59        /* check if credentials with the same name do not exist already */
60        self.get_all().and_then(|existing_creds| {
61            if existing_creds
62                .iter()
63                .any(|c| c.user_storage_name == creds.user_storage_name)
64            {
65                anyhow::bail!("Credentials with the same name already exist");
66            }
67
68            let mut hasher = DefaultHasher::new();
69            creds.hash(&mut hasher);
70
71            let name = format!(
72                "{}_{:0x}.toml",
73                Utc::now().format("%Y-%m-%d_%H-%M-%S"),
74                hasher.finish()
75            );
76            let path = self.base_path.join(name);
77            creds.write_to_path(&path)
78        })
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use tempfile::tempdir;
86
87    #[test]
88    fn test_credentials_manager() {
89        let temp_dir = tempdir().unwrap();
90        let creds_dir = temp_dir.path().join("creds");
91        let creds_manager = CredentialsManager::new(creds_dir.clone());
92        assert_eq!(creds_manager.get_all().unwrap().len(), 0);
93
94        assert_eq!(
95            creds_manager.remove("test").err().unwrap().to_string(),
96            "Failed to read from credentials directory"
97        );
98
99        let creds = Credentials::new_r2(
100            "test".to_string(),
101            "storage_name".to_string(),
102            "account_id".to_string(),
103            "access_key".to_string(),
104            "secret_key".to_string(),
105        );
106
107        creds_manager.add(creds.clone()).unwrap();
108        let all_creds = creds_manager.get_all().unwrap();
109        assert_eq!(all_creds.len(), 1);
110        assert_eq!(all_creds[0], creds);
111
112        let creds2 = Credentials::new_r2(
113            "test2".to_string(),
114            "storage_name".to_string(),
115            "account_id".to_string(),
116            "access_key".to_string(),
117            "secret_key".to_string(),
118        );
119
120        creds_manager.add(creds2.clone()).unwrap();
121        let all_creds = creds_manager.get_all().unwrap();
122        assert_eq!(all_creds.len(), 2);
123        assert!(all_creds.contains(&creds));
124        assert!(all_creds.contains(&creds2));
125
126        creds_manager.remove("test").unwrap();
127        let all_creds = creds_manager.get_all().unwrap();
128        assert_eq!(all_creds.len(), 1);
129        assert_eq!(all_creds[0].user_storage_name, "test2");
130
131        creds_manager.remove("test2").unwrap();
132        let all_creds = creds_manager.get_all().unwrap();
133        assert_eq!(all_creds.len(), 0);
134
135        assert_eq!(
136            creds_manager.remove("test").err().unwrap().to_string(),
137            "Credentials not found"
138        );
139        assert_eq!(
140            creds_manager.remove("test2").err().unwrap().to_string(),
141            "Credentials not found"
142        );
143        assert_eq!(creds_manager.get_all().unwrap().len(), 0);
144    }
145}