core_crypto/transaction_context/e2e_identity/
stash.rs

1use super::Result;
2use crate::RecursiveError;
3use crate::e2e_identity::EnrollmentHandle;
4use crate::prelude::E2eiEnrollment;
5use crate::transaction_context::TransactionContext;
6
7impl TransactionContext {
8    /// Allows persisting an active enrollment (for example while redirecting the user during OAuth)
9    /// in order to resume it later with [TransactionContext::e2ei_enrollment_stash_pop]
10    ///
11    /// # Arguments
12    /// * `enrollment` - the enrollment instance to persist
13    ///
14    /// # Returns
15    /// A handle for retrieving the enrollment later on
16    pub async fn e2ei_enrollment_stash(&self, enrollment: E2eiEnrollment) -> Result<EnrollmentHandle> {
17        enrollment
18            .stash(
19                &self
20                    .mls_provider()
21                    .await
22                    .map_err(RecursiveError::transaction("getting mls provider"))?,
23            )
24            .await
25            .map_err(RecursiveError::e2e_identity("stashing enrollment"))
26            .map_err(Into::into)
27    }
28
29    /// Fetches the persisted enrollment and deletes it from the keystore
30    ///
31    /// # Arguments
32    /// * `handle` - returned by [TransactionContext::e2ei_enrollment_stash]
33    pub async fn e2ei_enrollment_stash_pop(&self, handle: EnrollmentHandle) -> Result<E2eiEnrollment> {
34        E2eiEnrollment::stash_pop(
35            &self
36                .mls_provider()
37                .await
38                .map_err(RecursiveError::transaction("getting mls provider"))?,
39            handle,
40        )
41        .await
42        .map_err(RecursiveError::e2e_identity("popping stashed enrollment"))
43        .map_err(Into::into)
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use crate::{
50        e2e_identity::{enrollment::test_utils::*, id::WireQualifiedClientId},
51        prelude::{E2eiEnrollment, INITIAL_KEYING_MATERIAL_COUNT},
52        test_utils::{x509::X509TestChain, *},
53    };
54    use mls_crypto_provider::MlsCryptoProvider;
55    use wasm_bindgen_test::*;
56
57    use core_crypto_keystore::DatabaseKey;
58
59    wasm_bindgen_test_configure!(run_in_browser);
60
61    #[apply(all_cred_cipher)]
62    #[wasm_bindgen_test]
63    async fn stash_and_pop_should_not_abort_enrollment(case: TestCase) {
64        run_test_wo_clients(case.clone(), move |mut cc| {
65            Box::pin(async move {
66                let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
67
68                let is_renewal = false;
69                let (mut enrollment, cert) = e2ei_enrollment(
70                    &mut cc,
71                    &case,
72                    &x509_test_chain,
73                    Some(E2EI_CLIENT_ID_URI),
74                    is_renewal,
75                    init_enrollment,
76                    |e, cc| {
77                        Box::pin(async move {
78                            let handle = cc.e2ei_enrollment_stash(e).await.unwrap();
79                            cc.e2ei_enrollment_stash_pop(handle).await.unwrap()
80                        })
81                    },
82                )
83                .await
84                .unwrap();
85
86                assert!(
87                    cc.context
88                        .e2ei_mls_init_only(&mut enrollment, cert, Some(INITIAL_KEYING_MATERIAL_COUNT))
89                        .await
90                        .is_ok()
91                );
92            })
93        })
94        .await
95    }
96
97    // this ensures the nominal test does its job
98    #[apply(all_cred_cipher)]
99    #[wasm_bindgen_test]
100    async fn should_fail_when_restoring_invalid(case: TestCase) {
101        run_test_wo_clients(case.clone(), move |mut cc| {
102            Box::pin(async move {
103                let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
104
105                let is_renewal = false;
106                let result = e2ei_enrollment(
107                    &mut cc,
108                    &case,
109                    &x509_test_chain,
110                    Some(E2EI_CLIENT_ID_URI),
111                    is_renewal,
112                    init_enrollment,
113                    move |e, _cc| {
114                        Box::pin(async move {
115                            // this restore recreates a partial enrollment
116                            let key = DatabaseKey::generate();
117                            let backend = MlsCryptoProvider::try_new_in_memory(&key).await.unwrap();
118                            backend.new_transaction().await.unwrap();
119                            let client_id = e.client_id().parse::<WireQualifiedClientId>().unwrap();
120                            E2eiEnrollment::try_new(
121                                client_id.into(),
122                                e.display_name().to_string(),
123                                e.handle().to_string(),
124                                e.team().map(ToString::to_string),
125                                1,
126                                &backend,
127                                e.ciphersuite().clone(),
128                                None,
129                                #[cfg(not(target_family = "wasm"))]
130                                None,
131                            )
132                            .unwrap()
133                        })
134                    },
135                )
136                .await;
137                assert!(result.is_err());
138            })
139        })
140        .await
141    }
142}