1use crate::access_control::SecAccessControl;
6use core_foundation::base::{CFOptionFlags, CFType, TCFType};
7#[allow(unused_imports)]
8use core_foundation::boolean::CFBoolean;
9use core_foundation::dictionary::CFDictionary;
10use core_foundation::number::CFNumber;
11use core_foundation::string::{CFString, CFStringRef};
12use security_framework_sys::access_control::*;
13use security_framework_sys::item::{
14 kSecAttrAccessControl, kSecAttrAccessGroup, kSecAttrAccount, kSecAttrAuthenticationType,
15 kSecAttrComment, kSecAttrDescription, kSecAttrLabel,
16 kSecAttrPath, kSecAttrPort, kSecAttrProtocol, kSecAttrSecurityDomain, kSecAttrServer,
17 kSecAttrService, kSecClass, kSecClassGenericPassword, kSecClassInternetPassword,
18};
19#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
20use security_framework_sys::item::kSecAttrSynchronizable;
21#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
22use security_framework_sys::item::kSecAttrSynchronizableAny;
23#[cfg(any(feature = "OSX_10_15", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
24use security_framework_sys::item::kSecUseDataProtectionKeychain;
25use security_framework_sys::keychain::{SecAuthenticationType, SecProtocolType};
26
27pub struct PasswordOptions {
29 #[deprecated(note = "This field should have been private. Please use setters that don't expose CFType")]
31 pub query: Vec<(CFString, CFType)>,
32}
33
34bitflags::bitflags! {
35 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37 pub struct AccessControlOptions: CFOptionFlags {
38 const USER_PRESENCE = kSecAccessControlUserPresence;
40 #[cfg(feature = "OSX_10_13")]
41 const BIOMETRY_ANY = kSecAccessControlBiometryAny;
43 #[cfg(feature = "OSX_10_13")]
44 const BIOMETRY_CURRENT_SET = kSecAccessControlBiometryCurrentSet;
46 const DEVICE_PASSCODE = kSecAccessControlDevicePasscode;
48 #[cfg(feature = "OSX_10_15")]
49 const WATCH = kSecAccessControlWatch;
51 const OR = kSecAccessControlOr;
53 const AND = kSecAccessControlAnd;
55 const PRIVATE_KEY_USAGE = kSecAccessControlPrivateKeyUsage;
57 const APPLICATION_PASSWORD = kSecAccessControlApplicationPassword;
59 }
60}
61
62impl PasswordOptions {
63 #[must_use]
67 pub fn new_generic_password(service: &str, account: &str) -> Self {
68 #[allow(deprecated)]
69 Self { query: vec![
70 (
71 unsafe { CFString::wrap_under_get_rule(kSecClass) },
72 unsafe { CFString::wrap_under_get_rule(kSecClassGenericPassword).into_CFType() },
73 ),
74 (unsafe { CFString::wrap_under_get_rule(kSecAttrService) }, CFString::from(service).into_CFType()),
75 (unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) }, CFString::from(account).into_CFType()),
76 ] }
77 }
78
79 #[must_use]
83 pub fn new_internet_password(
84 server: &str,
85 security_domain: Option<&str>,
86 account: &str,
87 path: &str,
88 port: Option<u16>,
89 protocol: SecProtocolType,
90 authentication_type: SecAuthenticationType,
91 ) -> Self {
92 #[allow(deprecated)]
93 let mut this = Self { query: vec![
94 (
95 unsafe { CFString::wrap_under_get_rule(kSecClass) },
96 unsafe { CFString::wrap_under_get_rule(kSecClassInternetPassword) }.into_CFType(),
97 ),
98 (unsafe { CFString::wrap_under_get_rule(kSecAttrServer) }, CFString::from(server).into_CFType()),
99 (unsafe { CFString::wrap_under_get_rule(kSecAttrPath) }, CFString::from(path).into_CFType()),
100 (unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) }, CFString::from(account).into_CFType()),
101 (unsafe { CFString::wrap_under_get_rule(kSecAttrProtocol) }, CFNumber::from(protocol as i32).into_CFType()),
102 (
103 unsafe { CFString::wrap_under_get_rule(kSecAttrAuthenticationType) },
104 CFNumber::from(authentication_type as i32).into_CFType(),
105 ),
106 ] };
107 if let Some(domain) = security_domain {
108 unsafe {
109 this.push_query(kSecAttrSecurityDomain, CFString::from(domain));
110 }
111 }
112 if let Some(port) = port {
113 unsafe {
114 this.push_query(kSecAttrPort, CFNumber::from(i32::from(port)));
115 }
116 }
117 this
118 }
119
120 pub fn set_access_control_options(&mut self, options: AccessControlOptions) {
122 unsafe {
123 self.push_query(kSecAttrAccessControl, SecAccessControl::create_with_flags(options.bits()).unwrap());
124 }
125 }
126
127 pub fn set_access_control(&mut self, access_control: SecAccessControl) {
129 unsafe {
130 self.push_query(kSecAttrAccessControl, access_control);
131 }
132 }
133
134 pub fn set_access_group(&mut self, group: &str) {
136 unsafe {
137 self.push_query(kSecAttrAccessGroup, CFString::from(group));
138 }
139 }
140
141 #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
142 pub fn set_access_synchronized(&mut self, synchronized: Option<bool>) {
166 unsafe {
167 if let Some(synchronizable) = synchronized {
168 self.push_query(kSecAttrSynchronizable, CFBoolean::from(synchronizable));
169 } else {
170 let either = CFString::wrap_under_get_rule(kSecAttrSynchronizableAny);
171 self.push_query(kSecAttrSynchronizable, either);
172 }
173 }
174 }
175
176 pub fn set_comment(&mut self, comment: &str) {
178 unsafe {
179 self.push_query(kSecAttrComment, CFString::from(comment));
180 }
181 }
182
183 pub fn set_description(&mut self, description: &str) {
185 unsafe {
186 self.push_query(kSecAttrDescription, CFString::from(description));
187 }
188 }
189
190 pub fn set_label(&mut self, label: &str) {
192 unsafe {
193 self.push_query(kSecAttrLabel, CFString::from(label));
194 }
195 }
196
197 #[cfg(any(feature = "OSX_10_15", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
198 pub fn use_protected_keychain(&mut self) {
200 unsafe {
201 self.push_query(kSecUseDataProtectionKeychain, CFBoolean::from(true));
202 }
203 }
204
205 pub(crate) unsafe fn push_query(&mut self, static_key_constant: CFStringRef, value: impl TCFType) {
208 #[allow(deprecated)]
209 self.query.push((
210 unsafe { CFString::wrap_under_get_rule(static_key_constant) },
211 value.into_CFType(),
212 ));
213 }
214
215 pub(crate) fn to_dictionary(&self) -> CFDictionary<CFString, CFType> {
216 #[allow(deprecated)]
217 CFDictionary::from_CFType_pairs(&self.query[..])
218 }
219}