#![cfg_attr(docsrs, feature(doc_cfg))]
use log::debug;
use std::collections::HashMap;
use std::sync::Arc;
pub mod api;
pub mod attributes;
pub mod error;
pub mod mock;
#[cfg(feature = "sample")]
pub mod sample;
pub use api::{Credential, CredentialPersistence, CredentialStore};
pub use error::{Error, Result};
#[derive(Default, Debug)]
struct DefaultStore {
inner: Option<Arc<CredentialStore>>,
}
static DEFAULT_STORE: std::sync::RwLock<DefaultStore> =
std::sync::RwLock::new(DefaultStore { inner: None });
pub fn set_default_store(new: Arc<CredentialStore>) {
debug!("setting the default credential store to {new:?}");
let mut guard = DEFAULT_STORE
.write()
.expect("Poisoned RwLock in keyring_core::set_default_store: please report a bug!");
guard.inner = Some(new);
}
pub fn get_default_store() -> Option<Arc<CredentialStore>> {
debug!("getting the default credential store");
let guard = DEFAULT_STORE
.read()
.expect("Poisoned RwLock in keyring_core::get_default_store: please report a bug!");
guard.inner.clone()
}
pub fn unset_default_store() -> Option<Arc<CredentialStore>> {
debug!("unsetting the default credential store");
let mut guard = DEFAULT_STORE
.write()
.expect("Poisoned RwLock in keyring_core::unset_default_store: please report a bug!");
guard.inner.take()
}
fn build_default_credential(
service: &str,
user: &str,
attrs: Option<&HashMap<&str, &str>>,
) -> Result<Entry> {
let guard = DEFAULT_STORE
.read()
.expect("Poisoned RwLock in keyring-core::build_default_credential: please report a bug!");
match guard.inner.as_ref() {
Some(store) => store.build(service, user, attrs),
None => Err(Error::NoDefaultStore),
}
}
#[derive(Debug)]
pub struct Entry {
inner: Arc<Credential>,
}
impl Entry {
pub fn new(service: &str, user: &str) -> Result<Entry> {
debug!("creating entry with service {service}, user {user}");
let entry = build_default_credential(service, user, None)?;
debug!("created entry {:?}", entry.inner);
Ok(entry)
}
pub fn new_with_modifiers(
service: &str,
user: &str,
modifiers: &HashMap<&str, &str>,
) -> Result<Entry> {
debug!("creating entry with service {service}, user {user}, and mods {modifiers:?}");
let entry = build_default_credential(service, user, Some(modifiers))?;
debug!("created entry {:?}", entry.inner);
Ok(entry)
}
pub fn new_with_credential(credential: Arc<Credential>) -> Entry {
debug!("create entry wrapping {credential:?}");
Entry { inner: credential }
}
pub fn search(spec: &HashMap<&str, &str>) -> Result<Vec<Entry>> {
debug!("searching for {spec:?}");
let guard = DEFAULT_STORE.read().expect(
"Poisoned RwLock in keyring-core::search_for_credentials: please report a bug!",
);
match guard.inner.as_ref() {
Some(store) => store.search(spec),
None => Err(Error::NoDefaultStore),
}
}
pub fn set_password(&self, password: &str) -> Result<()> {
debug!("set password for entry {:?}", self.inner);
self.inner.set_password(password)
}
pub fn set_secret(&self, secret: &[u8]) -> Result<()> {
debug!("set secret for entry {:?}", self.inner);
self.inner.set_secret(secret)
}
pub fn get_password(&self) -> Result<String> {
debug!("get password from entry {:?}", self.inner);
self.inner.get_password()
}
pub fn get_secret(&self) -> Result<Vec<u8>> {
debug!("get secret from entry {:?}", self.inner);
self.inner.get_secret()
}
pub fn get_attributes(&self) -> Result<HashMap<String, String>> {
debug!("get attributes from entry {:?}", self.inner);
self.inner.get_attributes()
}
pub fn update_attributes(&self, attributes: &HashMap<&str, &str>) -> Result<()> {
debug!(
"update attributes for entry {:?} from map {attributes:?}",
self.inner
);
self.inner.update_attributes(attributes)
}
pub fn delete_credential(&self) -> Result<()> {
debug!("delete entry {:?}", self.inner);
self.inner.delete_credential()
}
pub fn get_credential(&self) -> Result<Entry> {
debug!("get credential for entry {:?}", self.inner);
match self.inner.get_credential() {
Ok(Some(inner)) => Ok(Entry { inner }),
Ok(None) => Ok(Entry {
inner: self.inner.clone(),
}),
Err(e) => Err(e),
}
}
pub fn get_specifiers(&self) -> Option<(String, String)> {
self.inner.get_specifiers()
}
pub fn as_any(&self) -> &dyn std::any::Any {
self.inner.as_any()
}
}
#[cfg(doctest)]
doc_comment::doctest!("../README.md", readme);