security/async_api/
mod.rs1#![cfg(feature = "async")]
11
12use core::ffi::c_void;
13use core::marker::PhantomData;
14use core::pin::Pin;
15use core::task::{Context, Poll};
16use std::future::Future;
17use std::ptr;
18
19use doom_fish_utils::completion::{AsyncCompletion, AsyncCompletionFuture};
20use doom_fish_utils::panic_safe::catch_user_panic;
21use serde_json::Value;
22
23use crate::authorization::{Authorization, AuthorizationOptions};
24use crate::bridge;
25use crate::error::{status, Result, SecurityError};
26use crate::trust::Trust;
27
28fn flatten_async_result<T>(result: std::result::Result<Result<T>, String>) -> Result<T> {
29 result
30 .map_err(SecurityError::Serialization)
31 .and_then(|result| result)
32}
33
34fn bridge_status_error(
35 operation: &'static str,
36 status: i32,
37 error_raw: *mut c_void,
38) -> SecurityError {
39 match bridge::status_error(operation, status, error_raw) {
40 Ok(error) | Err(error) => error,
41 }
42}
43
44fn trust_failure(error_raw: *mut c_void) -> SecurityError {
45 match bridge::optional_string(error_raw) {
46 Ok(Some(message)) => SecurityError::TrustEvaluationFailed(message),
47 Ok(None) => SecurityError::TrustEvaluationFailed("trust evaluation failed".to_owned()),
48 Err(error) => error,
49 }
50}
51
52unsafe extern "C" fn trust_evaluate_async_cb(
53 refcon: *mut c_void,
54 trusted: bool,
55 error_raw: *mut c_void,
56) {
57 catch_user_panic("security::trust_evaluate_async_cb", || {
58 let result = if trusted {
59 Ok(())
60 } else {
61 Err(trust_failure(error_raw))
62 };
63 unsafe {
64 AsyncCompletion::<Result<()>>::complete_ok(refcon, result);
65 };
66 });
67}
68
69unsafe extern "C" fn authorization_copy_rights_async_cb(
70 refcon: *mut c_void,
71 json_raw: *mut c_void,
72 status_raw: i32,
73 error_raw: *mut c_void,
74) {
75 catch_user_panic("security::authorization_copy_rights_async_cb", || {
76 let result = if status_raw == status::SUCCESS {
77 match bridge::optional_json::<Value>(json_raw) {
78 Ok(Some(value)) => Ok(value),
79 Ok(None) => Err(SecurityError::InvalidArgument(
80 "security_authorization_copy_rights_async_start returned no authorization rights"
81 .to_owned(),
82 )),
83 Err(error) => Err(error),
84 }
85 } else {
86 Err(bridge_status_error(
87 "security_authorization_copy_rights_async_start",
88 status_raw,
89 error_raw,
90 ))
91 };
92 unsafe {
93 AsyncCompletion::<Result<Value>>::complete_ok(refcon, result);
94 };
95 });
96}
97
98pub struct TrustEvaluateFuture<'a> {
100 inner: AsyncCompletionFuture<Result<()>>,
101 _owner: PhantomData<&'a Trust>,
102}
103
104impl core::fmt::Debug for TrustEvaluateFuture<'_> {
105 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106 f.debug_struct("TrustEvaluateFuture")
107 .finish_non_exhaustive()
108 }
109}
110
111impl Future for TrustEvaluateFuture<'_> {
112 type Output = Result<()>;
113
114 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
115 Pin::new(&mut self.inner).poll(cx).map(flatten_async_result)
116 }
117}
118
119pub struct AuthorizationRightsFuture<'a> {
121 inner: AsyncCompletionFuture<Result<Value>>,
122 _owner: PhantomData<&'a Authorization>,
123}
124
125impl core::fmt::Debug for AuthorizationRightsFuture<'_> {
126 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
127 f.debug_struct("AuthorizationRightsFuture")
128 .finish_non_exhaustive()
129 }
130}
131
132impl Future for AuthorizationRightsFuture<'_> {
133 type Output = Result<Value>;
134
135 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
136 Pin::new(&mut self.inner).poll(cx).map(flatten_async_result)
137 }
138}
139
140#[derive(Debug, Clone, Copy)]
142pub struct AsyncTrust<'a> {
143 trust: &'a Trust,
144}
145
146impl<'a> AsyncTrust<'a> {
147 #[must_use]
149 pub const fn new(trust: &'a Trust) -> Self {
150 Self { trust }
151 }
152
153 pub fn evaluate(&self) -> Result<TrustEvaluateFuture<'a>> {
155 let (inner, refcon) = AsyncCompletion::<Result<()>>::create();
156 let mut error_raw = ptr::null_mut();
157 let status = unsafe {
158 bridge::security_trust_evaluate_async_start(
159 self.trust.as_ptr(),
160 refcon,
161 Some(trust_evaluate_async_cb),
162 &mut error_raw,
163 )
164 };
165 if status != status::SUCCESS {
166 let error =
167 bridge_status_error("security_trust_evaluate_async_start", status, error_raw);
168 unsafe {
169 AsyncCompletion::<Result<()>>::complete_err(refcon, error.to_string());
170 };
171 drop(inner);
172 return Err(error);
173 }
174
175 Ok(TrustEvaluateFuture {
176 inner,
177 _owner: PhantomData,
178 })
179 }
180}
181
182#[derive(Debug, Clone, Copy)]
184pub struct AsyncAuthorization<'a> {
185 authorization: &'a Authorization,
186}
187
188impl<'a> AsyncAuthorization<'a> {
189 #[must_use]
191 pub const fn new(authorization: &'a Authorization) -> Self {
192 Self { authorization }
193 }
194
195 pub fn copy_rights(
197 &self,
198 rights: &[&str],
199 options: AuthorizationOptions,
200 ) -> Result<AuthorizationRightsFuture<'a>> {
201 let rights_json = bridge::json_cstring(&rights)?;
202 let (inner, refcon) = AsyncCompletion::<Result<Value>>::create();
203 let mut error_raw = ptr::null_mut();
204 let status = unsafe {
205 bridge::security_authorization_copy_rights_async_start(
206 self.authorization.as_ptr(),
207 rights_json.as_ptr(),
208 options.bits(),
209 refcon,
210 Some(authorization_copy_rights_async_cb),
211 &mut error_raw,
212 )
213 };
214 if status != status::SUCCESS {
215 let error = bridge_status_error(
216 "security_authorization_copy_rights_async_start",
217 status,
218 error_raw,
219 );
220 unsafe {
221 AsyncCompletion::<Result<Value>>::complete_err(refcon, error.to_string());
222 };
223 drop(inner);
224 return Err(error);
225 }
226
227 Ok(AuthorizationRightsFuture {
228 inner,
229 _owner: PhantomData,
230 })
231 }
232}