Skip to content

Commit

Permalink
Merge pull request #434 from xmtp/cv/latest-libxmtp-permissions-descr…
Browse files Browse the repository at this point in the history
…iption-updates

Latest libxmtp - permissions and description field updates
  • Loading branch information
cameronvoell authored Jul 2, 2024
2 parents 86652bc + 1e5fcd5 commit 2fdc48b
Show file tree
Hide file tree
Showing 16 changed files with 773 additions and 91 deletions.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ repositories {
dependencies {
implementation project(':expo-modules-core')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
implementation "org.xmtp:android:0.13.9"
implementation "org.xmtp:android:0.14.2"
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.facebook.react:react-native:0.71.3'
implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1"
Expand Down
164 changes: 144 additions & 20 deletions android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import expo.modules.xmtpreactnativesdk.wrappers.DecryptedLocalAttachment
import expo.modules.xmtpreactnativesdk.wrappers.EncryptedLocalAttachment
import expo.modules.xmtpreactnativesdk.wrappers.GroupWrapper
import expo.modules.xmtpreactnativesdk.wrappers.MemberWrapper
import expo.modules.xmtpreactnativesdk.wrappers.PermissionPolicySetWrapper
import expo.modules.xmtpreactnativesdk.wrappers.PreparedLocalMessage
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -61,11 +62,13 @@ import org.xmtp.android.library.messages.getPublicKeyBundle
import org.xmtp.android.library.push.Service
import org.xmtp.android.library.push.XMTPPush
import org.xmtp.android.library.toHex
import org.xmtp.android.library.hexToByteArray
import org.xmtp.proto.keystore.api.v1.Keystore.TopicMap.TopicData
import org.xmtp.proto.message.api.v1.MessageApiOuterClass
import org.xmtp.proto.message.contents.Invitation.ConsentProofPayload
import org.xmtp.proto.message.contents.PrivateKeyOuterClass
import uniffi.xmtpv3.GroupPermissions
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.GroupPermissionPreconfiguration
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionOption
import java.io.File
import java.util.Date
import java.util.UUID
Expand Down Expand Up @@ -411,11 +414,14 @@ class XMTPModule : Module() {

//
// Client API
AsyncFunction("canMessage") { inboxId: String, peerAddress: String ->
logV("canMessage")
val client = clients[inboxId] ?: throw XMTPException("No client")
AsyncFunction("canMessage") Coroutine { inboxId: String, peerAddress: String ->
withContext(Dispatchers.IO) {
logV("canMessage")

val client = clients[inboxId] ?: throw XMTPException("No client")

client.canMessage(peerAddress)
client.canMessage(peerAddress)
}
}

AsyncFunction("canGroupMessage") Coroutine { inboxId: String, peerAddresses: List<String> ->
Expand All @@ -426,13 +432,15 @@ class XMTPModule : Module() {
}
}

AsyncFunction("staticCanMessage") { peerAddress: String, environment: String, appVersion: String? ->
try {
logV("staticCanMessage")
val options = ClientOptions(api = apiEnvironments(environment, appVersion))
Client.canMessage(peerAddress = peerAddress, options = options)
} catch (e: Exception) {
throw XMTPException("Failed to create client: ${e.message}")
AsyncFunction("staticCanMessage") Coroutine { peerAddress: String, environment: String, appVersion: String? ->
withContext(Dispatchers.IO) {
try {
logV("staticCanMessage")
val options = ClientOptions(api = apiEnvironments(environment, appVersion))
Client.canMessage(peerAddress = peerAddress, options = options)
} catch (e: Exception) {
throw XMTPException("Failed to create client: ${e.message}")
}
}
}

Expand Down Expand Up @@ -826,19 +834,20 @@ class XMTPModule : Module() {
ConversationWrapper.encode(client, conversation)
}
}
AsyncFunction("createGroup") Coroutine { inboxId: String, peerAddresses: List<String>, permission: String, groupName: String, groupImageUrlSquare: String ->
AsyncFunction("createGroup") Coroutine { inboxId: String, peerAddresses: List<String>, permission: String, groupName: String, groupImageUrlSquare: String, groupDescription: String ->
withContext(Dispatchers.IO) {
logV("createGroup")
val client = clients[inboxId] ?: throw XMTPException("No client")
val permissionLevel = when (permission) {
"admin_only" -> GroupPermissions.ADMIN_ONLY
else -> GroupPermissions.ALL_MEMBERS
"admin_only" -> GroupPermissionPreconfiguration.ADMIN_ONLY
else -> GroupPermissionPreconfiguration.ALL_MEMBERS
}
val group = client.conversations.newGroup(
peerAddresses,
permissionLevel,
groupName,
groupImageUrlSquare
groupImageUrlSquare,
groupDescription
)
GroupWrapper.encode(client, group)
}
Expand Down Expand Up @@ -959,6 +968,26 @@ class XMTPModule : Module() {
}
}

AsyncFunction("groupDescription") Coroutine { inboxId: String, id: String ->
withContext(Dispatchers.IO) {
logV("groupDescription")
val client = clients[inboxId] ?: throw XMTPException("No client")
val group = findGroup(inboxId, id)

group?.description
}
}

AsyncFunction("updateGroupDescription") Coroutine { inboxId: String, id: String, groupDescription: String ->
withContext(Dispatchers.IO) {
logV("updateGroupDescription")
val client = clients[inboxId] ?: throw XMTPException("No client")
val group = findGroup(inboxId, id)

group?.updateGroupDescription(groupDescription)
}
}

AsyncFunction("isGroupActive") Coroutine { inboxId: String, id: String ->
withContext(Dispatchers.IO) {
logV("isGroupActive")
Expand Down Expand Up @@ -1067,6 +1096,91 @@ class XMTPModule : Module() {
}
}

AsyncFunction("updateAddMemberPermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateAddMemberPermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateAddMemberPermission(getPermissionOption(newPermission))
}
}

AsyncFunction("updateRemoveMemberPermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateRemoveMemberPermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateRemoveMemberPermission(getPermissionOption(newPermission))
}
}

AsyncFunction("updateAddAdminPermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateAddAdminPermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateAddAdminPermission(getPermissionOption(newPermission))
}
}

AsyncFunction("updateRemoveAdminPermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateRemoveAdminPermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateRemoveAdminPermission(getPermissionOption(newPermission))
}
}

AsyncFunction("updateGroupNamePermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateGroupNamePermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateGroupNamePermission(getPermissionOption(newPermission))
}
}

AsyncFunction("updateGroupImageUrlSquarePermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateGroupImageUrlSquarePermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateGroupImageUrlSquarePermission(getPermissionOption(newPermission))
}
}

AsyncFunction("updateGroupDescriptionPermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateGroupDescriptionPermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateGroupDescriptionPermission(getPermissionOption(newPermission))
}
}

