doum_cli/system/
secret.rs1use anyhow::{Context, Result};
2use keyring::Entry;
3use serde::{Deserialize, Serialize};
4
5pub trait ProviderSecret: Serialize + for<'de> Deserialize<'de> {
7 fn validate(&self) -> Result<()>;
9
10 fn masked(&self) -> String;
12}
13
14pub struct SecretManager;
16
17impl SecretManager {
18 pub fn save<T: ProviderSecret>(service_name: &str, secret: &T) -> Result<()> {
20 secret.validate()?;
22
23 let entry = Entry::new(service_name, "doum-cli").context("Failed to access keyring")?;
25 let value = serde_json::to_string(secret).context("Failed to serialize secret to JSON")?;
26 entry
27 .set_password(&value)
28 .context("Failed to save to keyring")?;
29
30 Ok(())
31 }
32
33 pub fn load<T: ProviderSecret>(service_name: &str) -> Result<T> {
35 let entry = Entry::new(service_name, "doum-cli").context("Failed to access keyring")?;
36
37 let secret_json = entry
38 .get_password()
39 .context("Failed to retrieve from keyring")?;
40
41 serde_json::from_str(&secret_json).context("Failed to parse secret")
42 }
43
44 pub fn delete(service_name: &str) -> Result<()> {
46 let entry = Entry::new(service_name, "doum-cli").context("Failed to access keyring")?;
47 entry
48 .delete_credential()
49 .context("Failed to delete from keyring")?;
50 Ok(())
51 }
52}