Skip to main content

core_crypto/mls/conversation/immutable/
credential.rs

1use std::{collections::HashMap, sync::Arc};
2
3use openmls::prelude::{Credential as MlsCredential, CredentialWithKey, SignaturePublicKey};
4
5use super::{Error, Result};
6use crate::{ClientId, Credential, RecursiveError, mls::conversation::group_metadata};
7
8impl super::Conversation {
9    /// Find the current leaf node, then load it scredential.
10    pub(crate) async fn find_current_credential(&self) -> Result<Arc<Credential>> {
11        // if the group has pending proposals one of which is an own update proposal, we should take the credential from
12        // there.
13        let group = self.group().await;
14        let own_leaf =
15            group_metadata::current_own_leaf(&group).ok_or(Error::MlsGroupInvalidState("own leaf node not found"))?;
16        let credential = self
17            .session
18            .load_credential(own_leaf.signature_key(), own_leaf.credential().credential_type())
19            .await
20            .map_err(RecursiveError::context("finding current credential"))?;
21        Ok(credential)
22    }
23
24    /// Returns all members credentials from the group/conversation
25    pub async fn members(&self) -> HashMap<Vec<u8>, MlsCredential> {
26        // this fold is the compact way to express this:
27        // a normal `.map().collect()` would preserve later instances of duplicated keys,
28        // but this preserves the first instance of each key
29        self.group().await.members().fold(HashMap::new(), |mut acc, kp| {
30            let credential = kp.credential;
31            let id = credential.identity().to_vec();
32            acc.entry(id).or_insert(credential);
33            acc
34        })
35    }
36
37    /// Returns all members credentials with their signature public key from the group/conversation
38    pub async fn members_with_key(&self) -> Result<HashMap<ClientId, CredentialWithKey>> {
39        self.group()
40            .await
41            .members()
42            .map(|member| {
43                let credential = member.credential;
44                let id: ClientId = credential
45                    .identity()
46                    .try_into()
47                    .map_err(RecursiveError::context("client id from bytes"))?;
48
49                let credential = CredentialWithKey {
50                    credential,
51                    signature_key: SignaturePublicKey::from(member.signature_key),
52                };
53
54                Ok((id, credential))
55            })
56            .collect()
57    }
58
59    pub(crate) async fn own_mls_credential(&self) -> Result<MlsCredential> {
60        let credential = self
61            .group()
62            .await
63            .own_leaf_node()
64            .ok_or(Error::MlsGroupInvalidState("own_leaf_node not present in group"))?
65            .credential()
66            .to_owned();
67        Ok(credential)
68    }
69}