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