core_crypto_ffi/core_crypto/
conversation.rs

1use core_crypto::{RecursiveError, mls::conversation::Conversation as _};
2#[cfg(target_family = "wasm")]
3use wasm_bindgen::prelude::*;
4
5use crate::{Ciphersuite, ClientId, CoreCrypto, CoreCryptoResult};
6
7// Note that we can't do the same `Box<[u8]>` thing here; it doesn't work for async functions.
8#[cfg(target_family = "wasm")]
9pub(crate) type ConversationId = js_sys::Uint8Array;
10
11#[cfg(not(target_family = "wasm"))]
12pub(crate) type ConversationId = Vec<u8>;
13
14#[macro_export]
15macro_rules! conversation_id_vec {
16    ($conversation_id:expr) => {{
17        #[cfg(target_family = "wasm")]
18        {
19            // unfortunate that `Uint8Array` doesn't give us a way to borrow a byte slice,
20            // but apparently we have no lifetime guarantees so it's understandable
21            $conversation_id.to_vec()
22        }
23
24        #[cfg(not(target_family = "wasm"))]
25        {
26            // it's kind of silly that we have to clone it here given that both
27            // sides of the interface expect references, but that's unfortunately
28            // the only way to make the macro / lifetimes all work out
29            $conversation_id.to_owned()
30        }
31    }};
32}
33
34#[cfg_attr(not(target_family = "wasm"), uniffi::export)]
35#[cfg_attr(target_family = "wasm", wasm_bindgen)]
36impl CoreCrypto {
37    /// See [core_crypto::mls::conversation::ImmutableConversation::epoch]
38    pub async fn conversation_epoch(&self, conversation_id: &ConversationId) -> CoreCryptoResult<u64> {
39        let conversation_id = conversation_id_vec!(conversation_id);
40        let conversation = self
41            .inner
42            .get_raw_conversation(&conversation_id)
43            .await
44            .map_err(RecursiveError::mls_client("getting raw conversation by id"))?;
45        Ok(conversation.epoch().await)
46    }
47
48    /// See [core_crypto::mls::conversation::ImmutableConversation::ciphersuite]
49    pub async fn conversation_ciphersuite(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Ciphersuite> {
50        let conversation_id = conversation_id_vec!(conversation_id);
51        let cs = self
52            .inner
53            .get_raw_conversation(&conversation_id)
54            .await
55            .map_err(RecursiveError::mls_client("getting raw conversation by id"))?
56            .ciphersuite()
57            .await;
58        Ok(Ciphersuite::from(core_crypto::prelude::CiphersuiteName::from(cs)))
59    }
60
61    /// See [core_crypto::mls::MlsCentral::conversation_exists]
62    pub async fn conversation_exists(&self, conversation_id: &ConversationId) -> CoreCryptoResult<bool> {
63        let conversation_id = conversation_id_vec!(conversation_id);
64        self.inner
65            .conversation_exists(&conversation_id)
66            .await
67            .map_err(RecursiveError::mls_client("getting conversation existence by id"))
68            .map_err(Into::into)
69    }
70
71    /// See [core_crypto::mls::conversation::ImmutableConversation::get_client_ids]
72    pub async fn get_client_ids(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Vec<ClientId>> {
73        let conversation_id = conversation_id_vec!(conversation_id);
74        let conversation = self
75            .inner
76            .get_raw_conversation(&conversation_id)
77            .await
78            .map_err(RecursiveError::mls_client("getting raw conversation"))?;
79        Ok(conversation.get_client_ids().await.into_iter().map(ClientId).collect())
80    }
81
82    /// See [core_crypto::mls::conversation::ImmutableConversation::get_external_sender]
83    pub async fn get_external_sender(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Vec<u8>> {
84        let conversation_id = conversation_id_vec!(conversation_id);
85        let conversation = self
86            .inner
87            .get_raw_conversation(&conversation_id)
88            .await
89            .map_err(RecursiveError::mls_client("getting raw conversation"))?;
90        conversation.get_external_sender().await.map_err(Into::into)
91    }
92
93    /// See [core_crypto::mls::conversation::ImmutableConversation::export_secret_key]
94    pub async fn export_secret_key(
95        &self,
96        conversation_id: &ConversationId,
97        key_length: u32,
98    ) -> CoreCryptoResult<Vec<u8>> {
99        let conversation_id = conversation_id_vec!(conversation_id);
100        self.inner
101            .get_raw_conversation(&conversation_id)
102            .await
103            .map_err(RecursiveError::mls_client("getting raw conversation"))?
104            .export_secret_key(key_length as usize)
105            .await
106            .map_err(Into::into)
107    }
108}