core_crypto/mls/conversation/
wipe.rs1use super::Result;
2use crate::{
3 MlsError,
4 context::CentralContext,
5 prelude::{ConversationId, MlsConversation},
6};
7use mls_crypto_provider::MlsCryptoProvider;
8use openmls_traits::OpenMlsCryptoProvider;
9
10impl CentralContext {
11 #[cfg_attr(test, crate::dispotent)]
16 pub async fn wipe_conversation(&self, id: &ConversationId) -> Result<()> {
17 self.conversation(id).await?.wipe().await
18 }
19}
20
21impl MlsConversation {
22 pub(crate) async fn wipe_associated_entities(&mut self, backend: &MlsCryptoProvider) -> Result<()> {
23 let _ = self.group.delete_previous_epoch_keypairs(backend).await;
26
27 let pending_proposals = self.group.pending_proposals().cloned().collect::<Vec<_>>();
28 for proposal in pending_proposals {
29 self.group
31 .remove_pending_proposal(backend.key_store(), proposal.proposal_reference())
32 .await
33 .map_err(MlsError::wrap("removing pending proposal"))?;
34 }
35
36 Ok(())
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use wasm_bindgen_test::*;
43
44 use super::super::error::Error;
45 use crate::test_utils::*;
46
47 wasm_bindgen_test_configure!(run_in_browser);
48
49 #[apply(all_cred_cipher)]
50 #[wasm_bindgen_test]
51 async fn can_wipe_group(case: TestCase) {
52 run_test_with_central(case.clone(), move |[central]| {
53 Box::pin(async move {
54 let id = conversation_id();
55 central
56 .context
57 .new_conversation(&id, case.credential_type, case.cfg.clone())
58 .await
59 .unwrap();
60 assert!(central.get_conversation_unchecked(&id).await.group.is_active());
61
62 central.context.wipe_conversation(&id).await.unwrap();
63 assert!(!central.context.conversation_exists(&id).await.unwrap());
64 })
65 })
66 .await;
67 }
68
69 #[apply(all_cred_cipher)]
70 #[wasm_bindgen_test]
71 async fn cannot_wipe_group_non_existent(case: TestCase) {
72 use crate::LeafError;
73
74 run_test_with_central(case.clone(), move |[central]| {
75 Box::pin(async move {
76 let id = conversation_id();
77 let err = central.context.wipe_conversation(&id).await.unwrap_err();
78 assert!(matches!(err, Error::Leaf(LeafError::ConversationNotFound(conv_id)) if conv_id == id));
79 })
80 })
81 .await;
82 }
83
84 #[apply(all_cred_cipher)]
86 #[wasm_bindgen_test]
87 async fn should_cascade_deletion(case: TestCase) {
88 run_test_with_client_ids(case.clone(), ["alice"], move |[cc]| {
89 Box::pin(async move {
90 let id = conversation_id();
91 cc.context
92 .new_conversation(&id, case.credential_type, case.cfg.clone())
93 .await
94 .unwrap();
95 let initial_count = cc.context.count_entities().await;
96
97 cc.context.new_update_proposal(&id).await.unwrap();
98 let post_proposal_count = cc.context.count_entities().await;
99 assert_eq!(
100 post_proposal_count.encryption_keypair,
101 initial_count.encryption_keypair + 1
102 );
103
104 cc.context.wipe_conversation(&id).await.unwrap();
105
106 let final_count = cc.context.count_entities().await;
107 assert_eq!(final_count.group, 0);
108 assert_eq!(final_count.encryption_keypair, final_count.key_package);
109 assert_eq!(final_count.epoch_encryption_keypair, 0);
110 })
111 })
112 .await
113 }
114}