Skip to content

Commit

Permalink
Node bindings updates (#825)
Browse files Browse the repository at this point in the history
* Ensure lowercase address for inbox IDs

* Add permissions functions to groups

* Update test utils

* Updated version and changelog
  • Loading branch information
rygine authored Jun 6, 2024
1 parent be947aa commit 236902f
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 4 deletions.
6 changes: 6 additions & 0 deletions bindings_node/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @xmtp/mls-client-bindings-node

## 0.0.2

- Added inbox ID helpers
- Refactored identity strategy creation
- Added permissions functions to groups

## 0.0.1

Initial release
2 changes: 1 addition & 1 deletion bindings_node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xmtp/mls-client-bindings-node",
"version": "0.0.1",
"version": "0.0.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
Expand Down
3 changes: 2 additions & 1 deletion bindings_node/scripts/streamTest.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import process from "node:process";
import { AsyncStream } from "./AsyncStream.mjs";
import { initEcdsaClient } from "./utils.mjs";
import { initEcdsaClient, syncGroups } from "./utils.mjs";
import { wallets } from "./users.mjs";

const client1 = await initEcdsaClient(wallets[0]);
await syncGroups(client1);
Expand Down
14 changes: 13 additions & 1 deletion bindings_node/scripts/utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@ import { toBytes } from "viem";
import { join } from "node:path";
import process from "node:process";
import { TextEncoder } from "node:util";
import { createClient } from "../dist/index.js";
import {
createClient,
getInboxIdForAddress,
generateInboxId,
} from "../dist/index.js";

export const initEcdsaClient = async (wallet) => {
const dbPath = join(process.cwd(), `${wallet.account.address}.db3`);

const inboxId =
(await getInboxIdForAddress(
"http://localhost:5556",
false,
wallet.account.address
)) || generateInboxId(wallet.account.address);

const client = await createClient(
"http://localhost:5556",
false,
dbPath,
inboxId,
wallet.account.address
);

Expand Down
141 changes: 140 additions & 1 deletion bindings_node/src/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use xmtp_cryptography::signature::ed25519_public_key_to_address;
use xmtp_mls::groups::{
group_metadata::{ConversationType, GroupMetadata},
group_permissions::GroupMutablePermissions,
MlsGroup, PreconfiguredPolicies,
members::PermissionLevel,
MlsGroup, PreconfiguredPolicies, UpdateAdminListType,
};
use xmtp_proto::xmtp::mls::message_contents::EncodedContent;

Expand Down Expand Up @@ -70,11 +71,19 @@ impl NapiGroupMetadata {
}
}

#[napi]
pub enum NapiPermissionLevel {
Member,
Admin,
SuperAdmin,
}

#[napi]
pub struct NapiGroupMember {
pub inbox_id: String,
pub account_addresses: Vec<String>,
pub installation_ids: Vec<String>,
pub permission_level: NapiPermissionLevel,
}

#[napi]
Expand Down Expand Up @@ -231,12 +240,63 @@ impl NapiGroup {
.into_iter()
.map(|id| ed25519_public_key_to_address(id.as_slice()))
.collect(),
permission_level: match member.permission_level {
PermissionLevel::Member => NapiPermissionLevel::Member,
PermissionLevel::Admin => NapiPermissionLevel::Admin,
PermissionLevel::SuperAdmin => NapiPermissionLevel::SuperAdmin,
},
})
.collect();

Ok(members)
}

#[napi]
pub fn admin_list(&self) -> Result<Vec<String>> {
let group = MlsGroup::new(
self.inner_client.context().clone(),
self.group_id.clone(),
self.created_at_ns,
);

let admin_list = group
.admin_list()
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(admin_list)
}

#[napi]
pub fn super_admin_list(&self) -> Result<Vec<String>> {
let group = MlsGroup::new(
self.inner_client.context().clone(),
self.group_id.clone(),
self.created_at_ns,
);

let super_admin_list = group
.super_admin_list()
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(super_admin_list)
}

#[napi]
pub fn is_admin(&self, inbox_id: String) -> Result<bool> {
let admin_list = self
.admin_list()
.map_err(|e| Error::from_reason(format!("{}", e)))?;
Ok(admin_list.contains(&inbox_id))
}

#[napi]
pub fn is_super_admin(&self, inbox_id: String) -> Result<bool> {
let super_admin_list = self
.super_admin_list()
.map_err(|e| Error::from_reason(format!("{}", e)))?;
Ok(super_admin_list.contains(&inbox_id))
}

#[napi]
pub async fn add_members(&self, account_addresses: Vec<String>) -> Result<()> {
let group = MlsGroup::new(
Expand All @@ -253,6 +313,85 @@ impl NapiGroup {
Ok(())
}

#[napi]
pub async fn add_admin(&self, inbox_id: String) -> Result<()> {
let group = MlsGroup::new(
self.inner_client.context().clone(),
self.group_id.clone(),
self.created_at_ns,
);
group
.update_admin_list(&self.inner_client, UpdateAdminListType::Add, inbox_id)
.await
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(())
}

#[napi]
pub async fn remove_admin(&self, inbox_id: String) -> Result<()> {
let group = MlsGroup::new(
self.inner_client.context().clone(),
self.group_id.clone(),
self.created_at_ns,
);
group
.update_admin_list(&self.inner_client, UpdateAdminListType::Remove, inbox_id)
.await
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(())
}

#[napi]
pub async fn add_super_admin(&self, inbox_id: String) -> Result<()> {
let group = MlsGroup::new(
self.inner_client.context().clone(),
self.group_id.clone(),
self.created_at_ns,
);
group
.update_admin_list(&self.inner_client, UpdateAdminListType::AddSuper, inbox_id)
.await
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(())
}

#[napi]
pub async fn remove_super_admin(&self, inbox_id: String) -> Result<()> {
let group = MlsGroup::new(
self.inner_client.context().clone(),
self.group_id.clone(),
self.created_at_ns,
);
group
.update_admin_list(
&self.inner_client,
UpdateAdminListType::RemoveSuper,
inbox_id,
)
.await
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(())
}

#[napi]
pub fn group_permissions(&self) -> Result<NapiGroupPermissions> {
let group = MlsGroup::new(
self.inner_client.context().clone(),
self.group_id.clone(),
self.created_at_ns,
);

let permissions = group
.permissions()
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(NapiGroupPermissions { inner: permissions })
}

#[napi]
pub async fn add_members_by_inbox_id(&self, inbox_ids: Vec<String>) -> Result<()> {
let group = MlsGroup::new(
Expand Down
2 changes: 2 additions & 0 deletions bindings_node/src/mls_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub async fn get_inbox_id_for_address(
is_secure: bool,
account_address: String,
) -> Result<Option<String>> {
let account_address = account_address.to_lowercase();
let api_client = ApiClientWrapper::new(
TonicApiClient::create(host.clone(), is_secure)
.await
Expand All @@ -99,6 +100,7 @@ pub async fn get_inbox_id_for_address(

#[napi]
pub fn generate_inbox_id(account_address: String) -> String {
let account_address = account_address.to_lowercase();
// ensure that the nonce is always 1 for now since this will only be used for the
// create_client function above, which also has a hard-coded nonce of 1
xmtp_id_generate_inbox_id(&account_address, &1)
Expand Down

0 comments on commit 236902f

Please sign in to comment.