1use bitflags::bitflags;
2
3use crate::bridge::{self, Handle};
4use crate::error::Result;
5
6bitflags! {
7 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8 pub struct AccessControlFlags: u64 {
10 const DEFAULTS = 0;
12 const USER_PRESENCE = 1 << 0;
14 const BIOMETRY_ANY = 1 << 1;
16 const BIOMETRY_CURRENT_SET = 1 << 3;
18 const DEVICE_PASSCODE = 1 << 4;
20 const COMPANION = 1 << 5;
22 const OR = 1 << 14;
24 const AND = 1 << 15;
26 const PRIVATE_KEY_USAGE = 1 << 30;
28 const APPLICATION_PASSWORD = 1 << 31;
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34pub enum AccessControlProtection {
36 WhenUnlocked,
38 AfterFirstUnlock,
40 WhenPasscodeSetThisDeviceOnly,
42 WhenUnlockedThisDeviceOnly,
44 AfterFirstUnlockThisDeviceOnly,
46}
47
48impl AccessControlProtection {
49 const fn as_bridge_name(self) -> &'static str {
50 match self {
51 Self::WhenUnlocked => "when_unlocked",
52 Self::AfterFirstUnlock => "after_first_unlock",
53 Self::WhenPasscodeSetThisDeviceOnly => "when_passcode_set_this_device_only",
54 Self::WhenUnlockedThisDeviceOnly => "when_unlocked_this_device_only",
55 Self::AfterFirstUnlockThisDeviceOnly => "after_first_unlock_this_device_only",
56 }
57 }
58}
59
60#[derive(Debug)]
61pub struct AccessControl {
63 handle: Handle,
64}
65
66impl AccessControl {
67 pub fn type_id() -> usize {
69 unsafe { bridge::security_access_control_get_type_id() }
70 }
71
72 pub fn create(protection: AccessControlProtection, flags: AccessControlFlags) -> Result<Self> {
74 let protection = bridge::cstring(protection.as_bridge_name())?;
75 let mut status = 0;
76 let mut error = std::ptr::null_mut();
77 let raw = unsafe {
78 bridge::security_access_control_create(
79 protection.as_ptr(),
80 flags.bits(),
81 &mut status,
82 &mut error,
83 )
84 };
85 bridge::required_handle("security_access_control_create", raw, status, error)
86 .map(|handle| Self { handle })
87 }
88
89 pub fn is_valid(&self) -> bool {
91 !self.handle.as_ptr().is_null()
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Hash)]
96pub struct KeychainEntry {
98 account: String,
99 service: String,
100}
101
102impl KeychainEntry {
103 pub fn new(account: impl Into<String>, service: impl Into<String>) -> Self {
105 Self {
106 account: account.into(),
107 service: service.into(),
108 }
109 }
110
111 pub fn account(&self) -> &str {
113 &self.account
114 }
115
116 pub fn service(&self) -> &str {
118 &self.service
119 }
120
121 pub fn set(&self, password: &str) -> Result<()> {
123 Keychain::set(&self.account, &self.service, password)
124 }
125
126 pub fn get(&self) -> Result<String> {
128 Keychain::get(&self.account, &self.service)
129 }
130
131 pub fn delete(&self) -> Result<()> {
133 Keychain::delete(&self.account, &self.service)
134 }
135}
136
137pub struct Keychain;
139
140impl Keychain {
141 pub fn entry(account: impl Into<String>, service: impl Into<String>) -> KeychainEntry {
143 KeychainEntry::new(account, service)
144 }
145
146 pub fn set(account: &str, service: &str, password: &str) -> Result<()> {
148 let account = bridge::cstring(account)?;
149 let service = bridge::cstring(service)?;
150 let password = bridge::cstring(password)?;
151 let mut error = std::ptr::null_mut();
152 let status = unsafe {
153 bridge::security_keychain_set_password(
154 account.as_ptr(),
155 service.as_ptr(),
156 password.as_ptr(),
157 &mut error,
158 )
159 };
160 bridge::status_result("security_keychain_set_password", status, error)
161 }
162
163 pub fn get(account: &str, service: &str) -> Result<String> {
165 let account = bridge::cstring(account)?;
166 let service = bridge::cstring(service)?;
167 let mut status = 0;
168 let mut error = std::ptr::null_mut();
169 let raw = unsafe {
170 bridge::security_keychain_get_password(
171 account.as_ptr(),
172 service.as_ptr(),
173 &mut status,
174 &mut error,
175 )
176 };
177 bridge::required_string("security_keychain_get_password", raw, status, error)
178 }
179
180 pub fn delete(account: &str, service: &str) -> Result<()> {
182 let account = bridge::cstring(account)?;
183 let service = bridge::cstring(service)?;
184 let mut error = std::ptr::null_mut();
185 let status = unsafe {
186 bridge::security_keychain_delete_password(
187 account.as_ptr(),
188 service.as_ptr(),
189 &mut error,
190 )
191 };
192 bridge::status_result("security_keychain_delete_password", status, error)
193 }
194
195 pub fn list_accounts(service: &str) -> Result<Vec<String>> {
197 let service = bridge::cstring(service)?;
198 let mut status = 0;
199 let mut error = std::ptr::null_mut();
200 let raw = unsafe {
201 bridge::security_keychain_list_accounts(service.as_ptr(), &mut status, &mut error)
202 };
203 bridge::required_json("security_keychain_list_accounts", raw, status, error)
204 }
205}