apple_security/
passwords_options.rs1use core_foundation::{string::CFString, base::{CFType, TCFType, CFOptionFlags}, number::CFNumber};
4use apple_security_sys::{keychain::{SecProtocolType, SecAuthenticationType}, access_control::*};
5use apple_security_sys::item::{
6 kSecAttrAccessControl, kSecAttrAccount, kSecAttrAuthenticationType, kSecAttrPath, kSecAttrPort, kSecAttrProtocol,
7 kSecAttrSecurityDomain, kSecAttrServer, kSecAttrService, kSecClass, kSecClassGenericPassword,
8 kSecClassInternetPassword,
9};
10use crate::access_control::SecAccessControl;
11
12pub struct PasswordOptions {
14 pub query: Vec<(CFString, CFType)>,
16}
17
18bitflags::bitflags! {
19 pub struct AccessControlOptions: CFOptionFlags {
21 const USER_PRESENCE = kSecAccessControlUserPresence;
23 #[cfg(feature = "OSX_10_13")]
24 const BIOMETRY_ANY = kSecAccessControlBiometryAny;
26 #[cfg(feature = "OSX_10_13")]
27 const BIOMETRY_CURRENT_SET = kSecAccessControlBiometryCurrentSet;
29 const DEVICE_PASSCODE = kSecAccessControlDevicePasscode;
31 #[cfg(feature = "OSX_10_15")]
32 const WATCH = kSecAccessControlWatch;
34 const OR = kSecAccessControlOr;
36 const AND = kSecAccessControlAnd;
38 const PRIVATE_KEY_USAGE = kSecAccessControlPrivateKeyUsage;
40 const APPLICATION_PASSWORD = kSecAccessControlApplicationPassword;
42 }
43}
44
45impl PasswordOptions {
46 #[must_use] pub fn new_generic_password(service: &str, account: &str) -> Self {
50 let query = vec![
51 (
52 unsafe { CFString::wrap_under_get_rule(kSecClass) },
53 unsafe { CFString::wrap_under_get_rule(kSecClassGenericPassword).into_CFType() },
54 ),
55 (
56 unsafe { CFString::wrap_under_get_rule(kSecAttrService) },
57 CFString::from(service).into_CFType(),
58 ),
59 (
60 unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) },
61 CFString::from(account).into_CFType(),
62 ),
63 ];
64 Self { query }
65 }
66
67 #[must_use] pub fn new_internet_password(
71 server: &str,
72 security_domain: Option<&str>,
73 account: &str,
74 path: &str,
75 port: Option<u16>,
76 protocol: SecProtocolType,
77 authentication_type: SecAuthenticationType,
78 ) -> Self {
79 let mut query = vec![
80 (
81 unsafe { CFString::wrap_under_get_rule(kSecClass) },
82 unsafe { CFString::wrap_under_get_rule(kSecClassInternetPassword) }.into_CFType(),
83 ),
84 (
85 unsafe { CFString::wrap_under_get_rule(kSecAttrServer) },
86 CFString::from(server).into_CFType(),
87 ),
88 (
89 unsafe { CFString::wrap_under_get_rule(kSecAttrPath) },
90 CFString::from(path).into_CFType(),
91 ),
92 (
93 unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) },
94 CFString::from(account).into_CFType(),
95 ),
96 (
97 unsafe { CFString::wrap_under_get_rule(kSecAttrProtocol) },
98 CFNumber::from(protocol as i32).into_CFType(),
99 ),
100 (
101 unsafe { CFString::wrap_under_get_rule(kSecAttrAuthenticationType) },
102 CFNumber::from(authentication_type as i32).into_CFType(),
103 ),
104 ];
105 if let Some(domain) = security_domain {
106 query.push((
107 unsafe { CFString::wrap_under_get_rule(kSecAttrSecurityDomain) },
108 CFString::from(domain).into_CFType(),
109 ))
110 }
111 if let Some(port) = port {
112 query.push((
113 unsafe { CFString::wrap_under_get_rule(kSecAttrPort) },
114 CFNumber::from(i32::from(port)).into_CFType(),
115 ))
116 }
117 Self { query }
118 }
119
120 pub fn set_access_control_options(&mut self, options: AccessControlOptions) {
122 self.query.push((
123 unsafe { CFString::wrap_under_get_rule(kSecAttrAccessControl) },
124 SecAccessControl::create_with_flags(options.bits())
125 .unwrap()
126 .into_CFType(),
127 ))
128 }
129}