Skip to main content

koan_core/
credentials.rs

1use keyring::Entry;
2use thiserror::Error;
3
4const SERVICE_NAME: &str = "koan";
5
6#[derive(Debug, Error)]
7pub enum CredentialError {
8    #[error("keyring error: {0}")]
9    Keyring(#[from] keyring::Error),
10    #[error("password not found")]
11    NotFound,
12}
13
14/// Store a password in the platform credential store.
15/// macOS: Keychain. Linux: secret-service (GNOME Keyring / KDE Wallet).
16/// `account` should be the server URL or identifier.
17pub fn store_password(account: &str, password: &str) -> Result<(), CredentialError> {
18    let entry = Entry::new(SERVICE_NAME, account)?;
19    entry.set_password(password)?;
20    Ok(())
21}
22
23/// Retrieve a password from the platform credential store.
24pub fn get_password(account: &str) -> Result<String, CredentialError> {
25    let entry = Entry::new(SERVICE_NAME, account)?;
26    match entry.get_password() {
27        Ok(pw) => Ok(pw),
28        Err(keyring::Error::NoEntry) => Err(CredentialError::NotFound),
29        Err(e) => Err(CredentialError::Keyring(e)),
30    }
31}
32
33/// Delete a password from the platform credential store.
34pub fn delete_password(account: &str) -> Result<(), CredentialError> {
35    let entry = Entry::new(SERVICE_NAME, account)?;
36    entry.delete_credential()?;
37    Ok(())
38}