AsyncFunction("permissionPolicySet") Coroutine { inboxId: String, id: String ->
withContext(Dispatchers.IO) {
logV("groupImageUrlSquare")
val client = clients[inboxId] ?: throw XMTPException("No client")
val group = findGroup(inboxId, id)

val permissionPolicySet = group?.permissionPolicySet()
if (permissionPolicySet != null) {
PermissionPolicySetWrapper.encodeToJsonString(permissionPolicySet)
} else {
throw XMTPException("Permission policy set not found for group: $id")
}
}
}

AsyncFunction("processGroupMessage") Coroutine { inboxId: String, id: String, encryptedMessage: String ->
withContext(Dispatchers.IO) {
logV("processGroupMessage")
Expand Down Expand Up @@ -1325,34 +1439,44 @@ class XMTPModule : Module() {
AsyncFunction("allowGroups") Coroutine { inboxId: String, groupIds: List<String> ->
logV("allowGroups")
val client = clients[inboxId] ?: throw XMTPException("No client")
val groupDataIds = groupIds.mapNotNull { Hex.hexStringToByteArray(it) }
val groupDataIds = groupIds.map { Hex.hexStringToByteArray(it) }
client.contacts.allowGroups(groupDataIds)
}

AsyncFunction("denyGroups") Coroutine { inboxId: String, groupIds: List<String> ->
logV("denyGroups")
val client = clients[inboxId] ?: throw XMTPException("No client")
val groupDataIds = groupIds.mapNotNull { Hex.hexStringToByteArray(it) }
val groupDataIds = groupIds.map { Hex.hexStringToByteArray(it) }
client.contacts.denyGroups(groupDataIds)
}

AsyncFunction("isGroupAllowed") { inboxId: String, groupId: String ->
logV("isGroupAllowed")
val client = clients[inboxId] ?: throw XMTPException("No client")
client.contacts.isGroupAllowed(Hex.hexStringToByteArray(groupId))
client.contacts.isGroupAllowed(groupId.hexToByteArray())
}

AsyncFunction("isGroupDenied") { inboxId: String, groupId: String ->
logV("isGroupDenied")
val client = clients[inboxId] ?: throw XMTPException("No client")
client.contacts.isGroupDenied(Hex.hexStringToByteArray(groupId))
client.contacts.isGroupDenied(groupId.hexToByteArray())
}
}

//
// Helpers
//

private suspend fun getPermissionOption(permissionString: String): PermissionOption {
return when (permissionString) {
"allow" -> PermissionOption.Allow
"deny" -> PermissionOption.Deny
"admin" -> PermissionOption.Admin
"super_admin" -> PermissionOption.SuperAdmin
else -> throw XMTPException("Invalid permission option: $permissionString")
}
}

private suspend fun findConversation(
inboxId: String,
topic: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,26 @@ package expo.modules.xmtpreactnativesdk.wrappers

import com.google.gson.GsonBuilder
import org.xmtp.android.library.Client
import org.xmtp.android.library.Conversation
import org.xmtp.android.library.Group
import org.xmtp.android.library.codecs.Attachment
import org.xmtp.android.library.toHex
import uniffi.xmtpv3.GroupPermissions

class GroupWrapper {

companion object {
fun encodeToObj(client: Client, group: Group): Map<String, Any> {
val permissionString = when (group.permissionLevel()) {
GroupPermissions.ALL_MEMBERS -> "all_members"
GroupPermissions.ADMIN_ONLY -> "admin_only"
GroupPermissions.CUSTOM_POLICY -> "custom_policy"
}
val permissionPolicySet = PermissionPolicySetWrapper.encodeToJsonString(group.permissionPolicySet())
return mapOf(
"clientAddress" to client.address,
"id" to group.id.toHex(),
"createdAt" to group.createdAt.time,
"peerInboxIds" to group.peerInboxIds(),
"version" to "GROUP",
"topic" to group.topic,
"permissionLevel" to permissionString,
"creatorInboxId" to group.creatorInboxId(),
"name" to group.name,
"isActive" to group.isActive(),
"imageUrlSquare" to group.imageUrlSquare
"imageUrlSquare" to group.imageUrlSquare,
"description" to group.description
)
}

Expand All @@ -38,4 +31,4 @@ class GroupWrapper {
return gson.toJson(obj)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package expo.modules.xmtpreactnativesdk.wrappers

import com.google.gson.GsonBuilder
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionOption
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionPolicySet

class PermissionPolicySetWrapper {

companion object {
fun fromPermissionOption(permissionOption: PermissionOption): String {
return when (permissionOption) {
PermissionOption.Allow -> "allow"
PermissionOption.Deny -> "deny"
PermissionOption.Admin -> "admin"
PermissionOption.SuperAdmin -> "superAdmin"
PermissionOption.Unknown -> "unknown"
}
}
fun encodeToObj(policySet: PermissionPolicySet): Map<String, Any> {
return mapOf(
"addMemberPolicy" to fromPermissionOption(policySet.addMemberPolicy),
"removeMemberPolicy" to fromPermissionOption(policySet.removeMemberPolicy),
"addAdminPolicy" to fromPermissionOption(policySet.addAdminPolicy),
"removeAdminPolicy" to fromPermissionOption(policySet.removeAdminPolicy),
"updateGroupNamePolicy" to fromPermissionOption(policySet.updateGroupNamePolicy),
"updateGroupDescriptionPolicy" to fromPermissionOption(policySet.updateGroupDescriptionPolicy),
"updateGroupImagePolicy" to fromPermissionOption(policySet.updateGroupImagePolicy),
)
}

fun encodeToJsonString(policySet: PermissionPolicySet): String {
val gson = GsonBuilder().create()
val obj = encodeToObj(policySet)
return gson.toJson(obj)
}
}
}
14 changes: 7 additions & 7 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ PODS:
- hermes-engine/Pre-built (= 0.71.14)
- hermes-engine/Pre-built (0.71.14)
- libevent (2.1.12)
- LibXMTP (0.5.3-beta2)
- LibXMTP (0.5.4-beta1)
- Logging (1.0.0)
- MessagePacker (0.4.7)
- MMKV (1.3.5):
Expand Down Expand Up @@ -449,16 +449,16 @@ PODS:
- GenericJSON (~> 2.0)
- Logging (~> 1.0.0)
- secp256k1.swift (~> 0.1)
- XMTP (0.12.4):
- XMTP (0.13.2):
- Connect-Swift (= 0.12.0)
- GzipSwift
- LibXMTP (= 0.5.3-beta2)
- LibXMTP (= 0.5.4-beta1)
- web3.swift
- XMTPReactNative (0.1.0):
- ExpoModulesCore
- MessagePacker
- secp256k1.swift
- XMTP (= 0.12.4)
- XMTP (= 0.13.2)
- Yoga (1.14.0)

DEPENDENCIES:
Expand Down Expand Up @@ -711,7 +711,7 @@ SPEC CHECKSUMS:
GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa
hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
LibXMTP: c0f992e33c4ac95bdf2652f9429b3999890b6ab3
LibXMTP: f080197cea545a7daf3bc8476d97efc3b225a8d8
Logging: 9ef4ecb546ad3169398d5a723bc9bea1c46bef26
MessagePacker: ab2fe250e86ea7aedd1a9ee47a37083edd41fd02
MMKV: 506311d0494023c2f7e0b62cc1f31b7370fa3cfb
Expand Down Expand Up @@ -763,8 +763,8 @@ SPEC CHECKSUMS:
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959
XMTP: 7d69afe403538056efb6caf01db7248b01221c48
XMTPReactNative: 938a95995dcd9ddf7db3872ee69c59e59105cfaa
XMTP: 76ac90da19ba43afbde1382d57fbcdbdfe9491d8
XMTPReactNative: d3104af9a1504fb42b16c60888993d1d0516afae
Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9

PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2
Expand Down
Loading

0 comments on commit 2fdc48b

Please sign in to comment.