bitwarden_uniffi/platform/fido2/
device_auth_key.rs1use std::sync::Arc;
2
3use bitwarden_core::platform::SecretVerificationRequest;
4use bitwarden_crypto::Kdf;
5use bitwarden_fido::{
6 DeviceAuthKeyError as BitDeviceAuthKeyError, DeviceAuthKeyGetAssertionResult,
7 DeviceAuthKeyMetadata, DeviceAuthKeyRecord, GetAssertionRequest,
8};
9
10use super::UniffiTraitBridge;
11use crate::error::{Error, Result};
12
13#[derive(uniffi::Object)]
14pub struct ClientDeviceAuthKeyAuthenticator {
15 pub(super) client: bitwarden_fido::ClientFido2,
16 pub(super) store: Arc<dyn DeviceAuthKeyStore>,
17}
18
19#[uniffi::export(async_runtime = "tokio")]
20impl ClientDeviceAuthKeyAuthenticator {
21 pub async fn create_device_auth_key(
25 &self,
26 client_name: String,
27 web_vault_url: String,
28 email: String,
29 secret_verification_request: SecretVerificationRequest,
30 kdf: Kdf,
31 ) -> Result<()> {
32 let mut store = UniffiTraitBridge(self.store.as_ref());
33 let mut authenticator = self.client.create_device_key_authenticator(&mut store);
34 authenticator
35 .create_device_auth_key(
36 client_name,
37 web_vault_url,
38 email,
39 secret_verification_request,
40 kdf,
41 )
42 .await
43 .map_err(Error::DeviceAuthKey)
44 }
45
46 async fn assert_device_auth_key(
51 &self,
52 request: GetAssertionRequest,
53 ) -> Result<DeviceAuthKeyGetAssertionResult> {
54 let mut store = UniffiTraitBridge(self.store.as_ref());
55 let mut authenticator = self.client.create_device_key_authenticator(&mut store);
56 authenticator
57 .assert_device_auth_key(request)
58 .await
59 .map_err(Error::DeviceAuthKey)
60 }
61
62 async fn unregister_device_auth_key(
64 &self,
65 email: String,
66 secret_verification_request: SecretVerificationRequest,
67 kdf: Kdf,
68 ) -> Result<()> {
69 let mut store = UniffiTraitBridge(self.store.as_ref());
70 let mut authenticator = self.client.create_device_key_authenticator(&mut store);
71 authenticator
72 .unregister_device_auth_key(email, secret_verification_request, kdf)
73 .await
74 .map_err(Error::DeviceAuthKey)
75 }
76}
77
78#[uniffi::export(with_foreign)]
79#[async_trait::async_trait]
80pub trait DeviceAuthKeyStore: Send + Sync {
81 async fn create_record(
82 &self,
83 record: DeviceAuthKeyRecord,
84 ) -> Result<(), DeviceAuthKeyCallbackError>;
85 async fn create_metadata(
86 &self,
87 metadata: DeviceAuthKeyMetadata,
88 ) -> Result<(), DeviceAuthKeyCallbackError>;
89 async fn get_metadata(
90 &self,
91 ) -> Result<Option<DeviceAuthKeyMetadata>, DeviceAuthKeyCallbackError>;
92 async fn get_record(&self) -> Result<Option<DeviceAuthKeyRecord>, DeviceAuthKeyCallbackError>;
93 async fn delete_record_and_metadata(&self) -> Result<(), DeviceAuthKeyCallbackError>;
94}
95
96#[async_trait::async_trait]
99impl bitwarden_fido::DeviceAuthKeyStore for UniffiTraitBridge<&dyn DeviceAuthKeyStore> {
100 async fn create_record(
101 &mut self,
102 record: DeviceAuthKeyRecord,
103 ) -> Result<(), BitDeviceAuthKeyError> {
104 self.0.create_record(record).await.map_err(Into::into)
105 }
106
107 async fn create_metadata(
108 &mut self,
109 metadata: DeviceAuthKeyMetadata,
110 ) -> Result<(), BitDeviceAuthKeyError> {
111 self.0.create_metadata(metadata).await.map_err(Into::into)
112 }
113
114 async fn get_metadata(&self) -> Result<Option<DeviceAuthKeyMetadata>, BitDeviceAuthKeyError> {
115 self.0.get_metadata().await.map_err(Into::into)
116 }
117
118 async fn get_record(&self) -> Result<Option<DeviceAuthKeyRecord>, BitDeviceAuthKeyError> {
119 self.0.get_record().await.map_err(Into::into)
120 }
121
122 async fn delete_record_and_metadata(&mut self) -> Result<(), BitDeviceAuthKeyError> {
123 self.0
124 .delete_record_and_metadata()
125 .await
126 .map_err(Into::into)
127 }
128}
129
130#[derive(Debug, thiserror::Error, uniffi::Error)]
132pub enum DeviceAuthKeyCallbackError {
133 #[error("The authenticator failed to produce a valid response")]
135 AuthenticatorFailure,
136
137 #[error("Failed to convert between Rust types")]
139 Conversion,
140
141 #[error("The existing device auth key is already registered on the server.")]
143 CredentialExcluded,
144
145 #[error("The record identifier is not a valid UUID")]
147 InvalidRecordIdentifier,
148
149 #[error("Invalid Web Vault URL specified")]
151 InvalidWebVaultUrl,
152
153 #[error("No device auth key exists on this device")]
155 MissingDeviceAuthKey,
156
157 #[error("Failed to unregister device auth key from server")]
159 UnregisterFailure,
160
161 #[error("Failed to de-/serialize COSE key data")]
163 InvalidCoseKey,
164
165 #[error("An invalid public key credential descriptor was passed in the allow list")]
167 InvalidPublicKeyCredentialDescriptor,
168
169 #[error("A master password hash could not be generated for the given master password")]
171 MasterPasswordHash,
172
173 #[error(
175 "No credential ID was returned in the response nor was a single credential ID passed in the request"
176 )]
177 MissingCredentialId,
178
179 #[error("No HMAC secret was returned with the credential")]
181 MissingHmacSecret,
182
183 #[error("User handle was not returned in the response")]
185 MissingUserHandle,
186
187 #[error("Feature is not yet implemented")]
189 NotImplemented,
190
191 #[error("Failed to retrieve the registration options from the server")]
193 RetrieveRegistrationOptionsFailure,
194
195 #[error("Failed to generate rotateable key set from PRF output")]
197 PrfFailure,
198
199 #[error("Failed to submit registration request to the server")]
201 SubmitRegistrationFailure,
202
203 #[error("User cancelled the operation")]
205 UserCancelled,
206
207 #[error("An unknown error occurred")]
209 Unknown {
210 reason: String,
212 },
213}
214
215impl From<uniffi::UnexpectedUniFFICallbackError> for DeviceAuthKeyCallbackError {
219 fn from(e: uniffi::UnexpectedUniFFICallbackError) -> Self {
220 Self::Unknown { reason: e.reason }
221 }
222}
223
224impl From<DeviceAuthKeyCallbackError> for BitDeviceAuthKeyError {
225 fn from(val: DeviceAuthKeyCallbackError) -> Self {
226 match val {
227 DeviceAuthKeyCallbackError::AuthenticatorFailure => Self::AuthenticatorFailure,
228 DeviceAuthKeyCallbackError::Conversion => Self::Conversion,
229 DeviceAuthKeyCallbackError::CredentialExcluded => Self::CredentialExcluded,
230 DeviceAuthKeyCallbackError::InvalidRecordIdentifier => Self::InvalidRecordIdentifier,
231 DeviceAuthKeyCallbackError::InvalidWebVaultUrl => Self::InvalidWebVaultUrl,
232 DeviceAuthKeyCallbackError::MissingDeviceAuthKey => Self::MissingDeviceAuthKey,
233 DeviceAuthKeyCallbackError::UnregisterFailure => Self::UnregisterFailure,
234 DeviceAuthKeyCallbackError::InvalidCoseKey => Self::InvalidCoseKey,
235 DeviceAuthKeyCallbackError::InvalidPublicKeyCredentialDescriptor => {
236 Self::InvalidPublicKeyCredentialDescriptor
237 }
238 DeviceAuthKeyCallbackError::MasterPasswordHash => Self::MasterPasswordHash,
239 DeviceAuthKeyCallbackError::MissingCredentialId => Self::MissingCredentialId,
240 DeviceAuthKeyCallbackError::MissingHmacSecret => Self::MissingHmacSecret,
241 DeviceAuthKeyCallbackError::MissingUserHandle => Self::MissingUserHandle,
242 DeviceAuthKeyCallbackError::NotImplemented => Self::NotImplemented,
243 DeviceAuthKeyCallbackError::RetrieveRegistrationOptionsFailure => {
244 Self::RetrieveRegistrationOptionsFailure
245 }
246 DeviceAuthKeyCallbackError::PrfFailure => Self::PrfFailure,
247 DeviceAuthKeyCallbackError::SubmitRegistrationFailure => {
248 Self::SubmitRegistrationFailure
249 }
250 DeviceAuthKeyCallbackError::UserCancelled => Self::UserCancelled,
251 DeviceAuthKeyCallbackError::Unknown { reason } => Self::Unknown { reason },
252 }
253 }
254}
255
256impl From<BitDeviceAuthKeyError> for DeviceAuthKeyCallbackError {
257 fn from(val: BitDeviceAuthKeyError) -> Self {
258 match val {
259 BitDeviceAuthKeyError::AuthenticatorFailure => Self::AuthenticatorFailure,
260 BitDeviceAuthKeyError::Conversion => Self::Conversion,
261 BitDeviceAuthKeyError::CredentialExcluded => Self::CredentialExcluded,
262 BitDeviceAuthKeyError::InvalidRecordIdentifier => Self::InvalidRecordIdentifier,
263 BitDeviceAuthKeyError::InvalidWebVaultUrl => Self::InvalidWebVaultUrl,
264 BitDeviceAuthKeyError::MissingDeviceAuthKey => Self::MissingDeviceAuthKey,
265 BitDeviceAuthKeyError::UnregisterFailure => Self::UnregisterFailure,
266 BitDeviceAuthKeyError::InvalidCoseKey => Self::InvalidCoseKey,
267 BitDeviceAuthKeyError::InvalidPublicKeyCredentialDescriptor => {
268 Self::InvalidPublicKeyCredentialDescriptor
269 }
270 BitDeviceAuthKeyError::MasterPasswordHash => Self::MasterPasswordHash,
271 BitDeviceAuthKeyError::MissingCredentialId => Self::MissingCredentialId,
272 BitDeviceAuthKeyError::MissingHmacSecret => Self::MissingHmacSecret,
273 BitDeviceAuthKeyError::MissingUserHandle => Self::MissingUserHandle,
274 BitDeviceAuthKeyError::NotImplemented => Self::NotImplemented,
275 BitDeviceAuthKeyError::RetrieveRegistrationOptionsFailure => {
276 Self::RetrieveRegistrationOptionsFailure
277 }
278 BitDeviceAuthKeyError::PrfFailure => Self::PrfFailure,
279 BitDeviceAuthKeyError::SubmitRegistrationFailure => Self::SubmitRegistrationFailure,
280 BitDeviceAuthKeyError::UserCancelled => Self::UserCancelled,
281 BitDeviceAuthKeyError::Unknown { reason } => Self::Unknown { reason },
282 }
283 }
284}