pub use security_framework::base::Error;
use security_framework::passwords::{
delete_generic_password, get_generic_password, set_generic_password,
};
use super::credential::{Credential, CredentialApi, CredentialBuilder, CredentialBuilderApi};
use super::error::{decode_password, Error as ErrorCode, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IosCredential {
pub service: String,
pub account: String,
}
impl CredentialApi for IosCredential {
fn set_password(&self, password: &str) -> Result<()> {
set_generic_password(&self.service, &self.account, password.as_bytes())
.map_err(decode_error)?;
Ok(())
}
fn get_password(&self) -> Result<String> {
let password_bytes =
get_generic_password(&self.service, &self.account).map_err(decode_error)?;
decode_password(password_bytes.to_vec())
}
fn delete_password(&self) -> Result<()> {
delete_generic_password(&self.service, &self.account).map_err(decode_error)?;
Ok(())
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl IosCredential {
pub fn get_credential(&self) -> Result<Self> {
get_generic_password(&self.service, &self.account).map_err(decode_error)?;
Ok(self.clone())
}
pub fn new_with_target(target: Option<&str>, service: &str, user: &str) -> Result<Self> {
if service.is_empty() {
return Err(ErrorCode::Invalid(
"service".to_string(),
"cannot be empty".to_string(),
));
}
if user.is_empty() {
return Err(ErrorCode::Invalid(
"user".to_string(),
"cannot be empty".to_string(),
));
}
if let Some(target) = target {
if target.to_ascii_lowercase() != "default" {
return Err(ErrorCode::Invalid(
"target".to_string(),
"only 'default' is allowed".to_string(),
));
}
}
Ok(Self {
service: service.to_string(),
account: user.to_string(),
})
}
}
pub struct IosCredentialBuilder {}
pub fn default_credential_builder() -> Box<CredentialBuilder> {
Box::new(IosCredentialBuilder {})
}
impl CredentialBuilderApi for IosCredentialBuilder {
fn build(&self, target: Option<&str>, service: &str, user: &str) -> Result<Box<Credential>> {
Ok(Box::new(IosCredential::new_with_target(
target, service, user,
)?))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
fn decode_error(err: Error) -> ErrorCode {
match err.code() {
-25291 => ErrorCode::NoStorageAccess(Box::new(err)), -25292 => ErrorCode::NoStorageAccess(Box::new(err)), -25300 => ErrorCode::NoEntry, _ => ErrorCode::PlatformFailure(Box::new(err)),
}
}