diff --git a/android/build.gradle b/android/build.gradle index 15baf9138..df06a4007 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -98,7 +98,7 @@ repositories { dependencies { implementation project(':expo-modules-core') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}" - implementation "org.xmtp:android:0.12.0" + implementation "org.xmtp:android:0.12.1" 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" diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 91affb17b..c778655b9 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -1179,6 +1179,34 @@ class XMTPModule : Module() { } } + AsyncFunction("isInboxAllowed") { clientAddress: String, inboxId: String -> + logV("isInboxIdAllowed") + val client = clients[clientAddress] ?: throw XMTPException("No client") + client.contacts.isInboxAllowed(inboxId) + } + + AsyncFunction("isInboxDenied") { clientAddress: String, inboxId: String -> + logV("isInboxIdDenied") + val client = clients[clientAddress] ?: throw XMTPException("No client") + client.contacts.isInboxDenied(inboxId) + } + + AsyncFunction("denyInboxes") Coroutine { clientAddress: String, inboxIds: List -> + withContext(Dispatchers.IO) { + logV("denyInboxIds") + val client = clients[clientAddress] ?: throw XMTPException("No client") + client.contacts.denyInboxes(inboxIds) + } + } + + AsyncFunction("allowInboxes") Coroutine { clientAddress: String, inboxIds: List -> + withContext(Dispatchers.IO) { + logV("allowInboxIds") + val client = clients[clientAddress] ?: throw XMTPException("No client") + client.contacts.allowInboxes(inboxIds) + } + } + AsyncFunction("refreshConsentList") Coroutine { clientAddress: String -> withContext(Dispatchers.IO) { val client = clients[clientAddress] ?: throw XMTPException("No client") @@ -1222,14 +1250,14 @@ class XMTPModule : Module() { logV("allowGroups") val client = clients[clientAddress] ?: throw XMTPException("No client") val groupDataIds = groupIds.mapNotNull { Hex.hexStringToByteArray(it) } - client.contacts.allowGroup(groupDataIds) + client.contacts.allowGroups(groupDataIds) } AsyncFunction("denyGroups") Coroutine { clientAddress: String, groupIds: List -> logV("denyGroups") val client = clients[clientAddress] ?: throw XMTPException("No client") val groupDataIds = groupIds.mapNotNull { Hex.hexStringToByteArray(it) } - client.contacts.denyGroup(groupDataIds) + client.contacts.denyGroups(groupDataIds) } AsyncFunction("isGroupAllowed") { clientAddress: String, groupId: String -> diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 64e25a2a5..1e9fe0656 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -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.0-beta1) + - LibXMTP (0.5.0-beta2) - Logging (1.0.0) - MessagePacker (0.4.7) - MMKV (1.3.5): @@ -449,16 +449,16 @@ PODS: - GenericJSON (~> 2.0) - Logging (~> 1.0.0) - secp256k1.swift (~> 0.1) - - XMTP (0.11.0): + - XMTP (0.11.1): - Connect-Swift (= 0.12.0) - GzipSwift - - LibXMTP (= 0.5.0-beta1) + - LibXMTP (= 0.5.0-beta2) - web3.swift - XMTPReactNative (0.1.0): - ExpoModulesCore - MessagePacker - secp256k1.swift - - XMTP (= 0.11.0) + - XMTP (= 0.11.1) - Yoga (1.14.0) DEPENDENCIES: @@ -711,7 +711,7 @@ SPEC CHECKSUMS: GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - LibXMTP: 38800678de153b444c5a9b41a991080ee33e11ed + LibXMTP: 0a2e98cc3b101e53538c54061633e6587dc861bf Logging: 9ef4ecb546ad3169398d5a723bc9bea1c46bef26 MessagePacker: ab2fe250e86ea7aedd1a9ee47a37083edd41fd02 MMKV: 506311d0494023c2f7e0b62cc1f31b7370fa3cfb @@ -763,10 +763,10 @@ SPEC CHECKSUMS: secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634 SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1 web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959 - XMTP: 2fb42dccbf89949175e99309f337ec11d828b989 - XMTPReactNative: 53915a0488e11be25777aa0b96d7091fa3c3c05b + XMTP: b2145642aae614c82b8115d479442f58513139b6 + XMTPReactNative: 009e2c8fa77df1210aa595b06b0ec46feeff3be6 Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9 PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2 -COCOAPODS: 1.15.2 +COCOAPODS: 1.14.2 diff --git a/example/src/tests/groupTests.ts b/example/src/tests/groupTests.ts index b3a0e28df..1620bab3d 100644 --- a/example/src/tests/groupTests.ts +++ b/example/src/tests/groupTests.ts @@ -519,7 +519,9 @@ test('can remove members from a group', async () => { await alixGroup.sync() const alixGroupMembers = await alixGroup.memberInboxIds() if (alixGroupMembers.length !== 2) { - throw new Error('num group members should be 2') + throw new Error( + 'num group members should be 2 but was' + alixGroupMembers.length + ) } await caroGroups[0].sync() @@ -528,8 +530,11 @@ test('can remove members from a group', async () => { } const caroGroupMembers = await caroGroups[0].memberInboxIds() - if (caroGroupMembers.length !== 2) { - throw new Error('num group members should be 2') + // should be 3 since they wont get new updates to the group after being removed + if (caroGroupMembers.length !== 3) { + throw new Error( + 'num group members should be 3 but was' + caroGroupMembers.length + ) } return true @@ -1224,8 +1229,9 @@ test('creating a group should allow group', async () => { const group = await alix.conversations.newGroup([bo.address]) const consent = await alix.contacts.isGroupAllowed(group.id) + const groupConsent = await group.isAllowed() - if (!consent) { + if (!consent || !groupConsent) { throw Error('Group should be allowed') } @@ -1235,6 +1241,12 @@ test('creating a group should allow group', async () => { `the message should have a consent state of allowed but was ${state}` ) + const consentList = await alix.contacts.consentList() + assert( + consentList[0].permissionType === 'allowed', + `the message should have a consent state of allowed but was ${consentList[0].permissionType}` + ) + return true }) @@ -1262,8 +1274,11 @@ test('can deny a group', async () => { throw Error('Group should be unknown') } await bo.contacts.denyGroups([alixGroup.id]) + await bo.conversations.syncGroups() + const boGroups = await bo.conversations.listGroups() const isDenied = await bo.contacts.isGroupDenied(alixGroup.id) - if (!isDenied) { + const isGroupDenied = await boGroups[0].isDenied() + if (!isDenied || !isGroupDenied) { throw Error('Group should be denied') } await bo.contacts.allowGroups([alixGroup.id]) @@ -1275,6 +1290,32 @@ test('can deny a group', async () => { return true }) +test('can allow and deny a inbox id', async () => { + const [alix, bo] = await createClients(2) + const startConsent = await bo.contacts.isInboxAllowed(alix.inboxId) + if (startConsent) { + throw Error('inbox id should be unknown') + } + await bo.contacts.denyInboxes([alix.inboxId]) + const isDenied = await bo.contacts.isInboxDenied(alix.inboxId) + if (!isDenied) { + throw Error('inbox id should be denied') + } + await bo.contacts.allowInboxes([alix.inboxId]) + const isAllowed = await bo.contacts.isInboxAllowed(alix.inboxId) + if (!isAllowed) { + throw Error('inbox id should be allowed') + } + + const consentList = await bo.contacts.consentList() + assert( + consentList[0].entryType === 'inbox_id', + `the message should have a type of inbox_id but was ${consentList[0].entryType}` + ) + + return true +}) + test('can check if group is allowed', async () => { const [alix, bo] = await createClients(2) const alixGroup = await alix.conversations.newGroup([bo.address]) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index c35ad5755..98ff9645c 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -1064,6 +1064,34 @@ public class XMTPModule: Module { } try await client.contacts.allow(addresses: addresses) } + + AsyncFunction("isInboxAllowed") { (clientAddress: String, inboxId: String) -> Bool in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + return await client.contacts.isInboxAllowed(inboxId: inboxId) + } + + AsyncFunction("isInboxDenied") { (clientAddress: String, inboxId: String) -> Bool in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + return await client.contacts.isInboxDenied(inboxId: inboxId) + } + + AsyncFunction("denyInboxes") { (clientAddress: String, inboxIds: [String]) in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + try await client.contacts.denyInboxes(inboxIds: inboxIds) + } + + AsyncFunction("allowInboxes") { (clientAddress: String, inboxIds: [String]) in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + try await client.contacts.allowInboxes(inboxIds: inboxIds) + } AsyncFunction("refreshConsentList") { (clientAddress: String) -> [String] in guard let client = await clientsManager.getClient(key: clientAddress) else { @@ -1120,7 +1148,7 @@ public class XMTPModule: Module { throw Error.noClient } let groupDataIds = groupIds.compactMap { Data(hex: $0) } - try await client.contacts.allowGroup(groupIds: groupDataIds) + try await client.contacts.allowGroups(groupIds: groupDataIds) } AsyncFunction("denyGroups") { (clientAddress: String, groupIds: [String]) in @@ -1128,7 +1156,7 @@ public class XMTPModule: Module { throw Error.noClient } let groupDataIds = groupIds.compactMap { Data(hex: $0) } - try await client.contacts.denyGroup(groupIds: groupDataIds) + try await client.contacts.denyGroups(groupIds: groupDataIds) } AsyncFunction("isGroupAllowed") { (clientAddress: String, groupId: String) -> Bool in diff --git a/ios/XMTPReactNative.podspec b/ios/XMTPReactNative.podspec index ecfcde58d..8639ba63c 100644 --- a/ios/XMTPReactNative.podspec +++ b/ios/XMTPReactNative.podspec @@ -26,5 +26,5 @@ Pod::Spec.new do |s| s.source_files = "**/*.{h,m,swift}" s.dependency 'secp256k1.swift' s.dependency "MessagePacker" - s.dependency "XMTP", "= 0.11.0" + s.dependency "XMTP", "= 0.11.1" end diff --git a/src/index.ts b/src/index.ts index ae78a91bd..db28d689f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -822,6 +822,35 @@ export async function isGroupDenied( return XMTPModule.isGroupDenied(clientAddress, groupId) } +export async function allowInboxes( + clientAddress: string, + inboxIds: string[] +): Promise { + return XMTPModule.allowInboxes(clientAddress, inboxIds) +} + +export async function denyInboxes( + clientAddress: string, + inboxIds: string[] +): Promise { + return XMTPModule.denyInboxes(clientAddress, inboxIds) +} + +export async function isInboxAllowed( + clientAddress: string, + inboxId: string +): Promise { + return XMTPModule.isInboxAllowed(clientAddress, inboxId) +} + +export async function isInboxDenied( + clientAddress: string, + inboxId: string +): Promise { + return XMTPModule.isInboxDenied(clientAddress, inboxId) +} + + export async function processGroupMessage< ContentTypes extends DefaultContentTypes = DefaultContentTypes, >( diff --git a/src/lib/ConsentListEntry.ts b/src/lib/ConsentListEntry.ts index 9adb1392c..b22e0f5eb 100644 --- a/src/lib/ConsentListEntry.ts +++ b/src/lib/ConsentListEntry.ts @@ -1,6 +1,6 @@ export type ConsentState = 'allowed' | 'denied' | 'unknown' -export type ConsentListEntryType = 'address' +export type ConsentListEntryType = 'address' | 'group_id' | 'inbox_id' export class ConsentListEntry { value: string diff --git a/src/lib/Contacts.ts b/src/lib/Contacts.ts index b8f51e0ed..9dc9ee202 100644 --- a/src/lib/Contacts.ts +++ b/src/lib/Contacts.ts @@ -57,4 +57,20 @@ export default class Contacts { async isGroupDenied(groupId: string): Promise { return await XMTPModule.isGroupDenied(this.client.address, groupId) } + + async allowInboxes(inboxIds: string[]): Promise { + return await XMTPModule.allowInboxes(this.client.address, inboxIds) + } + + async denyInboxes(inboxIds: string[]): Promise { + return await XMTPModule.denyInboxes(this.client.address, inboxIds) + } + + async isInboxAllowed(inboxId: string): Promise { + return await XMTPModule.isInboxAllowed(this.client.address, inboxId) + } + + async isInboxDenied(inboxId: string): Promise { + return await XMTPModule.isInboxDenied(this.client.address, inboxId) + } } diff --git a/src/lib/Group.ts b/src/lib/Group.ts index aff2ead89..1870871af 100644 --- a/src/lib/Group.ts +++ b/src/lib/Group.ts @@ -287,4 +287,12 @@ export class Group< async consentState(): Promise<'allowed' | 'denied' | 'unknown'> { return await XMTP.groupConsentState(this.clientAddress, this.id) } + + async isAllowed(): Promise { + return await XMTP.isGroupAllowed(this.client.address, this.id) + } + + async isDenied(): Promise { + return await XMTP.isGroupDenied(this.client.address, this.id) + } }