Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 107 additions & 92 deletions crypto/src/mls/conversation/conversation_guard/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ impl ConversationGuard {
pub(super) async fn merge_commit(&mut self) -> Result<()> {
let provider = self.crypto_provider().await?;
let (conversation_id, epoch) = self
.conversation_mut(async |conversation| {
conversation.commit_accepted(&provider).await?;
Ok((conversation.id().to_owned(), conversation.group.epoch().as_u64()))
.conversation_mut(|conversation| {
Box::pin(async move {
conversation.commit_accepted(&provider).await?;
Ok((conversation.id().to_owned(), conversation.group.epoch().as_u64()))
})
})
.await?;
self.central_context
Expand Down Expand Up @@ -69,26 +71,28 @@ impl ConversationGuard {
let backend = self.crypto_provider().await?;
let credential = self.credential().await?;

self.conversation_mut(async move |conversation| {
let signer = credential.signature_key();
let (commit, welcome, group_info) = conversation
.group
.add_members(&backend, signer, key_packages.clone())
.await
.map_err(|err| {
if Self::err_is_duplicate_signature_key(&err) {
let affected_clients = Self::clients_with_duplicate_signature_keys(key_packages.as_ref());
Error::DuplicateSignature { affected_clients }
} else {
MlsError::wrap("group add members")(err).into()
}
})?;

Ok(MlsCommitBundle {
commit,
welcome: Some(welcome),
group_info: Self::group_info(group_info)?,
encrypted_message: None,
self.conversation_mut(|conversation| {
Box::pin(async move {
let signer = credential.signature_key();
let (commit, welcome, group_info) = conversation
.group
.add_members(&backend, signer, key_packages.clone())
.await
.map_err(|err| {
if Self::err_is_duplicate_signature_key(&err) {
let affected_clients = Self::clients_with_duplicate_signature_keys(key_packages.as_ref());
Error::DuplicateSignature { affected_clients }
} else {
MlsError::wrap("group add members")(err).into()
}
})?;

Ok(MlsCommitBundle {
commit,
welcome: Some(welcome),
group_info: Self::group_info(group_info)?,
encrypted_message: None,
})
})
})
.await
Expand Down Expand Up @@ -133,27 +137,32 @@ impl ConversationGuard {
self.ensure_no_pending_commit().await?;
let backend = self.crypto_provider().await?;
let credential = self.credential().await?;
let signer = credential.signature_key();

let members = {
let guard = self.conversation().await;
guard
.group
.members()
.filter_map(|kp| {
clients
.iter()
.any(|client_id| client_id.borrow() == kp.credential.identity())
.then_some(kp.index)
})
.collect::<Vec<_>>()
};

let (commit, welcome, group_info) = self
.conversation_mut(async |conversation| {
let members = conversation
.group
.members()
.filter_map(|kp| {
clients
.iter()
.any(move |client_id| client_id.borrow() == kp.credential.identity())
.then_some(kp.index)
})
.collect::<Vec<_>>();

conversation
.group
.remove_members(&backend, signer, &members)
.await
.map_err(MlsError::wrap("group remove members"))
.map_err(Into::into)
.conversation_mut(|conversation| {
Box::pin(async move {
let signer = credential.signature_key();
conversation
.group
.remove_members(&backend, signer, &members)
.await
.map_err(MlsError::wrap("group remove members"))
.map_err(Into::into)
})
})
.await?;

Expand Down Expand Up @@ -194,36 +203,38 @@ impl ConversationGuard {
let backend = self.crypto_provider().await?;
let credential = credential.clone();

self.conversation_mut(async move |conversation| {
// If the credential remains the same and we still want to update, we explicitly need to pass `None` to
// openmls, if we just passed an unchanged leaf node, no update commit would be created.
// Also, we can avoid cloning in the case we don't need to create a new leaf node.
let updated_leaf_node = {
let leaf_node = conversation.group.own_leaf().ok_or(LeafError::InternalMlsError)?;
if leaf_node.credential() == &credential.mls_credential {
None
} else {
let mut leaf_node = leaf_node.clone();
leaf_node.set_credential_with_key(credential.to_mls_credential_with_key());
Some(leaf_node)
}
};

let (commit, welcome, group_info) = conversation
.group
.explicit_self_update(&backend, &credential.signature_key_pair, updated_leaf_node)
.await
.map_err(MlsError::wrap("group self update"))?;

// We should always have ratchet tree extension turned on hence GroupInfo should always be present
let group_info = group_info.ok_or(LeafError::MissingGroupInfo)?;
let group_info = MlsGroupInfoBundle::try_new_full_plaintext(group_info)?;

Ok(MlsCommitBundle {
welcome,
commit,
group_info,
encrypted_message: None,
self.conversation_mut(|conversation| {
Box::pin(async move {
// If the credential remains the same and we still want to update, we explicitly need to pass `None` to
// openmls, if we just passed an unchanged leaf node, no update commit would be created.
// Also, we can avoid cloning in the case we don't need to create a new leaf node.
let updated_leaf_node = {
let leaf_node = conversation.group.own_leaf().ok_or(LeafError::InternalMlsError)?;
if leaf_node.credential() == &credential.mls_credential {
None
} else {
let mut leaf_node = leaf_node.clone();
leaf_node.set_credential_with_key(credential.to_mls_credential_with_key());
Some(leaf_node)
}
};

let (commit, welcome, group_info) = conversation
.group
.explicit_self_update(&backend, &credential.signature_key_pair, updated_leaf_node)
.await
.map_err(MlsError::wrap("group self update"))?;

// We should always have ratchet tree extension turned on hence GroupInfo should always be present
let group_info = group_info.ok_or(LeafError::MissingGroupInfo)?;
let group_info = MlsGroupInfoBundle::try_new_full_plaintext(group_info)?;

Ok(MlsCommitBundle {
welcome,
commit,
group_info,
encrypted_message: None,
})
})
})
.await
Expand All @@ -240,21 +251,23 @@ impl ConversationGuard {
}

pub(crate) async fn commit_pending_proposals_inner(&mut self) -> Result<Option<MlsCommitBundle>> {
let session = &self.session().await?;
let provider = &self.crypto_provider().await?;
let session = self.session().await?;
let provider = self.crypto_provider().await?;
if self.conversation().await.group().pending_proposals().next().is_none() {
return Ok(None);
}

let (commit, welcome, openmls_group_info) = self
.conversation_mut(async |inner| {
let signer = &inner.find_current_credential(session).await?.signature_key_pair;
inner
.group
.commit_to_pending_proposals(provider, signer)
.await
.map_err(MlsError::wrap("group commit to pending proposals"))
.map_err(Into::into)
.conversation_mut(|inner| {
Box::pin(async move {
let signer = &inner.find_current_credential(&session).await?.signature_key_pair;
inner
.group
.commit_to_pending_proposals(&provider, signer)
.await
.map_err(MlsError::wrap("group commit to pending proposals"))
.map_err(Into::into)
})
})
.await?;
let group_info = MlsGroupInfoBundle::try_new_full_plaintext(
Expand All @@ -273,21 +286,23 @@ impl ConversationGuard {
&mut self,
proposals: Vec<openmls::prelude::Proposal>,
) -> Result<Option<MlsCommitBundle>> {
let session = &self.session().await?;
let provider = &self.crypto_provider().await?;
let session = self.session().await?;
let provider = self.crypto_provider().await?;
if proposals.is_empty() {
return Ok(None);
}

let (commit, welcome, openmls_group_info) = self
.conversation_mut(async |inner| {
let signer = &inner.find_current_credential(session).await?.signature_key_pair;
inner
.group
.commit_to_inline_proposals(provider, signer, proposals)
.await
.map_err(MlsError::wrap("group commit to pending proposals"))
.map_err(Into::into)
.conversation_mut(|inner| {
Box::pin(async move {
let signer = &inner.find_current_credential(&session).await?.signature_key_pair;
inner
.group
.commit_to_inline_proposals(&provider, signer, proposals)
.await
.map_err(MlsError::wrap("group commit to pending proposals"))
.map_err(Into::into)
})
})
.await?;
let group_info = MlsGroupInfoBundle::try_new_full_plaintext(
Expand Down
Loading
Loading