Skip to main content

bitwarden_emergency_access/
update.rs

1use bitwarden_api_api::models::EmergencyAccessUpdateRequestModel;
2use bitwarden_core::ApiError;
3use bitwarden_error::bitwarden_error;
4use thiserror::Error;
5
6use crate::{EmergencyAccessClient, EmergencyAccessId, EmergencyAccessType};
7
8/// Errors returned when editing an emergency access.
9#[bitwarden_error(flat)]
10#[derive(Debug, Error)]
11pub enum EmergencyAccessUpdateError {
12    /// The request to the server failed.
13    #[error(transparent)]
14    Api(#[from] ApiError),
15}
16
17#[bitwarden_ffi::wasm_export]
18impl EmergencyAccessClient {
19    /// Changes the access type and wait time of an emergency access.
20    ///
21    /// Called by the grantor.
22    pub async fn update(
23        &self,
24        emergency_access_id: EmergencyAccessId,
25        r#type: EmergencyAccessType,
26        wait_time_days: i32,
27    ) -> Result<(), EmergencyAccessUpdateError> {
28        // The shared key is left untouched; it only changes on confirm and key rotation.
29        let request = EmergencyAccessUpdateRequestModel {
30            r#type: r#type.into(),
31            wait_time_days,
32            key_encrypted: None,
33        };
34
35        self.api_configurations
36            .api_client
37            .emergency_access_api()
38            .put(emergency_access_id.into(), Some(request))
39            .await?;
40
41        Ok(())
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use bitwarden_api_api::models::EmergencyAccessType as ApiEmergencyAccessType;
48    use bitwarden_core::client::test_accounts::test_bitwarden_com_account;
49
50    use super::*;
51    use crate::{
52        EmergencyAccessClientExt,
53        test_support::{api_error, is_test_id, test_client, test_id},
54    };
55
56    const TEST_WAIT_TIME_DAYS: i32 = 14;
57
58    #[tokio::test]
59    async fn sends_type_and_wait_time() {
60        let client = test_client(test_bitwarden_com_account(), |mock| {
61            mock.emergency_access_api
62                .expect_put()
63                .withf(|id, request| {
64                    is_test_id(id)
65                        && *request
66                            == Some(EmergencyAccessUpdateRequestModel {
67                                r#type: ApiEmergencyAccessType::View,
68                                wait_time_days: TEST_WAIT_TIME_DAYS,
69                                key_encrypted: None,
70                            })
71                })
72                .returning(|_, _| Ok(()))
73                .once();
74        })
75        .await;
76
77        client
78            .emergency_access()
79            .update(test_id(), EmergencyAccessType::View, TEST_WAIT_TIME_DAYS)
80            .await
81            .unwrap();
82    }
83
84    #[tokio::test]
85    async fn fails_when_request_fails() {
86        let client = test_client(test_bitwarden_com_account(), |mock| {
87            mock.emergency_access_api
88                .expect_put()
89                .returning(|_, _| api_error())
90                .once();
91        })
92        .await;
93
94        let result = client
95            .emergency_access()
96            .update(test_id(), EmergencyAccessType::View, TEST_WAIT_TIME_DAYS)
97            .await;
98
99        assert!(matches!(result, Err(EmergencyAccessUpdateError::Api(_))));
100    }
101}