From e1d8e9042401b4e8cd3010bc7d7ed968d5bf2143 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 20:28:01 -0800 Subject: [PATCH 1/3] fix: add ability to sign with an installation key --- android/build.gradle | 2 +- .../modules/xmtpreactnativesdk/XMTPModule.kt | 24 +++++++++++++++--- example/ios/Podfile.lock | 14 +++++------ ios/XMTPModule.swift | 9 +++++++ ios/XMTPReactNative.podspec | 2 +- src/index.ts | 11 ++++++++ src/lib/Client.ts | 25 ++++++++++++++----- 7 files changed, 69 insertions(+), 18 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 6ebd92fa..d213de4a 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:3.0.5" + implementation "org.xmtp:android:3.0.6" 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 6d980b01..454c04c1 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -364,6 +364,15 @@ class XMTPModule : Module() { } } + AsyncFunction("signWithInstallationKey") Coroutine { inboxId: String, message: String -> + withContext(Dispatchers.IO) { + val client = clients[inboxId] ?: throw XMTPException("No client") + + val signature = client.signWithInstallationKey(message) + signature.map { it.toInt() and 0xFF } + } + } + AsyncFunction("canMessage") Coroutine { inboxId: String, peerAddresses: List -> withContext(Dispatchers.IO) { logV("canMessage") @@ -445,7 +454,11 @@ class XMTPModule : Module() { val params = ConversationParamsWrapper.conversationParamsFromJson(groupParams ?: "") val order = getConversationSortOrder(sortOrder ?: "") val consent = consentState?.let { getConsentState(it) } - val groups = client.conversations.listGroups(order = order, limit = limit, consentState = consent) + val groups = client.conversations.listGroups( + order = order, + limit = limit, + consentState = consent + ) groups.map { group -> GroupWrapper.encode(client, group, params) } @@ -459,7 +472,11 @@ class XMTPModule : Module() { val params = ConversationParamsWrapper.conversationParamsFromJson(groupParams ?: "") val order = getConversationSortOrder(sortOrder ?: "") val consent = consentState?.let { getConsentState(it) } - val dms = client.conversations.listDms(order = order, limit = limit, consentState = consent) + val dms = client.conversations.listDms( + order = order, + limit = limit, + consentState = consent + ) dms.map { dm -> DmWrapper.encode(client, dm, params) } @@ -474,7 +491,8 @@ class XMTPModule : Module() { ConversationParamsWrapper.conversationParamsFromJson(conversationParams ?: "") val order = getConversationSortOrder(sortOrder ?: "") val consent = consentState?.let { getConsentState(it) } - val conversations = client.conversations.list(order = order, limit = limit, consentState = consent) + val conversations = + client.conversations.list(order = order, limit = limit, consentState = consent) conversations.map { conversation -> ConversationWrapper.encode(client, conversation, params) } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 533c7ead..e7d7a21b 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 (3.0.1) + - LibXMTP (3.0.3) - Logging (1.0.0) - MessagePacker (0.4.7) - MMKV (2.0.0): @@ -449,16 +449,16 @@ PODS: - GenericJSON (~> 2.0) - Logging (~> 1.0.0) - secp256k1.swift (~> 0.1) - - XMTP (3.0.5): + - XMTP (3.0.6): - Connect-Swift (= 0.12.0) - GzipSwift - - LibXMTP (= 3.0.1) + - LibXMTP (= 3.0.3) - web3.swift - XMTPReactNative (0.1.0): - ExpoModulesCore - MessagePacker - secp256k1.swift - - XMTP (= 3.0.5) + - XMTP (= 3.0.6) - Yoga (1.14.0) DEPENDENCIES: @@ -711,7 +711,7 @@ SPEC CHECKSUMS: GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - LibXMTP: b23a18d05d458fee72f0a96a114b1eb1e6d77d3b + LibXMTP: 948d39cf5b978adaa7d0f6ea5c6c0995a0b9e63f Logging: 9ef4ecb546ad3169398d5a723bc9bea1c46bef26 MessagePacker: ab2fe250e86ea7aedd1a9ee47a37083edd41fd02 MMKV: f7d1d5945c8765f97f39c3d121f353d46735d801 @@ -763,8 +763,8 @@ SPEC CHECKSUMS: secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634 SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1 web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959 - XMTP: 7b9105a3549427a294fb991c5892ebec73d2388d - XMTPReactNative: 0862a746eaddb7d643ad4cbdc2727d02863d9a18 + XMTP: 48d0c71ef732ac4d79c2942902a132bf71661029 + XMTPReactNative: 406f92e777c9d2891404956309d926e7b2f25c1c Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9 PODFILE CHECKSUM: 0e6fe50018f34e575d38dc6a1fdf1f99c9596cdd diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index fdcfa1f9..b75a0981 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -299,6 +299,15 @@ public class XMTPModule: Module { AsyncFunction("dropClient") { (inboxId: String) in await clientsManager.dropClient(key: inboxId) } + + AsyncFunction("signWithInstallationKey") { (inboxId: String, message: String) -> [UInt8] in + guard let client = await clientsManager.getClient(key: inboxId) + else { + throw Error.noClient + } + let signature = try client.signWithInstallationKey(message: message) + return [UInt8](signature) + } AsyncFunction("canMessage") { (inboxId: String, peerAddresses: [String]) -> [String: Bool] in diff --git a/ios/XMTPReactNative.podspec b/ios/XMTPReactNative.podspec index d0b93865..511f947e 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", "= 3.0.5" + s.dependency "XMTP", "= 3.0.6" end diff --git a/src/index.ts b/src/index.ts index 25e48c9f..33a4ba78 100644 --- a/src/index.ts +++ b/src/index.ts @@ -190,6 +190,17 @@ export async function dropClient(inboxId: InboxId) { return await XMTPModule.dropClient(inboxId) } +export async function signWithInstallationKey( + inboxId: InboxId, + message: string +): Promise { + const signatureArray = await XMTPModule.signWithInstallationKey( + inboxId, + message + ) + return new Uint8Array(signatureArray) +} + export async function canMessage( inboxId: InboxId, peerAddresses: Address[] diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 6f9ed29e..69a267dc 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -17,11 +17,13 @@ import * as XMTPModule from '../index' declare const Buffer -export type GetMessageContentTypeFromClient = - C extends Client ? T : never +export type GetMessageContentTypeFromClient = C extends Client + ? T + : never -export type ExtractDecodedType = - C extends XMTPModule.ContentCodec ? T : never +export type ExtractDecodedType = C extends XMTPModule.ContentCodec + ? T + : never export type InboxId = string & { readonly brand: unique symbol } export type Address = string @@ -316,6 +318,10 @@ export class Client< this.codecRegistry[id] = contentCodec } + async signWithInstallationKey(message: string): Promise { + return XMTPModule.signWithInstallationKey(this.inboxId, message) + } + /** * Find the Address associated with this address * @@ -409,8 +415,15 @@ export class Client< * @param {boolean} refreshFromNetwork - If you want to refresh the current state the inbox from the network or not. * @returns {Promise} A Promise resolving to a list of InboxState. */ - async inboxStates(refreshFromNetwork: boolean, inboxIds: InboxId[]): Promise { - return await XMTPModule.getInboxStates(this.inboxId, refreshFromNetwork, inboxIds) + async inboxStates( + refreshFromNetwork: boolean, + inboxIds: InboxId[] + ): Promise { + return await XMTPModule.getInboxStates( + this.inboxId, + refreshFromNetwork, + inboxIds + ) } /** From a43ed6be0938ea480ef37585305845e9e22e3c98 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 20:29:35 -0800 Subject: [PATCH 2/3] reformat ios --- ios/XMTPModule.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index b75a0981..8d2dfa2c 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -299,8 +299,9 @@ public class XMTPModule: Module { AsyncFunction("dropClient") { (inboxId: String) in await clientsManager.dropClient(key: inboxId) } - - AsyncFunction("signWithInstallationKey") { (inboxId: String, message: String) -> [UInt8] in + + AsyncFunction("signWithInstallationKey") { + (inboxId: String, message: String) -> [UInt8] in guard let client = await clientsManager.getClient(key: inboxId) else { throw Error.noClient From 4a79d7d75dc2358c2f10fd1f1cf340ff63ac9792 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 20:33:55 -0800 Subject: [PATCH 3/3] add a test --- example/src/tests/clientTests.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/example/src/tests/clientTests.ts b/example/src/tests/clientTests.ts index d916ef77..dba0cbb7 100644 --- a/example/src/tests/clientTests.ts +++ b/example/src/tests/clientTests.ts @@ -34,6 +34,18 @@ test('can make a client', async () => { return true }) +test('can sign with installation key', async () => { + const [client] = await createClients(1) + + const signature = await client.signWithInstallationKey('A digest message') + + assert( + signature !== undefined && signature.length > 0, + `Signature should not be empty but was: ${signature}` + ) + return true +}) + test('can revoke all other installations', async () => { const keyBytes = new Uint8Array([ 233, 120, 198, 96, 154, 65, 132, 17, 132, 96, 250, 40, 103, 35, 125, 64,