security_framework/
passwords_options.rs1use crate::access_control::SecAccessControl;
7use core_foundation::base::{CFOptionFlags, CFType, TCFType};
8use core_foundation::dictionary::CFDictionary;
9use core_foundation::number::CFNumber;
10use core_foundation::string::{CFString, CFStringRef};
11use security_framework_sys::access_control::*;
12use security_framework_sys::item::{
13 kSecAttrAccessControl, kSecAttrAccessGroup, kSecAttrAccount, kSecAttrAuthenticationType, kSecAttrPath, kSecAttrPort, kSecAttrProtocol, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrService, kSecClass, kSecClassGenericPassword, kSecClassInternetPassword
14};
15use security_framework_sys::keychain::{SecAuthenticationType, SecProtocolType};
16
17pub struct PasswordOptions {
19 #[deprecated(note = "This field should have been private. Please use setters that don't expose CFType")]
21 pub query: Vec<(CFString, CFType)>,
22}
23
24bitflags::bitflags! {
25 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27 pub struct AccessControlOptions: CFOptionFlags {
28 const USER_PRESENCE = kSecAccessControlUserPresence;
30 #[cfg(feature = "OSX_10_13")]
31 const BIOMETRY_ANY = kSecAccessControlBiometryAny;
33 #[cfg(feature = "OSX_10_13")]
34 const BIOMETRY_CURRENT_SET = kSecAccessControlBiometryCurrentSet;
36 const DEVICE_PASSCODE = kSecAccessControlDevicePasscode;
38 #[cfg(feature = "OSX_10_15")]
39 const WATCH = kSecAccessControlWatch;
41 const OR = kSecAccessControlOr;
43 const AND = kSecAccessControlAnd;
45 const PRIVATE_KEY_USAGE = kSecAccessControlPrivateKeyUsage;
47 const APPLICATION_PASSWORD = kSecAccessControlApplicationPassword;
49 }
50}
51
52impl PasswordOptions {
53 #[must_use]
57 pub fn new_generic_password(service: &str, account: &str) -> Self {
58 #[allow(deprecated)]
59 Self { query: vec![
60 (
61 unsafe { CFString::wrap_under_get_rule(kSecClass) },
62 unsafe { CFString::wrap_under_get_rule(kSecClassGenericPassword).into_CFType() },
63 ),
64 (unsafe { CFString::wrap_under_get_rule(kSecAttrService) }, CFString::from(service).into_CFType()),
65 (unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) }, CFString::from(account).into_CFType()),
66 ] }
67 }
68
69 #[must_use]
73 pub fn new_internet_password(
74 server: &str,
75 security_domain: Option<&str>,
76 account: &str,
77 path: &str,
78 port: Option<u16>,
79 protocol: SecProtocolType,
80 authentication_type: SecAuthenticationType,
81 ) -> Self {
82 #[allow(deprecated)]
83 let mut this = Self { query: vec![
84 (
85 unsafe { CFString::wrap_under_get_rule(kSecClass) },
86 unsafe { CFString::wrap_under_get_rule(kSecClassInternetPassword) }.into_CFType(),
87 ),
88 (unsafe { CFString::wrap_under_get_rule(kSecAttrServer) }, CFString::from(server).into_CFType()),
89 (unsafe { CFString::wrap_under_get_rule(kSecAttrPath) }, CFString::from(path).into_CFType()),
90 (unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) }, CFString::from(account).into_CFType()),
91 (unsafe { CFString::wrap_under_get_rule(kSecAttrProtocol) }, CFNumber::from(protocol as i32).into_CFType()),
92 (
93 unsafe { CFString::wrap_under_get_rule(kSecAttrAuthenticationType) },
94 CFNumber::from(authentication_type as i32).into_CFType(),
95 ),
96 ] };
97 if let Some(domain) = security_domain {
98 unsafe {
99 this.push_query(kSecAttrSecurityDomain, CFString::from(domain));
100 }
101 }
102 if let Some(port) = port {
103 unsafe {
104 this.push_query(kSecAttrPort, CFNumber::from(i32::from(port)));
105 }
106 }
107 this
108 }
109
110 pub fn set_access_control_options(&mut self, options: AccessControlOptions) {
112 unsafe {
113 self.push_query(kSecAttrAccessControl, SecAccessControl::create_with_flags(options.bits()).unwrap());
114 }
115 }
116
117 pub fn set_access_control(&mut self, access_control: SecAccessControl) {
119 unsafe {
120 self.push_query(kSecAttrAccessControl, access_control);
121 }
122 }
123
124 pub fn set_access_group(&mut self, group: &str) {
126 unsafe {
127 self.push_query(kSecAttrAccessGroup, CFString::from(group));
128 }
129 }
130
131 pub(crate) unsafe fn push_query(&mut self, static_key_constant: CFStringRef, value: impl TCFType) {
134 #[allow(deprecated)]
135 self.query.push((
136 unsafe { CFString::wrap_under_get_rule(static_key_constant) },
137 value.into_CFType(),
138 ));
139 }
140
141 pub(crate) fn to_dictionary(&self) -> CFDictionary<CFString, CFType> {
142 #[allow(deprecated)]
143 CFDictionary::from_CFType_pairs(&self.query[..])
144 }
145}