Skip to content

Commit

Permalink
feat: can set initial group name and read from group mutable metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
cameronvoell committed Apr 3, 2024
1 parent a99d38b commit fef808e
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 287 deletions.
98 changes: 98 additions & 0 deletions xmtp_mls/src/groups/group_mutable_metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use openmls::{extensions::{Extension, UnknownExtension}, group::MlsGroup as OpenMlsGroup};
use prost::Message;
use thiserror::Error;

use xmtp_proto::xmtp::mls::message_contents::GroupMutableMetadataV1 as GroupMutableMetadataProto;

#[derive(Debug, Error)]
pub enum GroupMutableMetadataError {
#[error("serialization: {0}")]
Serialization(#[from] prost::EncodeError),
#[error("deserialization: {0}")]
Deserialization(#[from] prost::DecodeError),
#[error("missing extension")]
MissingExtension,
}

#[derive(Debug, Clone, PartialEq)]
pub struct GroupMutableMetadata {
pub group_name: String,
pub allow_list_account_addresses: Vec<String>,
}

impl GroupMutableMetadata {
pub fn new(
group_name: String,
allow_list_account_addresses: Vec<String>,
) -> Self {
Self {
group_name,
allow_list_account_addresses,
}
}

pub(crate) fn from_proto(proto: GroupMutableMetadataProto) -> Result<Self, GroupMutableMetadataError> {
Ok(Self::new(
proto.group_name.clone(),
proto.allow_list_account_addresses.clone(),
))
}

pub(crate) fn to_proto(&self) -> Result<GroupMutableMetadataProto, GroupMutableMetadataError> {
Ok(GroupMutableMetadataProto {
group_name: self.group_name.clone(),
allow_list_account_addresses: self.allow_list_account_addresses.clone(),
})
}
}

impl TryFrom<GroupMutableMetadata> for Vec<u8> {
type Error = GroupMutableMetadataError;

fn try_from(value: GroupMutableMetadata) -> Result<Self, Self::Error> {
let mut buf = Vec::new();
let proto_val = value.to_proto()?;
proto_val.encode(&mut buf)?;

Ok(buf)
}
}

impl TryFrom<&Vec<u8>> for GroupMutableMetadata {
type Error = GroupMutableMetadataError;

fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
let proto_val = GroupMutableMetadataProto::decode(value.as_slice())?;
Self::from_proto(proto_val)
}
}

impl TryFrom<GroupMutableMetadataProto> for GroupMutableMetadata {
type Error = GroupMutableMetadataError;

fn try_from(value: GroupMutableMetadataProto) -> Result<Self, Self::Error> {
Self::from_proto(value)
}
}

pub fn extract_group_mutable_metadata(group: &OpenMlsGroup) -> Result<GroupMutableMetadata, GroupMutableMetadataError> {
let extensions = group
.export_group_context()
.extensions();
for extension in extensions.iter() {
if let Extension::Unknown(0xff00, UnknownExtension(meta_data)) = extension {
return GroupMutableMetadata::try_from(meta_data);
}
}
Err(GroupMutableMetadataError::MissingExtension)
}

#[cfg(test)]
mod tests {

use super::*;

Check warning on line 93 in xmtp_mls/src/groups/group_mutable_metadata.rs

View workflow job for this annotation

GitHub Actions / Test

unused import: `super::*`
#[test]
fn test_preconfigured_mutable_metadata() {
// TODO add test here
}
}
101 changes: 92 additions & 9 deletions xmtp_mls/src/groups/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod group_metadata;
pub mod group_mutable_metadata;
mod group_permissions;
mod intents;
mod members;
Expand All @@ -8,7 +9,7 @@ pub mod validated_commit;

use intents::SendMessageIntentData;
use openmls::{
extensions::{Extension, Extensions, Metadata},
extensions::{Extension, Extensions, Metadata, UnknownExtension},
group::{MlsGroupCreateConfig, MlsGroupJoinConfig},
prelude::{
CredentialWithKey, CryptoConfig, Error as TlsCodecError, GroupId, MlsGroup as OpenMlsGroup,
Expand All @@ -22,15 +23,14 @@ use thiserror::Error;
use xmtp_cryptography::signature::is_valid_ed25519_public_key;
use xmtp_proto::{
api_client::XmtpMlsClient,
xmtp::mls::api::v1::{
xmtp::mls::{api::v1::{
group_message::{Version as GroupMessageVersion, V1 as GroupMessageV1},
GroupMessage,
},
xmtp::mls::message_contents::plaintext_envelope::{Content, V1},
xmtp::mls::message_contents::PlaintextEnvelope,
}, database::AccountAddresses, message_contents::{plaintext_envelope::{Content, V1}, GroupMutableMetadataV1, PlaintextEnvelope}},
};

use self::group_metadata::extract_group_metadata;
use self::{group_metadata::extract_group_metadata, group_mutable_metadata::{GroupMutableMetadata, GroupMutableMetadataError}, intents::UpdateMetadataIntentData};
use self::group_mutable_metadata::extract_group_mutable_metadata;
pub use self::group_permissions::PreconfiguredPolicies;
pub use self::intents::{AddressesOrInstallationIds, IntentError};
use self::{
Expand Down Expand Up @@ -110,6 +110,8 @@ pub enum GroupError {
CommitValidation(#[from] CommitValidationError),
#[error("Metadata error {0}")]
GroupMetadata(#[from] GroupMetadataError),
#[error("Mutable Metadata error {0}")]
GroupMutableMetadata(#[from] GroupMutableMetadataError),
#[error("Errors occurred during sync {0:?}")]
Sync(Vec<GroupError>),
#[error("Hpke error: {0}")]
Expand Down Expand Up @@ -189,7 +191,12 @@ where
.unwrap_or(PreconfiguredPolicies::default())
.to_policy_set(),
)?;
let group_config = build_group_config(protected_metadata)?;
// TODO: Add constant for default group name
let mutable_metadata = build_mutable_metadata_extension(
"New Group".to_string(),
vec![client.account_address().clone()],
)?;
let group_config = build_group_config(protected_metadata, mutable_metadata)?;

let mut mls_group = OpenMlsGroup::new(
&provider,
Expand Down Expand Up @@ -346,6 +353,27 @@ where
self.sync_until_intent_resolved(conn, intent.id).await
}

pub async fn update_group_metadata(
&self,
group_name: String,
) -> Result<(), GroupError> {
// TODO: enable mutable metadata allow list
let empty_account_addresses: AccountAddresses = AccountAddresses{
account_addresses: vec![]
};

let conn = &mut self.client.store.conn()?;
let intent_data: Vec<u8> =
UpdateMetadataIntentData::new(group_name, empty_account_addresses).to_bytes();
let intent = conn.insert_group_intent(NewGroupIntent::new(
IntentKind::MetadataUpdate,
self.group_id.clone(),
intent_data,
))?;

self.sync_until_intent_resolved(conn, intent.id).await
}

pub async fn add_members_by_installation_id(
&self,
installation_ids: Vec<Vec<u8>>,
Expand Down Expand Up @@ -419,6 +447,14 @@ where

Ok(extract_group_metadata(&mls_group)?)
}

pub fn mutable_metadata(&self) -> Result<GroupMutableMetadata, GroupError> {
let conn = &self.client.store.conn()?;
let provider = XmtpOpenMlsProvider::new(conn);
let mls_group = self.load_mls_group(&provider)?;

Ok(extract_group_mutable_metadata(&mls_group)?)
}
}

fn extract_message_v1(message: GroupMessage) -> Result<GroupMessageV1, MessageProcessingError> {
Expand Down Expand Up @@ -464,10 +500,28 @@ fn build_protected_metadata_extension(
Ok(Extension::ImmutableMetadata(protected_metadata))
}

fn build_mutable_metadata_extension(
group_name: String,
allow_list_account_addresses: Vec<String>,
) -> Result<Extension, GroupError> {

let mutable_metadata: GroupMutableMetadataV1 = GroupMutableMetadataV1 {
group_name,
allow_list_account_addresses,
};

let unknown_gc_extension = UnknownExtension(mutable_metadata.encode_to_vec());

// TODO: Where should the constant hex value live?
Ok(Extension::Unknown(0xff00, unknown_gc_extension))
}

fn build_group_config(
protected_metadata_extension: Extension,
mutable_metadata_extension: Extension
) -> Result<MlsGroupCreateConfig, GroupError> {
let extensions = Extensions::single(protected_metadata_extension);
let mut extensions = Extensions::single(protected_metadata_extension);
extensions.add(mutable_metadata_extension)?;

Ok(MlsGroupCreateConfig::builder()
.with_group_context_extensions(extensions)?
Expand All @@ -488,7 +542,7 @@ fn build_group_join_config() -> MlsGroupJoinConfig {

#[cfg(test)]
mod tests {
use openmls::prelude::Member;
use openmls::{group, prelude::Member};

Check warning on line 545 in xmtp_mls/src/groups/mod.rs

View workflow job for this annotation

GitHub Actions / Test

unused import: `group`
use prost::Message;
use xmtp_api_grpc::grpc_api_helper::Client as GrpcClient;
use xmtp_cryptography::utils::generate_local_wallet;
Expand Down Expand Up @@ -943,6 +997,35 @@ mod tests {
.is_err(),);
}

#[tokio::test]
async fn test_group_mutable_data() {
// TODO: Add check for updating group mutable metadata
let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await;
let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await;

Check warning on line 1004 in xmtp_mls/src/groups/mod.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `bola`
let charlie = ClientBuilder::new_test_client(&generate_local_wallet()).await;

Check warning on line 1005 in xmtp_mls/src/groups/mod.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `charlie`

let policies = Some(PreconfiguredPolicies::GroupCreatorIsAdmin);

let amal_group: MlsGroup<_> = amal.create_group(policies)
.unwrap();

amal_group.sync().await.unwrap();

let mut group_mutable_metadata = amal_group.mutable_metadata().unwrap();

Check warning on line 1014 in xmtp_mls/src/groups/mod.rs

View workflow job for this annotation

GitHub Actions / Test

variable does not need to be mutable
assert!(group_mutable_metadata.group_name.eq("New Group"));

// Update group name
// amal_group
// .update_group_metadata("New Group Name 1".to_string())
// .await
// .unwrap();

// amal_group.sync().await.unwrap();

// group_mutable_metadata = amal_group.mutable_metadata().unwrap();
// assert!(group_mutable_metadata.group_name.eq("New Group Name 1"));
}

#[tokio::test]
async fn test_max_limit_add() {
let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await;
Expand Down
10 changes: 7 additions & 3 deletions xmtp_mls/src/groups/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use openmls::{
credentials::BasicCredential,
framing::ProtocolMessage,
group::MergePendingCommitError,
messages::proposals::GroupContextExtensionProposal,

Check warning on line 8 in xmtp_mls/src/groups/sync.rs

View workflow job for this annotation

GitHub Actions / Test

unused import: `messages::proposals::GroupContextExtensionProposal`

Check warning on line 8 in xmtp_mls/src/groups/sync.rs

View workflow job for this annotation

GitHub Actions / Test

unused import: `messages::proposals::GroupContextExtensionProposal`

Check warning on line 8 in xmtp_mls/src/groups/sync.rs

View workflow job for this annotation

GitHub Actions / Test

unused import: `messages::proposals::GroupContextExtensionProposal`

Check warning on line 8 in xmtp_mls/src/groups/sync.rs

View workflow job for this annotation

GitHub Actions / workspace

unused import: `messages::proposals::GroupContextExtensionProposal`

warning: unused import: `messages::proposals::GroupContextExtensionProposal` --> xmtp_mls/src/groups/sync.rs:8:5 | 8 | messages::proposals::GroupContextExtensionProposal, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
prelude::{
tls_codec::{Deserialize, Serialize},
LeafNodeIndex, MlsGroup as OpenMlsGroup, MlsMessageBodyIn, MlsMessageIn, PrivateMessageIn,
ProcessedMessage, ProcessedMessageContent, Sender,
},
prelude_test::KeyPackage,
}, prelude_test::KeyPackage
};
use openmls_traits::OpenMlsProvider;
use prost::bytes::Bytes;
Expand All @@ -33,7 +33,7 @@ use xmtp_proto::{
use super::{
intents::{
AddMembersIntentData, AddressesOrInstallationIds, Installation, PostCommitAction,
RemoveMembersIntentData, SendMessageIntentData, SendWelcomesAction,
RemoveMembersIntentData, SendMessageIntentData, SendWelcomesAction, UpdateMetadataIntentData,
},
members::GroupMember,
GroupError, MlsGroup,
Expand Down Expand Up @@ -656,6 +656,10 @@ where
}
IntentKind::MetadataUpdate => {
// TODO: Not implemented
let intent_data = UpdateMetadataIntentData::from_bytes(intent.data.as_slice())?;
println!("Trying to process Update metadata intent data: {}", intent_data.group_name);



Ok((vec![], None))
}
Expand Down
Loading

0 comments on commit fef808e

Please sign in to comment.