use crate::error::{KeyringError, Result};
use secret_service::{EncryptionType, SecretService};
use std::collections::HashMap;
pub struct Keyring<'a> {
attributes: HashMap<&'a str, &'a str>,
service: &'a str,
username: &'a str,
}
impl<'a> Keyring<'a> {
pub fn new(service: &'a str, username: &'a str) -> Keyring<'a> {
let attributes = HashMap::from([("service", service), ("username", username)]);
Keyring {
attributes,
service,
username,
}
}
pub fn set_password(&self, password: &str) -> Result<()> {
let ss = SecretService::new(EncryptionType::Dh)?;
let collection = ss.get_default_collection()?;
if collection.is_locked()? {
collection.unlock()?;
}
let mut attrs = self.attributes.clone();
attrs.insert("application", "rust-keyring");
let label = &format!("Password for {} on {}", self.username, self.service)[..];
collection.create_item(
label,
attrs,
password.as_bytes(),
true, "text/plain",
)?;
Ok(())
}
pub fn get_password(&self) -> Result<String> {
let ss = SecretService::new(EncryptionType::Dh)?;
let collection = ss.get_default_collection()?;
if collection.is_locked()? {
collection.unlock()?;
}
let search = collection.search_items(self.attributes.clone())?;
let item = search.get(0).ok_or(KeyringError::NoPasswordFound)?;
let secret_bytes = item.get_secret()?;
let secret = String::from_utf8(secret_bytes)?;
Ok(secret)
}
pub fn delete_password(&self) -> Result<()> {
let ss = SecretService::new(EncryptionType::Dh)?;
let collection = ss.get_default_collection()?;
if collection.is_locked()? {
collection.unlock()?;
}
let search = collection.search_items(self.attributes.clone())?;
let item = search.get(0).ok_or(KeyringError::NoPasswordFound)?;
Ok(item.delete()?)
}
}