Skip to content

Commit

Permalink
Added new Permissions Extension (#724)
Browse files Browse the repository at this point in the history
* Added new Permissions Extension

* fix bindings

* update TODO for follow up PR

* Update xmtp_mls/src/groups/group_mutable_metadata.rs

clean up admin list error checking

Co-authored-by: 37ng <[email protected]>

* Revert "Update xmtp_mls/src/groups/group_mutable_metadata.rs
"

This reverts commit 1b0cc38.

* fixed concise error checking

* Point gen_protos.sh back to main branch

* lint fix after merge

---------

Co-authored-by: cameronvoell <[email protected]>
Co-authored-by: 37ng <[email protected]>
  • Loading branch information
3 people authored May 15, 2024
1 parent e42406c commit bba18be
Show file tree
Hide file tree
Showing 17 changed files with 3,054 additions and 1,682 deletions.
2 changes: 2 additions & 0 deletions bindings_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub enum GenericError {
Signature(#[from] xmtp_cryptography::signature::SignatureError),
#[error("Group metadata: {0}")]
GroupMetadata(#[from] xmtp_mls::groups::group_metadata::GroupMetadataError),
#[error("Group permissions: {0}")]
GroupMutablePermissions(#[from] xmtp_mls::groups::group_permissions::GroupMutablePermissionsError),
#[error("Generic {err}")]
Generic { err: String },
}
Expand Down
19 changes: 15 additions & 4 deletions bindings_ffi/src/mls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use tokio::sync::oneshot::Sender;
use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient;
use xmtp_mls::groups::group_metadata::ConversationType;
use xmtp_mls::groups::group_metadata::GroupMetadata;
use xmtp_mls::groups::group_permissions::GroupMutablePermissions;
use xmtp_mls::groups::PreconfiguredPolicies;
use xmtp_mls::identity::v3::{IdentityStrategy, LegacyIdentity};
use xmtp_mls::{
Expand Down Expand Up @@ -184,8 +185,8 @@ pub enum GroupPermissions {
impl From<PreconfiguredPolicies> for GroupPermissions {
fn from(policy: PreconfiguredPolicies) -> Self {
match policy {
PreconfiguredPolicies::EveryoneIsAdmin => GroupPermissions::EveryoneIsAdmin,
PreconfiguredPolicies::GroupCreatorIsAdmin => GroupPermissions::GroupCreatorIsAdmin,
PreconfiguredPolicies::AllMembers => GroupPermissions::EveryoneIsAdmin,
PreconfiguredPolicies::AdminsOnly => GroupPermissions::GroupCreatorIsAdmin,
}
}
}
Expand All @@ -204,10 +205,10 @@ impl FfiConversations {

let group_permissions = match permissions {
Some(GroupPermissions::EveryoneIsAdmin) => {
Some(xmtp_mls::groups::PreconfiguredPolicies::EveryoneIsAdmin)
Some(xmtp_mls::groups::PreconfiguredPolicies::AllMembers)
}
Some(GroupPermissions::GroupCreatorIsAdmin) => {
Some(xmtp_mls::groups::PreconfiguredPolicies::GroupCreatorIsAdmin)
Some(xmtp_mls::groups::PreconfiguredPolicies::AdminsOnly)
}
_ => None,
};
Expand Down Expand Up @@ -662,6 +663,16 @@ impl FfiGroupMetadata {
ConversationType::Sync => "sync".to_string(),
}
}
}


#[derive(uniffi::Object)]
pub struct FfiGroupPermissions {
inner: Arc<GroupMutablePermissions>,
}

#[uniffi::export]
impl FfiGroupPermissions {

pub fn policy_type(&self) -> Result<GroupPermissions, GenericError> {
Ok(self.inner.preconfigured_policy()?.into())
Expand Down
6 changes: 2 additions & 4 deletions examples/cli/cli-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,9 @@ async fn main() {
}
Commands::CreateGroup { permissions } => {
let group_permissions = match permissions {
Permissions::EveryoneIsAdmin => {
xmtp_mls::groups::PreconfiguredPolicies::EveryoneIsAdmin
}
Permissions::EveryoneIsAdmin => xmtp_mls::groups::PreconfiguredPolicies::AllMembers,
Permissions::GroupCreatorIsAdmin => {
xmtp_mls::groups::PreconfiguredPolicies::GroupCreatorIsAdmin
xmtp_mls::groups::PreconfiguredPolicies::AdminsOnly
}
};
let client = create_client(&cli, IdentityStrategy::CachedOnly)
Expand Down
3 changes: 2 additions & 1 deletion examples/cli/serializable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ impl<'a> From<&'a MlsGroup> for SerializableGroup {
.collect::<Vec<String>>();

let metadata = group.metadata().expect("could not load metadata");
let permissions = group.permissions().expect("could not load permissions");

Self {
group_id,
members,
metadata: SerializableGroupMetadata {
creator_account_address: metadata.creator_account_address.clone(),
policy: metadata
policy: permissions
.preconfigured_policy()
.expect("could not get policy")
.to_string(),
Expand Down
1 change: 1 addition & 0 deletions xmtp_mls/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub const DELIMITER: char = '\x01';
/// | 0xff00 - 0xffff | Reserved for Private Use | N/A | N/A | RFC XXXX |
pub const MUTABLE_METADATA_EXTENSION_ID: u16 = 0xff00;
pub const GROUP_MEMBERSHIP_EXTENSION_ID: u16 = 0xff01;
pub const GROUP_PERMISSIONS_EXTENSION_ID: u16 = 0xff02;

pub const DEFAULT_GROUP_NAME: &str = "New Group";
pub const DEFAULT_GROUP_DESCRIPTION: &str = "New Group Description";
58 changes: 0 additions & 58 deletions xmtp_mls/src/groups/group_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,14 @@ use xmtp_proto::xmtp::mls::message_contents::{
ConversationType as ConversationTypeProto, GroupMetadataV1 as GroupMetadataProto,
};

use super::{
group_permissions::{PolicyError, PolicySet},
PreconfiguredPolicies,
};

#[derive(Debug, Error)]
pub enum GroupMetadataError {
#[error("serialization: {0}")]
Serialization(#[from] prost::EncodeError),
#[error("deserialization: {0}")]
Deserialization(#[from] prost::DecodeError),
#[error("policy error {0}")]
Policy(#[from] PolicyError),
#[error("invalid conversation type")]
InvalidConversationType,
#[error("missing policies")]
MissingPolicies,
#[error("missing extension")]
MissingExtension,
}
Expand All @@ -33,7 +24,6 @@ pub struct GroupMetadata {
// TODO: Remove this once transition is completed
pub creator_account_address: String,
pub creator_inbox_id: String,
pub policies: PolicySet,
}

impl GroupMetadata {
Expand All @@ -42,31 +32,19 @@ impl GroupMetadata {
// TODO: Remove this once transition is completed
creator_account_address: String,
creator_inbox_id: String,
policies: PolicySet,
) -> Self {
Self {
conversation_type,
creator_account_address,
creator_inbox_id,
policies,
}
}

pub fn preconfigured_policy(&self) -> Result<PreconfiguredPolicies, GroupMetadataError> {
Ok(PreconfiguredPolicies::from_policy_set(&self.policies)?)
}

pub(crate) fn from_proto(proto: GroupMetadataProto) -> Result<Self, GroupMetadataError> {
if proto.policies.is_none() {
return Err(GroupMetadataError::MissingPolicies);
}
let policies = proto.policies.unwrap();

Ok(Self::new(
proto.conversation_type.try_into()?,
proto.creator_account_address.clone(),
proto.creator_inbox_id.clone(),
PolicySet::from_proto(policies)?,
))
}

Expand All @@ -76,7 +54,6 @@ impl GroupMetadata {
conversation_type: conversation_type as i32,
creator_inbox_id: self.creator_inbox_id.clone(),
creator_account_address: self.creator_account_address.clone(),
policies: Some(self.policies.to_proto()?),
})
}
}
Expand Down Expand Up @@ -149,38 +126,3 @@ pub fn extract_group_metadata(group: &OpenMlsGroup) -> Result<GroupMetadata, Gro

extension.metadata().try_into()
}

#[cfg(test)]
mod tests {
use crate::groups::group_permissions::{
policy_everyone_is_admin, policy_group_creator_is_admin,
};

use super::*;
#[test]
fn test_preconfigured_policy() {
let account_address = "account_address";
let group_metadata = GroupMetadata::new(
ConversationType::Group,
account_address.to_string(),
"inbox_id".to_string(),
policy_everyone_is_admin(),
);
assert_eq!(
group_metadata.preconfigured_policy().unwrap(),
PreconfiguredPolicies::EveryoneIsAdmin
);

let group_metadata_creator_admin = GroupMetadata::new(
ConversationType::Group,
account_address.to_string(),
"inbox_id".to_string(),
policy_group_creator_is_admin(),
);

assert_eq!(
group_metadata_creator_admin.preconfigured_policy().unwrap(),
PreconfiguredPolicies::GroupCreatorIsAdmin
);
}
}
60 changes: 49 additions & 11 deletions xmtp_mls/src/groups/group_mutable_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use openmls::{
use prost::Message;
use thiserror::Error;

use xmtp_proto::xmtp::mls::message_contents::GroupMutableMetadataV1 as GroupMutableMetadataProto;
use xmtp_proto::xmtp::mls::message_contents::{
GroupMutableMetadataV1 as GroupMutableMetadataProto, Inboxes as InboxesProto,
};

use crate::configuration::{
DEFAULT_GROUP_DESCRIPTION, DEFAULT_GROUP_NAME, MUTABLE_METADATA_EXTENSION_ID,
Expand All @@ -27,6 +29,8 @@ pub enum GroupMutableMetadataError {
TooManyUpdates,
#[error("no changes in this update")]
NoUpdates,
#[error("metadata field is missing")]
MissingMetadataField,
}

// Fields should be added to supported_fields fn for Metadata Update Support
Expand Down Expand Up @@ -55,10 +59,24 @@ impl fmt::Display for MetadataField {
pub struct GroupMutableMetadata {
// Allow libxmtp to receive attributes from updated versions not yet captured in MetadataField
pub attributes: HashMap<String, String>,
pub admin_list: Vec<String>,
pub super_admin_list: Vec<String>,
}

impl Default for GroupMutableMetadata {
fn default() -> Self {
impl GroupMutableMetadata {
pub fn new(
attributes: HashMap<String, String>,
admin_list: Vec<String>,
super_admin_list: Vec<String>,
) -> Self {
Self {
attributes,
admin_list,
super_admin_list,
}
}

pub fn new_default(creator_account_address: String) -> Self {
let mut attributes = HashMap::new();
attributes.insert(
MetadataField::GroupName.to_string(),
Expand All @@ -68,13 +86,13 @@ impl Default for GroupMutableMetadata {
MetadataField::Description.to_string(),
DEFAULT_GROUP_DESCRIPTION.to_string(),
);
Self { attributes }
}
}

impl GroupMutableMetadata {
pub fn new(attributes: HashMap<String, String>) -> Self {
Self { attributes }
let admin_list = vec![creator_account_address.clone()];
let super_admin_list = vec![creator_account_address.clone()];
Self {
attributes,
admin_list,
super_admin_list,
}
}

// These fields will receive default permission policies for new groups
Expand All @@ -90,6 +108,12 @@ impl TryFrom<GroupMutableMetadata> for Vec<u8> {
let mut buf = Vec::new();
let proto_val = GroupMutableMetadataProto {
attributes: value.attributes.clone(),
admin_list: Some(InboxesProto {
inbox_ids: value.admin_list,
}),
super_admin_list: Some(InboxesProto {
inbox_ids: value.super_admin_list,
}),
};
proto_val.encode(&mut buf)?;

Expand All @@ -110,7 +134,21 @@ impl TryFrom<GroupMutableMetadataProto> for GroupMutableMetadata {
type Error = GroupMutableMetadataError;

fn try_from(value: GroupMutableMetadataProto) -> Result<Self, Self::Error> {
Ok(Self::new(value.attributes.clone()))
let admin_list = value
.admin_list
.ok_or_else(|| GroupMutableMetadataError::MissingMetadataField)?
.inbox_ids;

let super_admin_list = value
.super_admin_list
.ok_or_else(|| GroupMutableMetadataError::MissingMetadataField)?
.inbox_ids;

Ok(Self::new(
value.attributes.clone(),
admin_list,
super_admin_list,
))
}
}

Expand Down
Loading

0 comments on commit bba18be

Please sign in to comment.