use std::collections::HashMap;
#[derive(Debug)]
pub enum Platform {
Linux,
Windows,
MacOs,
Ios,
}
#[derive(Debug, Clone, PartialEq)]
pub struct LinuxCredential {
pub collection: String,
pub attributes: HashMap<String, String>,
pub label: String,
}
impl LinuxCredential {
pub fn attributes(&self) -> HashMap<&str, &str> {
self.attributes
.iter()
.map(|(k, v)| (k.as_str(), v.as_str()))
.collect()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct WinCredential {
pub username: String,
pub target_name: String,
pub target_alias: String,
pub comment: String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MacCredential {
pub domain: MacKeychainDomain,
pub service: String,
pub account: String,
}
#[derive(Debug, Clone, PartialEq)]
pub enum MacKeychainDomain {
User,
System,
Common,
Dynamic,
}
impl From<&str> for MacKeychainDomain {
fn from(keychain: &str) -> Self {
match keychain.to_ascii_lowercase().as_str() {
"system" => MacKeychainDomain::System,
"common" => MacKeychainDomain::Common,
"dynamic" => MacKeychainDomain::Dynamic,
_ => MacKeychainDomain::User,
}
}
}
impl From<Option<&str>> for MacKeychainDomain {
fn from(keychain: Option<&str>) -> Self {
match keychain {
None => MacKeychainDomain::User,
Some(str) => str.into(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct IosCredential {
pub service: String,
pub account: String,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PlatformCredential {
Linux(LinuxCredential),
Win(WinCredential),
Mac(MacCredential),
Ios(IosCredential),
}
impl PlatformCredential {
pub fn matches_platform(&self, os: &Platform) -> bool {
match self {
PlatformCredential::Linux(_) => matches!(os, Platform::Linux),
PlatformCredential::Win(_) => matches!(os, Platform::Windows),
PlatformCredential::Mac(_) => matches!(os, Platform::MacOs),
PlatformCredential::Ios(_) => matches!(os, Platform::Ios),
}
}
}
pub fn default_target(
platform: &Platform,
target: Option<&str>,
service: &str,
username: &str,
) -> PlatformCredential {
const VERSION: &str = env!("CARGO_PKG_VERSION");
let custom = if target.is_none() {
"entry"
} else {
"custom entry"
};
let metadata = format!(
"keyring-rs v{} {} for service '{}', user '{}'",
VERSION, custom, service, username
);
match platform {
Platform::Linux => PlatformCredential::Linux(LinuxCredential {
collection: target.unwrap_or("default").to_string(),
attributes: HashMap::from([
("service".to_string(), service.to_string()),
("username".to_string(), username.to_string()),
("application".to_string(), "rust-keyring".to_string()),
]),
label: metadata,
}),
Platform::Windows => {
if let Some(keychain) = target {
PlatformCredential::Win(WinCredential {
username: username.to_string(),
target_name: keychain.to_string(),
target_alias: String::new(),
comment: metadata,
})
} else {
PlatformCredential::Win(WinCredential {
username: username.to_string(),
target_name: format!("{}.{}", username, service),
target_alias: String::new(),
comment: metadata,
})
}
}
Platform::MacOs => PlatformCredential::Mac(MacCredential {
domain: target.into(),
service: service.to_string(),
account: username.to_string(),
}),
Platform::Ios => PlatformCredential::Ios(IosCredential {
service: service.to_string(),
account: username.to_string(),
}),
}
}