Skip to main content

core_crypto/mls/conversation/immutable/
e2ei.rs

1use std::{borrow::Borrow, collections::HashMap};
2
3use openmls_traits::OpenMlsCryptoProvider as _;
4
5use super::{Error, Result};
6use crate::{
7    ClientIdRef, CredentialType, E2eiConversationState, RecursiveError, Session, UserId, WireIdentity,
8    mls::credential::ext::CredentialExt as _,
9};
10
11impl super::Conversation {
12    /// Indicates when to mark a conversation as not verified i.e. when not all its members have a X509
13    /// Credential generated by Wire's end-to-end identity enrollment
14    pub async fn e2ei_conversation_state(&self) -> Result<E2eiConversationState> {
15        let backend = &self.session.crypto_provider;
16
17        let state = Session::compute_conversation_state(
18            self.cipher_suite(),
19            self.group().await.members_credentials(),
20            CredentialType::X509,
21            backend.authentication_service(),
22        )
23        .await;
24        Ok(state)
25    }
26
27    /// From a given conversation, get the identity of the members supplied. Identity is only present for
28    /// members with a Certificate Credential (after turning on end-to-end identity).
29    /// If no member has a x509 certificate, it will return an empty Vec
30    pub async fn get_device_identities(
31        &self,
32        device_ids: &[impl Borrow<ClientIdRef> + Sync],
33    ) -> Result<Vec<WireIdentity>> {
34        if device_ids.is_empty() {
35            return Err(Error::CallerError(
36                "This function accepts a list of IDs as a parameter, but that list was empty.",
37            ));
38        }
39        let mls_provider = &self.session.crypto_provider;
40        let auth_service = mls_provider.authentication_service();
41
42        let pki_env = auth_service.pki_env().await;
43
44        let mut identities = vec![];
45        for (id, credential) in self.members_with_key().await {
46            if device_ids.iter().any(|client_id| client_id.borrow() == id) {
47                identities.push(
48                    credential
49                        .extract_identity(self.cipher_suite(), pki_env.as_deref())
50                        .await
51                        .map_err(RecursiveError::mls_credential("extracting identity"))?,
52                );
53            }
54        }
55        Ok(identities)
56    }
57
58    /// From a given conversation, get the identity of the users (device holders) supplied.
59    /// Identity is only present for devices with a Certificate Credential (after turning on end-to-end identity).
60    /// If no member has a x509 certificate, it will return an empty Vec.
61    ///
62    /// Returns a Map with all the identities for a given users. Consumers are then recommended to
63    /// reduce those identities to determine the actual status of a user.
64    pub async fn get_user_identities(&self, user_ids: &[String]) -> Result<HashMap<String, Vec<WireIdentity>>> {
65        if user_ids.is_empty() {
66            return Err(Error::CallerError(
67                "This function accepts a list of IDs as a parameter, but that list was empty.",
68            ));
69        }
70        let mls_provider = &self.session.crypto_provider;
71        let auth_service = mls_provider.authentication_service();
72        let user_ids = user_ids.iter().map(|uid| uid.as_bytes()).collect::<Vec<_>>();
73
74        let pki_env = auth_service.pki_env().await;
75
76        let mut identities = HashMap::new();
77        for (id, credential) in self.members_with_key().await {
78            let uid = match UserId::try_from(id.as_slice()) {
79                Ok(uid) => uid,
80                Err(_) => continue,
81            };
82
83            if !user_ids.contains(&uid) {
84                continue;
85            }
86
87            let uid = String::try_from(uid).map_err(RecursiveError::mls_client("getting user identities"))?;
88            let identity = credential
89                .extract_identity(self.cipher_suite(), pki_env.as_deref())
90                .await
91                .map_err(RecursiveError::mls_credential("extracting identity"))?;
92            let value = identities.entry(uid).or_insert_with(Vec::new);
93            value.push(identity);
94        }
95
96        Ok(identities)
97    }
98}