Skip to main content

core_crypto/mls/conversation/mutable/
mod.rs

1mod commit;
2pub(crate) mod decrypt;
3mod encrypt;
4mod group_mutation;
5mod history_sharing;
6mod merge;
7mod own_commit;
8mod proposal;
9mod tnt;
10mod wipe;
11
12use std::sync::Arc;
13
14use core_crypto_keystore::Database;
15use openmls::prelude::group_info::GroupInfo;
16
17pub use self::tnt::TargetedMessagePolicy;
18pub(crate) use self::tnt::TntMessageCounter;
19use super::{Error, Result};
20use crate::{
21    CryptoProvider, GroupInfoBundle, LeafError, MlsTransport, RecursiveError, Session,
22    mls::{conversation::Conversation, credential::Credential},
23    transaction_context::TransactionContext,
24};
25
26/// A mutable view of an MLS conversation.
27///
28/// The conversation is ultimately owned by the conversation
29/// cache, but we take an `Arc` here so that we don't have to tie
30/// the lifetime of the guard to the cache.
31///
32/// More generally, the conversation guard gives us convenient mutable accesses to a single
33/// conversation. This in turn means that we don't have to duplicate the entire
34/// conversation API on `TransactionContext`.
35#[derive(Debug, derive_more::Constructor, derive_more::Deref)]
36pub struct ConversationMut {
37    #[deref(forward)]
38    inner: Arc<Conversation>,
39    tx_context: TransactionContext,
40}
41
42impl ConversationMut {
43    async fn transport(&self) -> Result<Arc<dyn MlsTransport>> {
44        self.tx_context
45            .mls_transport()
46            .await
47            .map_err(RecursiveError::transaction("getting transport for conversation guard"))
48            .map_err(Into::into)
49    }
50
51    async fn database(&self) -> Result<Arc<Database>> {
52        self.tx_context
53            .database()
54            .await
55            .map_err(RecursiveError::transaction("getting database from context"))
56            .map_err(Into::into)
57    }
58
59    async fn crypto_provider(&self) -> Result<CryptoProvider> {
60        self.tx_context
61            .crypto_provider()
62            .await
63            .map_err(RecursiveError::transaction(
64                "acquiring crypto provider for conversation guard from tx context",
65            ))
66            .map_err(Into::into)
67    }
68
69    pub(crate) async fn credential(&self) -> Result<Arc<Credential>> {
70        self.find_current_credential()
71            .await
72            .map_err(|_| Error::IdentityInitializationError)
73    }
74
75    /// Get access to the MLS session for this guard
76    pub(super) async fn session(&self) -> Result<Session> {
77        self.tx_context
78            .session()
79            .await
80            .map_err(RecursiveError::transaction("getting session from transaction context"))
81            .map_err(Into::into)
82    }
83
84    fn group_info(group_info: Option<GroupInfo>) -> Result<GroupInfoBundle> {
85        let group_info = group_info.ok_or(LeafError::MissingGroupInfo)?;
86        GroupInfoBundle::try_new_full_plaintext(group_info)
87    }
88}
89
90#[cfg(test)]
91mod test_utils {
92    use super::ConversationMut;
93    use crate::mls::conversation::Conversation;
94
95    impl ConversationMut {
96        /// Replaces the MLS group in memory with the one from keystore.
97        pub async fn drop_and_restore(&mut self) {
98            let session = self.tx_context.session().await.unwrap();
99            let id = self.id();
100
101            let conversation = Conversation::load(session, id).await.unwrap().unwrap();
102            self.tx_context.mls_groups().await.unwrap().insert(conversation);
103        }
104    }
105}