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, 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::context("getting transport for conversation guard"))
48            .map_err(Into::into)
49    }
50
51    fn database(&self) -> Result<Arc<Database>> {
52        self.tx_context
53            .database()
54            .map_err(RecursiveError::context("getting database from context"))
55            .map_err(Into::into)
56    }
57
58    async fn crypto_provider(&self) -> Result<CryptoProvider> {
59        self.tx_context
60            .crypto_provider()
61            .await
62            .map_err(RecursiveError::context(
63                "acquiring crypto provider for conversation guard from tx context",
64            ))
65            .map_err(Into::into)
66    }
67
68    pub(crate) async fn credential(&self) -> Result<Arc<Credential>> {
69        self.find_current_credential()
70            .await
71            .map_err(|_| Error::IdentityInitializationError)
72    }
73
74    /// Get access to the MLS session for this guard
75    pub(super) async fn session(&self) -> Result<Session> {
76        self.tx_context
77            .session()
78            .await
79            .map_err(RecursiveError::context("getting session from transaction context"))
80            .map_err(Into::into)
81    }
82
83    fn group_info(group_info: Option<GroupInfo>) -> Result<GroupInfoBundle> {
84        let group_info = group_info.ok_or(Error::MissingGroupInfo)?;
85        GroupInfoBundle::try_new_full_plaintext(group_info)
86    }
87}
88
89#[cfg(test)]
90mod test_utils {
91    use super::ConversationMut;
92    use crate::mls::conversation::Conversation;
93
94    impl ConversationMut {
95        /// Replaces the MLS group in memory with the one from keystore.
96        pub async fn drop_and_restore(&mut self) {
97            let session = self.tx_context.session().await.unwrap();
98            let id = self.id();
99
100            let conversation = Conversation::load(session, id).await.unwrap().unwrap();
101            self.tx_context.mls_groups().await.unwrap().insert(conversation);
102        }
103    }
104}