1use crate::SyncError;
11use keyring::Entry;
12use sioul_core::config::Account;
13
14const SERVICE: &str = "sioul";
15
16fn entry(account: &Account) -> Result<Entry, SyncError> {
17 let host = account.host.as_deref().ok_or(SyncError::NoServer)?;
18 let login = account.login().ok_or(SyncError::NoServer)?;
19 Entry::new(SERVICE, &format!("{login} on {host}")).map_err(|e| SyncError::Keyring(e.to_string()))
20}
21
22pub fn save(account: &Account, password: &str) -> Result<(), SyncError> {
24 if testing() {
25 return Ok(());
26 }
27 entry(account)?.set_password(password).map_err(|e| SyncError::Keyring(e.to_string()))
28}
29
30fn testing() -> bool {
32 #[cfg(feature = "insecure-test-tls")]
33 if std::env::var_os("SIOUL_TEST_PASSWORD").is_some() {
34 return true;
35 }
36 false
37}
38
39pub fn password(account: &Account) -> Result<String, SyncError> {
44 if let Some(oauth) = crate::sasl::OAuth::of(account) {
45 return oauth.mark(account.login().ok_or(SyncError::NoServer)?);
46 }
47 #[cfg(feature = "insecure-test-tls")]
49 if let Ok(password) = std::env::var("SIOUL_TEST_PASSWORD") {
50 return Ok(password);
51 }
52 match entry(account)?.get_password() {
53 Ok(password) => Ok(password),
54 Err(keyring::Error::NoEntry) => Err(SyncError::NoPassword),
55 Err(e) => Err(SyncError::Keyring(e.to_string())),
56 }
57}
58
59fn passphrase_entry(fingerprint: &str) -> Result<Entry, SyncError> {
60 Entry::new(SERVICE, &format!("OpenPGP key {fingerprint}")).map_err(|e| SyncError::Keyring(e.to_string()))
61}
62
63pub fn pgp_passphrase(fingerprint: &str) -> Option<String> {
65 #[cfg(feature = "insecure-test-tls")]
66 if let Ok(passphrase) = std::env::var("SIOUL_TEST_PASSWORD") {
67 return Some(passphrase);
68 }
69 passphrase_entry(fingerprint).ok()?.get_password().ok()
70}
71
72pub fn test_passphrase() -> Option<String> {
75 #[cfg(feature = "insecure-test-tls")]
76 if let Ok(passphrase) = std::env::var("SIOUL_TEST_PASSWORD") {
77 return Some(passphrase);
78 }
79 None
80}
81
82pub fn save_pgp_passphrase(fingerprint: &str, passphrase: &str) -> Result<(), SyncError> {
84 if testing() {
85 return Ok(());
86 }
87 passphrase_entry(fingerprint)?.set_password(passphrase).map_err(|e| SyncError::Keyring(e.to_string()))
88}
89
90pub fn named(name: &str) -> Option<String> {
92 if testing() {
93 return None;
94 }
95 Entry::new(SERVICE, name).ok()?.get_password().ok()
96}
97
98pub fn save_named(name: &str, secret: &str) -> Result<(), SyncError> {
100 if testing() {
101 return Ok(());
102 }
103 Entry::new(SERVICE, name).and_then(|e| e.set_password(secret)).map_err(|e| SyncError::Keyring(e.to_string()))
104}
105
106pub fn forget_named(name: &str) -> Result<(), SyncError> {
108 if testing() {
109 return Ok(());
110 }
111 match Entry::new(SERVICE, name).and_then(|e| e.delete_credential()) {
112 Ok(()) | Err(keyring::Error::NoEntry) => Ok(()),
113 Err(e) => Err(SyncError::Keyring(e.to_string())),
114 }
115}
116
117pub fn forget(account: &Account) -> Result<(), SyncError> {
119 if testing() {
120 return Ok(());
121 }
122 match entry(account)?.delete_credential() {
123 Ok(()) | Err(keyring::Error::NoEntry) => Ok(()),
124 Err(e) => Err(SyncError::Keyring(e.to_string())),
125 }
126}