use crate::group::tests_and_kats::utils::{generate_credential_with_key, generate_key_package};
use crate::{framing::*, group::*};
#[openmls_test::openmls_test]
fn remove_blank() {
let group_id = GroupId::from_slice(b"Test Group");
let alice_provider = &Provider::default();
let bob_provider = &Provider::default();
let charlie_provider = &Provider::default();
let alice_credential_with_key_and_signer = generate_credential_with_key(
"Alice".into(),
ciphersuite.signature_algorithm(),
alice_provider,
);
let bob_credential_with_key_and_signer = generate_credential_with_key(
"Bob".into(),
ciphersuite.signature_algorithm(),
bob_provider,
);
let charlie_credential_with_key_and_signer = generate_credential_with_key(
"Charlie".into(),
ciphersuite.signature_algorithm(),
charlie_provider,
);
let bob_key_package = generate_key_package(
ciphersuite,
Extensions::empty(),
bob_provider,
bob_credential_with_key_and_signer.clone(),
);
let charlie_key_package = generate_key_package(
ciphersuite,
Extensions::empty(),
charlie_provider,
charlie_credential_with_key_and_signer,
);
let mls_group_create_config = MlsGroupCreateConfig::builder()
.ciphersuite(ciphersuite)
.build();
let mut alice_group = MlsGroup::new_with_group_id(
alice_provider,
&alice_credential_with_key_and_signer.signer,
&mls_group_create_config,
group_id,
alice_credential_with_key_and_signer
.credential_with_key
.clone(),
)
.expect("An unexpected error occurred.");
let (_message, welcome, _group_info) = alice_group
.add_members(
alice_provider,
&alice_credential_with_key_and_signer.signer,
&[
bob_key_package.key_package().clone(),
charlie_key_package.key_package().clone(),
],
)
.expect("An unexpected error occurred.");
alice_group
.merge_pending_commit(alice_provider)
.expect("error merging pending commit");
let welcome: MlsMessageIn = welcome.into();
let welcome = welcome
.into_welcome()
.expect("expected message to be a welcome");
let bob_group = StagedWelcome::new_from_welcome(
bob_provider,
mls_group_create_config.join_config(),
welcome.clone(),
Some(alice_group.export_ratchet_tree().into()),
)
.expect("Error creating staged join from Welcome")
.into_group(bob_provider)
.expect("Error creating group from staged join");
let bob_index = bob_group.own_leaf_index();
alice_group
.remove_members(
alice_provider,
&alice_credential_with_key_and_signer.signer,
&[bob_index],
)
.expect("error removing member the first time");
alice_group.merge_pending_commit(alice_provider).unwrap();
alice_group
.remove_members(
alice_provider,
&alice_credential_with_key_and_signer.signer,
&[bob_index],
)
.expect_err("using API to re-remove someone should fail");
}
#[openmls_test::openmls_test]
fn test_remove_operation_variants() {
#[derive(Debug, Clone, Copy)]
enum TestCase {
Remove,
Leave,
}
for test_case in [TestCase::Remove, TestCase::Leave] {
let alice_provider = &Provider::default();
let bob_provider = &Provider::default();
let charlie_provider = &Provider::default();
let group_id = GroupId::random(alice_provider.rand());
let alice_credential_with_key_and_signer = generate_credential_with_key(
"Alice".into(),
ciphersuite.signature_algorithm(),
alice_provider,
);
let bob_credential_with_key_and_signer = generate_credential_with_key(
"Bob".into(),
ciphersuite.signature_algorithm(),
bob_provider,
);
let charlie_credential_with_key_and_signer = generate_credential_with_key(
"Charlie".into(),
ciphersuite.signature_algorithm(),
charlie_provider,
);
let bob_key_package = generate_key_package(
ciphersuite,
Extensions::empty(),
bob_provider,
bob_credential_with_key_and_signer.clone(),
);
let charlie_key_package = generate_key_package(
ciphersuite,
Extensions::empty(),
charlie_provider,
charlie_credential_with_key_and_signer,
);
let mls_group_create_config = MlsGroupCreateConfig::builder()
.ciphersuite(ciphersuite)
.build();
let mut alice_group = MlsGroup::new_with_group_id(
alice_provider,
&alice_credential_with_key_and_signer.signer,
&mls_group_create_config,
group_id,
alice_credential_with_key_and_signer
.credential_with_key
.clone(),
)
.expect("An unexpected error occurred.");
let (_message, welcome, _group_info) = alice_group
.add_members(
alice_provider,
&alice_credential_with_key_and_signer.signer,
&[
bob_key_package.key_package().clone(),
charlie_key_package.key_package().clone(),
],
)
.expect("An unexpected error occurred.");
alice_group
.merge_pending_commit(alice_provider)
.expect("error merging pending commit");
let welcome: MlsMessageIn = welcome.into();
let welcome = welcome
.into_welcome()
.expect("expected message to be a welcome");
let mut bob_group = StagedWelcome::new_from_welcome(
bob_provider,
mls_group_create_config.join_config(),
welcome.clone(),
Some(alice_group.export_ratchet_tree().into()),
)
.expect("Error creating staged join from Welcome")
.into_group(bob_provider)
.expect("Error creating group from staged join");
let mut charlie_group = StagedWelcome::new_from_welcome(
charlie_provider,
mls_group_create_config.join_config(),
welcome,
Some(alice_group.export_ratchet_tree().into()),
)
.expect("Error creating staged join from Welcome")
.into_group(charlie_provider)
.expect("Error creating group from staged join");
let alice_index = alice_group.own_leaf_index();
let bob_index = bob_group.own_leaf_index();
let (message, _welcome, _group_info) = match test_case {
TestCase::Remove => alice_group
.remove_members(
alice_provider,
&alice_credential_with_key_and_signer.signer,
&[bob_index],
)
.expect("Could not remove members."),
TestCase::Leave => {
let message = bob_group
.leave_group(bob_provider, &bob_credential_with_key_and_signer.signer)
.expect("Could not leave group.");
for (group, provider) in [
(&mut alice_group, alice_provider),
(&mut charlie_group, charlie_provider),
] {
let processed_message = group
.process_message(provider, message.clone().into_protocol_message().unwrap())
.expect("Could not process message.");
match processed_message.into_content() {
ProcessedMessageContent::ProposalMessage(proposal) => {
group
.store_pending_proposal(provider.storage(), *proposal)
.unwrap();
}
_ => unreachable!(),
}
}
alice_group
.commit_to_pending_proposals(
alice_provider,
&alice_credential_with_key_and_signer.signer,
)
.expect("An unexpected error occurred.")
}
};
let alice_staged_commit = alice_group.pending_commit().expect("No pending commit.");
let remove_proposal = alice_staged_commit
.remove_proposals()
.next()
.expect("An unexpected error occurred.");
let remove_operation = RemoveOperation::new(remove_proposal, &alice_group)
.expect("An unexpected Error occurred.");
match test_case {
TestCase::Remove => {
match remove_operation {
RemoveOperation::WeRemovedThem(removed) => {
assert_eq!(removed, bob_index);
}
_ => unreachable!(),
}
}
TestCase::Leave => {
match remove_operation {
RemoveOperation::TheyLeft(removed) => {
assert_eq!(removed, bob_index);
}
_ => unreachable!(),
}
}
}
let bob_processed_message = bob_group
.process_message(
bob_provider,
message.clone().into_protocol_message().unwrap(),
)
.expect("Could not process message.");
match bob_processed_message.into_content() {
ProcessedMessageContent::StagedCommitMessage(bob_staged_commit) => {
let remove_proposal = bob_staged_commit
.remove_proposals()
.next()
.expect("An unexpected error occurred.");
let remove_operation = RemoveOperation::new(remove_proposal, &bob_group)
.expect("An unexpected Error occurred.");
match test_case {
TestCase::Remove => {
match remove_operation {
RemoveOperation::WeWereRemovedBy(sender) => {
assert!(sender.is_member());
assert!(bob_staged_commit.self_removed());
match sender {
Sender::Member(member) => {
assert_eq!(member, alice_index);
}
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
TestCase::Leave => {
match remove_operation {
RemoveOperation::WeLeft => {
assert!(bob_staged_commit.self_removed());
}
_ => unreachable!(),
}
}
}
}
_ => unreachable!(),
}
let protocol_message = message.into_protocol_message().unwrap();
let charlie_processed_message = charlie_group
.process_message(charlie_provider, protocol_message)
.expect("Could not process message.");
match charlie_processed_message.into_content() {
ProcessedMessageContent::StagedCommitMessage(charlie_staged_commit) => {
let remove_proposal = charlie_staged_commit
.remove_proposals()
.next()
.expect("An unexpected error occurred.");
let remove_operation = RemoveOperation::new(remove_proposal, &charlie_group)
.expect("An unexpected Error occurred.");
match test_case {
TestCase::Remove => {
match remove_operation {
RemoveOperation::TheyWereRemovedBy((removed, sender)) => {
assert!(sender.is_member());
assert_eq!(removed, bob_index);
match sender {
Sender::Member(member) => {
assert_eq!(member, alice_index);
}
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
TestCase::Leave => {
match remove_operation {
RemoveOperation::TheyLeft(removed) => {
assert_eq!(removed, bob_index);
}
_ => unreachable!(),
}
}
}
}
_ => unreachable!(),
}
}
}