use crate::config::AccountConfig;
use secret::Secret;
pub fn init_keyring() {
init_keyring_with_service("agentmail");
}
pub fn init_keyring_with_service(name: &'static str) {
secret::keyring::set_global_service_name(name);
}
pub async fn get_password(account_name: &str, config: &AccountConfig) -> crate::Result<String> {
let env_key = format!(
"AGENTMAIL_PASSWORD_{}",
account_name.to_uppercase().replace(['-', ' '], "_")
);
if let Ok(pw) = std::env::var(&env_key) {
return Ok(pw);
}
if let Some(ref secret) = config.password {
let pw = secret.get().await.map_err(|e| {
crate::AgentmailError::Credential(format!(
"Failed to retrieve password for account '{}': {}",
account_name, e
))
})?;
return Ok(pw);
}
let default_entry = secret::keyring::KeyringEntry::try_new(&config.username).map_err(|e| {
crate::AgentmailError::Credential(format!(
"Failed to create default keyring entry for '{}': {}",
config.username, e
))
})?;
let default_secret = Secret::new_keyring_entry(default_entry);
if let Ok(pw) = default_secret.get().await {
return Ok(pw);
}
Err(crate::AgentmailError::Credential(format!(
"No password found for account '{}' (user='{}').\n\
Configure it in config.toml:\n \
password.keyring = \"{}\"\n \
password.cmd = \"security find-internet-password -s {} -a {} -w\"\n\
Or store it: agentmail set-password --account {}",
account_name, config.username, config.username, config.host, config.username, account_name
)))
}
pub async fn set_password(
account_name: &str,
config: &AccountConfig,
password: &str,
) -> crate::Result<()> {
let mut secret = match config.password {
Some(ref s @ Secret::Keyring(_)) => s.clone(),
_ => {
let entry = secret::keyring::KeyringEntry::try_new(&config.username).map_err(|e| {
crate::AgentmailError::Credential(format!(
"Failed to create keyring entry for '{}': {}",
config.username, e
))
})?;
Secret::new_keyring_entry(entry)
}
};
secret.set(password).await.map_err(|e| {
crate::AgentmailError::Credential(format!(
"Failed to store password for account '{}': {}",
account_name, e
))
})?;
Ok(())
}