core_crypto/mls/session/
mod.rs1mod credential;
2pub(crate) mod e2e_identity;
3mod epoch_observer;
4mod error;
5mod history_observer;
6pub(crate) mod id;
7pub(crate) mod key_package;
8pub(crate) mod user_id;
9
10use std::sync::Arc;
11
12use async_lock::{Mutex, RwLock};
13pub use epoch_observer::EpochObserver;
14pub(crate) use error::{Error, Result};
15pub use history_observer::HistoryObserver;
16use openmls_traits::OpenMlsCryptoProvider;
17
18use crate::{
19 ClientId, HistorySecret, ImmutableDatabase, LeafError, MlsTransport, OpenMlsError, RecursiveError,
20 mls::{
21 conversation::{Conversation, ConversationIdRef},
22 conversation_cache::ConversationCache,
23 },
24 mls_provider::{CryptoProvider, EntropySeed},
25};
26
27#[derive(Clone, derive_more::Debug)]
38pub struct Session {
39 id: ClientId,
40 pub(crate) crypto_provider: CryptoProvider,
41 pub(crate) transport: Arc<dyn MlsTransport + 'static>,
42 database: ImmutableDatabase,
43 #[debug("EpochObserver")]
44 pub(crate) epoch_observer: Arc<RwLock<Option<Arc<dyn EpochObserver + 'static>>>>,
45 #[debug("HistoryObserver")]
46 pub(crate) history_observer: Arc<RwLock<Option<Arc<dyn HistoryObserver + 'static>>>>,
47 pub(crate) conversation_cache: Arc<Mutex<ConversationCache>>,
52}
53
54impl Session {
55 pub fn new(
57 id: ClientId,
58 crypto_provider: CryptoProvider,
59 database: ImmutableDatabase,
60 transport: Arc<dyn MlsTransport>,
61 ) -> Self {
62 Self {
63 id,
64 crypto_provider,
65 transport,
66 database,
67 epoch_observer: Arc::new(RwLock::new(None)),
68 history_observer: Arc::new(RwLock::new(None)),
69 conversation_cache: Arc::new(Mutex::new(ConversationCache::new())),
70 }
71 }
72
73 pub async fn get_raw_conversation(&self, id: &ConversationIdRef) -> Result<Conversation> {
78 Conversation::load(self.clone(), id)
79 .await
80 .map_err(RecursiveError::mls_conversation("getting raw conversation by id"))?
81 .ok_or_else(|| LeafError::ConversationNotFound(id.to_owned()))
82 .map_err(Into::into)
83 }
84
85 pub async fn conversation_exists(&self, id: &ConversationIdRef) -> Result<bool> {
87 match self.get_raw_conversation(id).await {
88 Ok(_) => Ok(true),
89 Err(Error::Leaf(LeafError::ConversationNotFound(_))) => Ok(false),
90 Err(e) => Err(e),
91 }
92 }
93
94 pub fn random_bytes(&self, len: usize) -> crate::mls::Result<Vec<u8>> {
96 use openmls_traits::random::OpenMlsRand as _;
97 self.crypto_provider
98 .rand()
99 .random_vec(len)
100 .map_err(OpenMlsError::wrap("generating random vector"))
101 .map_err(Into::into)
102 }
103
104 pub fn database(&self) -> &ImmutableDatabase {
106 &self.database
107 }
108
109 pub async fn reseed(&self, seed: Option<EntropySeed>) -> crate::mls::Result<()> {
111 self.crypto_provider
112 .reseed(seed)
113 .map_err(OpenMlsError::wrap("reseeding mls backend"))
114 .map_err(Into::into)
115 }
116
117 pub(crate) async fn restore_from_history_secret(&self, history_secret: HistorySecret) -> Result<()> {
119 history_secret
121 .key_package
122 .store(&self.crypto_provider)
123 .await
124 .map_err(OpenMlsError::wrap("storing key package encapsulation"))?;
125
126 Ok(())
127 }
128
129 pub fn id(&self) -> ClientId {
131 self.id.clone()
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use core_crypto_keystore::{entities::*, traits::FetchFromDatabase};
138
139 use super::*;
140 use crate::{KeystoreError, mls_provider::CryptoProvider, transaction_context::test_utils::EntitiesCount};
141
142 impl Session {
143 #![allow(missing_docs)]
145
146 pub async fn find_keypackages(&self, backend: &CryptoProvider) -> Result<Vec<openmls::prelude::KeyPackage>> {
147 let kps = backend
148 .key_store()
149 .mls_fetch_key_packages::<openmls::prelude::KeyPackage>(u32::MAX)
150 .await
151 .map_err(KeystoreError::wrap("fetching mls keypackages"))?;
152 Ok(kps)
153 }
154
155 pub async fn count_entities(&self) -> EntitiesCount {
157 let keystore = &self.database;
158 let credential = keystore.count::<StoredCredential>().await.unwrap();
159 let encryption_keypair = keystore.count::<StoredEncryptionKeyPair>().await.unwrap();
160 let epoch_encryption_keypair = keystore.count::<StoredEpochEncryptionKeypair>().await.unwrap();
161 let enrollment = keystore.count::<StoredE2eiEnrollment>().await.unwrap();
162 let group = keystore.count::<PersistedMlsGroup>().await.unwrap();
163 let hpke_private_key = keystore.count::<StoredHpkePrivateKey>().await.unwrap();
164 let key_package = keystore.count::<StoredKeypackage>().await.unwrap();
165 let pending_group = keystore.count::<PersistedMlsPendingGroup>().await.unwrap();
166 let pending_messages = keystore.count::<MlsPendingMessage>().await.unwrap();
167 let psk_bundle = keystore.count::<StoredPskBundle>().await.unwrap();
168 EntitiesCount {
169 credential,
170 encryption_keypair,
171 epoch_encryption_keypair,
172 enrollment,
173 group,
174 hpke_private_key,
175 key_package,
176 pending_group,
177 pending_messages,
178 psk_bundle,
179 }
180 }
181 }
182}