use crate::error::{KeyringError, Result};
use crate::*;
use security_framework::base::Error as SfError;
use security_framework::passwords::{
delete_generic_password, get_generic_password, set_generic_password,
};
pub type OSStatus = i32;
#[allow(non_upper_case_globals)]
const errSecItemNotFound: OSStatus = -25300;
#[allow(non_upper_case_globals)]
#[inline(always)]
fn map_keyring_error(err: SfError) -> KeyringError {
match err.code() {
errSecItemNotFound => KeyringError::NoPasswordFound,
err => KeyringError::from(err),
}
}
pub struct IosKeyringManager {
application: String,
}
impl IosKeyringManager {
pub fn new(application: &str) -> Result<Self> {
Ok(IosKeyringManager {
application: application.to_owned(),
})
}
pub fn with_keyring<F, T>(&self, service: &str, key: &str, func: F) -> Result<T>
where
F: FnOnce(&mut dyn Keyring) -> Result<T>,
{
let mut kr = IosKeyring::new(&self.application, service, key)?;
func(&mut kr)
}
}
pub struct IosKeyring<'a> {
application: &'a str,
service: &'a str,
key: &'a str,
}
impl<'a> IosKeyring<'a> {
fn new(application: &'a str, service: &'a str, key: &'a str) -> Result<IosKeyring<'a>> {
Ok(IosKeyring {
application,
service,
key,
})
}
fn make_key_string(&self) -> String {
[
crate::escape(self.application),
crate::escape(self.service),
crate::escape(self.key),
]
.join("\t")
}
}
impl<'a> Keyring for IosKeyring<'a> {
fn set_value(&mut self, value: &str) -> Result<()> {
let account_name = self.make_key_string();
set_generic_password("", &account_name, value.as_bytes()).map_err(map_keyring_error)?;
Ok(())
}
fn get_value(&self) -> Result<String> {
let account_name = self.make_key_string();
let data = get_generic_password("", &account_name).map_err(map_keyring_error)?;
let mut buf = Vec::new();
buf.extend_from_slice(&data);
String::from_utf8(buf).map_err(|e| {
KeyringError::from(format!("couldn't convert keychain data to string: {}", e))
})
}
fn delete_value(&mut self) -> Result<()> {
let account_name = self.make_key_string();
delete_generic_password("", &account_name).map_err(map_keyring_error)?;
Ok(())
}
}