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, ExternalSenderKey, Result, SecretKey};
13use crate::{CipherSuite, ConversationConfiguration, ConversationId, CredentialRef, OpenMlsError, Session};
14
15#[derive(Debug, derive_more::Constructor)]
17pub struct Conversation {
18 pub(in crate::mls::conversation) id: ConversationId,
19 pub(in crate::mls::conversation) group: RwLock<MlsGroup>,
20 pub(in crate::mls::conversation) configuration: ConversationConfiguration,
21 session: Session,
22}
23
24impl Conversation {
25 pub fn id(&self) -> &ConversationIdRef {
27 ConversationIdRef::new(&self.id)
28 }
29
30 pub async fn group(&self) -> RwLockReadGuard<'_, MlsGroup> {
32 self.group.read().await
33 }
34
35 pub fn configuration(&self) -> &ConversationConfiguration {
37 &self.configuration
38 }
39
40 pub async fn epoch(&self) -> u64 {
42 self.group().await.epoch().as_u64()
43 }
44
45 pub fn cipher_suite(&self) -> CipherSuite {
47 self.configuration.cipher_suite
48 }
49
50 pub async fn credential_ref(&self) -> Result<CredentialRef> {
52 let credential = self
53 .find_current_credential()
54 .await
55 .map_err(|_| Error::IdentityInitializationError)?;
56 Ok(CredentialRef::from_credential(&credential))
57 }
58
59 pub async fn export_secret_key(&self, key_length: usize) -> Result<SecretKey> {
68 const EXPORTER_LABEL: &str = "exporter";
69 const EXPORTER_CONTEXT: &[u8] = &[];
70 self.group()
71 .await
72 .export_secret(
73 &self.session.crypto_provider,
74 EXPORTER_LABEL,
75 EXPORTER_CONTEXT,
76 key_length,
77 )
78 .map(Into::into)
79 .map_err(OpenMlsError::wrap("exporting secret key"))
80 .map_err(Into::into)
81 }
82
83 pub async fn get_external_sender(&self) -> Result<ExternalSenderKey> {
87 let group = self.group().await;
88 let ext_senders = group
89 .group_context_extensions()
90 .external_senders()
91 .ok_or(Error::MissingExternalSenderExtension)?;
92 let ext_sender = ext_senders.first().ok_or(Error::MissingExternalSenderExtension)?;
93 let ext_sender_public_key = ext_sender.signature_key().as_slice().to_vec().into();
94 Ok(ext_sender_public_key)
95 }
96}
97
98#[cfg(test)]
99mod test_utils {
100 use openmls::prelude::SignaturePublicKey;
101
102 use super::*;
103
104 impl Conversation {
105 pub async fn signature_keys(&self) -> Vec<SignaturePublicKey> {
106 let group = self.group().await;
107 group
108 .members()
109 .map(|m| m.signature_key)
110 .map(|mpk| SignaturePublicKey::from(mpk.as_slice()))
111 .collect()
112 }
113
114 pub async fn encryption_keys(&self) -> Vec<Vec<u8>> {
115 let group = self.group().await;
116 group.members().map(|m| m.encryption_key).collect()
117 }
118
119 pub async fn extensions(&self) -> openmls::prelude::Extensions {
120 let group = self.group().await;
121 group.export_group_context().extensions().to_owned()
122 }
123 }
124}