core_crypto/mls/conversation/immutable/
mod.rs1mod clients;
2mod commit_delay;
3mod credential;
4mod duplicate;
5mod e2ei;
6mod history_sharing;
7mod persistence;
8
9use async_lock::{RwLock, RwLockReadGuard};
10use openmls::group::MlsGroup;
11
12use super::{ConversationIdRef, Error, Result, SecretKey};
13use crate::{
14 CipherSuite, ConversationConfiguration, ConversationId, CredentialRef, ExternalSender, OpenMlsError, Session,
15};
16
17#[derive(Debug, derive_more::Constructor)]
19pub struct Conversation {
20 pub(in crate::mls::conversation) id: ConversationId,
21 pub(in crate::mls::conversation) group: RwLock<MlsGroup>,
22 pub(in crate::mls::conversation) configuration: ConversationConfiguration,
23 session: Session,
24}
25
26impl Conversation {
27 pub fn id(&self) -> &ConversationIdRef {
29 ConversationIdRef::new(&self.id)
30 }
31
32 pub async fn group(&self) -> RwLockReadGuard<'_, MlsGroup> {
34 self.group.read().await
35 }
36
37 pub fn configuration(&self) -> &ConversationConfiguration {
39 &self.configuration
40 }
41
42 pub async fn epoch(&self) -> u64 {
44 self.group().await.epoch().as_u64()
45 }
46
47 pub fn cipher_suite(&self) -> CipherSuite {
49 self.configuration.cipher_suite
50 }
51
52 pub async fn credential_ref(&self) -> Result<CredentialRef> {
54 let credential = self
55 .find_current_credential()
56 .await
57 .map_err(|_| Error::IdentityInitializationError)?;
58 Ok(CredentialRef::from_credential(&credential))
59 }
60
61 pub async fn export_secret_key(&self, key_length: usize) -> Result<SecretKey> {
70 const EXPORTER_LABEL: &str = "exporter";
71 const EXPORTER_CONTEXT: &[u8] = &[];
72 self.group()
73 .await
74 .export_secret(
75 &self.session.crypto_provider,
76 EXPORTER_LABEL,
77 EXPORTER_CONTEXT,
78 key_length,
79 )
80 .map(Into::into)
81 .map_err(OpenMlsError::wrap("exporting secret key"))
82 .map_err(Into::into)
83 }
84
85 pub async fn get_external_sender(&self) -> Result<ExternalSender> {
89 let group = self.group().await;
90 let ext_senders = group
91 .group_context_extensions()
92 .external_senders()
93 .ok_or(Error::MissingExternalSenderExtension)?;
94 let ext_sender = ext_senders.first().ok_or(Error::MissingExternalSenderExtension)?;
95 Ok(ext_sender.clone().into())
96 }
97}
98
99#[cfg(test)]
100mod test_utils {
101 use openmls::prelude::SignaturePublicKey;
102
103 use super::*;
104
105 impl Conversation {
106 pub async fn signature_keys(&self) -> Vec<SignaturePublicKey> {
107 let group = self.group().await;
108 group
109 .members()
110 .map(|m| m.signature_key)
111 .map(|mpk| SignaturePublicKey::from(mpk.as_slice()))
112 .collect()
113 }
114
115 pub async fn encryption_keys(&self) -> Vec<Vec<u8>> {
116 let group = self.group().await;
117 group.members().map(|m| m.encryption_key).collect()
118 }
119
120 pub async fn extensions(&self) -> openmls::prelude::Extensions {
121 let group = self.group().await;
122 group.export_group_context().extensions().to_owned()
123 }
124 }
125}