core_crypto/mls/conversation/immutable/
clients.rs1use std::collections::HashSet;
2
3use log::trace;
4use openmls::prelude::{LeafNodeIndex, Proposal};
5
6use crate::{ClientId, HISTORY_CLIENT_ID_PREFIX, RecursiveError, mls::conversation::immutable::Result};
7
8impl super::Conversation {
9 pub async fn get_client_ids(&self) -> Result<Vec<ClientId>> {
12 let prefix = HISTORY_CLIENT_ID_PREFIX.as_bytes();
13 self.group()
14 .await
15 .members()
16 .filter(|member| !member.credential.identity().starts_with(prefix))
17 .map(|kp| {
18 ClientId::new_from_bytes(kp.credential.identity().to_owned())
19 .map_err(RecursiveError::mls_client("new client id from bytes"))
20 .map_err(Into::into)
21 })
22 .collect()
23 }
24
25 pub async fn get_history_client_ids(&self) -> Vec<Vec<u8>> {
27 let prefix = HISTORY_CLIENT_ID_PREFIX.as_bytes();
28
29 self.group()
30 .await
31 .members()
32 .filter_map(|kp| {
33 let identity = kp.credential.identity();
34
35 identity.starts_with(prefix).then(|| identity.to_owned())
36 })
37 .collect()
38 }
39 async fn pending_removals(&self) -> Vec<LeafNodeIndex> {
41 self.group()
42 .await
43 .pending_proposals()
44 .filter_map(|proposal| match proposal.proposal() {
45 Proposal::Remove(remove) => Some(remove.removed()),
46 _ => None,
47 })
48 .collect::<Vec<_>>()
49 }
50
51 pub async fn members_in_next_epoch(&self) -> Result<Vec<ClientId>> {
53 let pending_removals = self.pending_removals().await;
54 let existing_clients = self
55 .group()
56 .await
57 .members()
58 .filter_map(|member| {
59 if !pending_removals.contains(&member.index) {
60 let client_id_result = ClientId::new_from_bytes(member.credential.identity().to_owned())
61 .map_err(RecursiveError::mls_client("new client id from bytes"))
62 .map_err(Into::into);
63 Some(client_id_result)
64 } else {
65 trace!(client_index:% = member.index; "Client is pending removal");
66 None
67 }
68 })
69 .collect::<Result<HashSet<_>>>()?;
70 Ok(existing_clients.into_iter().collect())
71 }
72}