Skip to content

Commit

Permalink
[uniffi] Expose RosterUpdate on Commit (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
mgeisler authored Mar 26, 2024
1 parent ae34509 commit d54563f
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 4 deletions.
64 changes: 61 additions & 3 deletions mls-rs-uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,51 @@ impl From<mls_rs::group::proposal::Proposal> for Proposal {
}
}

/// Update of a member due to a commit.
#[derive(Clone, Debug, uniffi::Record)]
pub struct MemberUpdate {
pub prior: Arc<SigningIdentity>,
pub new: Arc<SigningIdentity>,
}

/// A set of roster updates due to a commit.
#[derive(Clone, Debug, uniffi::Record)]
pub struct RosterUpdate {
pub added: Vec<Arc<SigningIdentity>>,
pub removed: Vec<Arc<SigningIdentity>>,
pub updated: Vec<MemberUpdate>,
}

impl RosterUpdate {
// This is an associated function because it felt wrong to hide
// the clones in an `impl From<&mls_rs::identity::RosterUpdate>`.
fn new(roster_update: &mls_rs::identity::RosterUpdate) -> Self {
let added = roster_update
.added()
.iter()
.map(|member| Arc::new(member.signing_identity.clone().into()))
.collect();
let removed = roster_update
.removed()
.iter()
.map(|member| Arc::new(member.signing_identity.clone().into()))
.collect();
let updated = roster_update
.updated()
.iter()
.map(|update| MemberUpdate {
prior: Arc::new(update.prior.signing_identity.clone().into()),
new: Arc::new(update.new.signing_identity.clone().into()),
})
.collect();
RosterUpdate {
added,
removed,
updated,
}
}
}

/// A [`mls_rs::group::ReceivedMessage`] wrapper.
#[derive(Clone, Debug, uniffi::Enum)]
pub enum ReceivedMessage {
Expand All @@ -208,7 +253,10 @@ pub enum ReceivedMessage {
},

/// A new commit was processed creating a new group state.
Commit { committer: Arc<SigningIdentity> },
Commit {
committer: Arc<SigningIdentity>,
roster_update: RosterUpdate,
},

// TODO(mgeisler): rename to `Proposal` when
// https://github.com/awslabs/mls-rs/issues/98 is fixed.
Expand Down Expand Up @@ -343,6 +391,11 @@ impl Client {
Ok(message.into())
}

pub fn signing_identity(&self) -> Result<Arc<SigningIdentity>, Error> {
let (signing_identity, _) = self.inner.signing_identity()?;
Ok(Arc::new(signing_identity.clone().into()))
}

/// Create and immediately join a new group.
///
/// If a group ID is not given, the underlying library will create
Expand Down Expand Up @@ -475,7 +528,8 @@ impl TryFrom<mls_rs::group::CommitOutput> for CommitOutput {
}
}

#[derive(Clone, Debug, uniffi::Object)]
#[derive(Clone, Debug, PartialEq, Eq, uniffi::Object)]
#[uniffi::export(Eq)]
pub struct SigningIdentity {
inner: identity::SigningIdentity,
}
Expand Down Expand Up @@ -686,7 +740,11 @@ impl Group {
group::ReceivedMessage::Commit(commit_message) => {
let committer =
Arc::new(index_to_identity(&group, commit_message.committer)?.into());
Ok(ReceivedMessage::Commit { committer })
let roster_update = RosterUpdate::new(commit_message.state_update.roster_update());
Ok(ReceivedMessage::Commit {
committer,
roster_update,
})
}
group::ReceivedMessage::Proposal(proposal_message) => {
let sender = match proposal_message.sender {
Expand Down
22 changes: 22 additions & 0 deletions mls-rs-uniffi/tests/roster_update_sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from mls_rs_uniffi import Client, CipherSuite, generate_signature_keypair, client_config_default

client_config = client_config_default()
alice = Client(b'alice', generate_signature_keypair(CipherSuite.CURVE25519_AES128), client_config)
bob = Client(b'bob', generate_signature_keypair(CipherSuite.CURVE25519_AES128), client_config)
carla = Client(b'carla', generate_signature_keypair(CipherSuite.CURVE25519_AES128), client_config)

# Alice creates a group and adds Bob.
alice_group = alice.create_group(None)
output = alice_group.add_members([bob.generate_key_package_message()])
alice_group.process_incoming_message(output.commit_message)

# Bob join the group and adds Carla.
bob_group = bob.join_group(None, output.welcome_message).group
output = bob_group.add_members([carla.generate_key_package_message()])
bob_group.process_incoming_message(output.commit_message)

# Alice learns that Carla has been added to the group.
received = alice_group.process_incoming_message(output.commit_message)
assert received.roster_update.added == [carla.signing_identity()]
assert received.roster_update.removed == []
assert received.roster_update.updated == []
1 change: 1 addition & 0 deletions mls-rs-uniffi/tests/scenarios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ generate_python_tests!(client_config_default_sync, client_config_default_async);
generate_python_tests!(custom_storage_sync, None);
generate_python_tests!(simple_scenario_sync, simple_scenario_async);
generate_python_tests!(ratchet_tree_sync, ratchet_tree_async);
generate_python_tests!(roster_update_sync, None);
2 changes: 1 addition & 1 deletion mls-rs-uniffi/tests/simple_scenario_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def scenario():

commit = await alice.add_members([message])
await alice.process_incoming_message(commit.commit_message)
bob = (await bob.join_group(None, commit.welcome_messages[0])).group
bob = (await bob.join_group(None, commit.welcome_message)).group

msg = await alice.encrypt_application_message(b'hello, bob')
output = await bob.process_incoming_message(msg)
Expand Down

0 comments on commit d54563f

Please sign in to comment.