Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new Permissions Extension #724

Merged
merged 10 commits into from
May 15, 2024
2 changes: 2 additions & 0 deletions bindings_ffi/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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 @@ -651,6 +652,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
2 changes: 1 addition & 1 deletion dev/gen_protos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ if ! cargo install --list | grep "protoc-gen-prost-crate" > /dev/null; then
fi
fi

if ! buf generate https://github.com/xmtp/proto.git#branch=main,subdir=proto; then
if ! buf generate https://github.com/xmtp/proto.git#branch=cv/policy-set-mutable,subdir=proto; then
neekolas marked this conversation as resolved.
Show resolved Hide resolved
echo "Failed to generate protobuf definitions"
exit 1
fi
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 @@ -34,13 +34,14 @@ impl<A: XmtpMlsClient + XmtpIdentityClient> From<&MlsGroup<'_, A>> for Serializa
.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
);
}
}
66 changes: 55 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,27 @@ impl TryFrom<GroupMutableMetadataProto> for GroupMutableMetadata {
type Error = GroupMutableMetadataError;

fn try_from(value: GroupMutableMetadataProto) -> Result<Self, Self::Error> {
Ok(Self::new(value.attributes.clone()))
#[allow(unused_mut)]
let mut admin_list: Vec<String>;
#[allow(unused_mut)]
let mut super_admin_list: Vec<String>;
match value.admin_list {
Some(inboxes) => {
admin_list = inboxes.inbox_ids;
}
None => return Err(GroupMutableMetadataError::MissingMetadataField),
}
match value.super_admin_list {
Some(inboxes) => {
super_admin_list = inboxes.inbox_ids;
}
None => return Err(GroupMutableMetadataError::MissingMetadataField),
}
Ok(Self::new(
value.attributes.clone(),
admin_list,
super_admin_list,
))
cameronvoell marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
Loading
Loading