From 5314987dc80403ffe5880817893872a04974e025 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 10:42:43 -0800 Subject: [PATCH 01/14] first pass at exposing a sign function --- .../java/expo/modules/xmtpreactnativesdk/XMTPModule.kt | 7 +++++++ src/index.ts | 5 +++++ src/lib/Client.ts | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 4e79d8979..e23d3ff2e 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -224,6 +224,13 @@ class XMTPModule : Module() { } } + AsyncFunction("sign") { message: List -> + logV("exportKeyBundle") + val client = clients[clientAddress] ?: throw XMTPException("No client") + Base64.encodeToString(client.privateKeyBundle.toByteArray(), NO_WRAP) + } + + AsyncFunction("exportKeyBundle") { clientAddress: String -> logV("exportKeyBundle") val client = clients[clientAddress] ?: throw XMTPException("No client") diff --git a/src/index.ts b/src/index.ts index b2039c9ef..5f2fcfcd2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -76,6 +76,11 @@ export async function createFromKeyBundle( ) } +export async function sign(message: Uint8Array): Promise { + const signatureArray = await XMTPModule.sign(Array.from(message)) + return new Uint8Array(signatureArray) +} + export async function exportKeyBundle(clientAddress: string): Promise { return await XMTPModule.exportKeyBundle(clientAddress) } diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 4dab22ebd..c746d3f0b 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -302,6 +302,10 @@ export class Client { this.codecRegistry[id] = contentCodec } + async sign(message: Uint8Array): Promise { + return XMTPModule.sign(message) + } + /** * Exports the key bundle associated with the current XMTP address. * From 4204be5844ef98b0baf878040238f43669dafca2 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 10:51:04 -0800 Subject: [PATCH 02/14] try and get the android side tracking --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index e23d3ff2e..69263011e 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.suspendCancellableCoroutine import org.json.JSONObject import org.xmtp.android.library.Client @@ -225,9 +226,22 @@ class XMTPModule : Module() { } AsyncFunction("sign") { message: List -> - logV("exportKeyBundle") + logV("sign") val client = clients[clientAddress] ?: throw XMTPException("No client") - Base64.encodeToString(client.privateKeyBundle.toByteArray(), NO_WRAP) + val messageBytes = + message.foldIndexed(ByteArray(message.size)) { i, a, v -> + a.apply { + set( + i, + v.toByte() + ) + } + } + client.privateKeyBundleV1.identityKey + val signature = runBlocking { + PrivateKeyBuilder(identity).sign(messageBytes) + } + signature.toByteArray().map { it.toInt() and 0xFF } } From 9e0736590625dbc3cc8c1e24253f8e81145b8b58 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 10:55:10 -0800 Subject: [PATCH 03/14] require a client --- .../java/expo/modules/xmtpreactnativesdk/XMTPModule.kt | 5 ++--- src/index.ts | 10 ++++++++-- src/lib/Client.ts | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 69263011e..ff246650f 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -225,7 +225,7 @@ class XMTPModule : Module() { } } - AsyncFunction("sign") { message: List -> + AsyncFunction("sign") { clientAddress: String, message: List -> logV("sign") val client = clients[clientAddress] ?: throw XMTPException("No client") val messageBytes = @@ -237,9 +237,8 @@ class XMTPModule : Module() { ) } } - client.privateKeyBundleV1.identityKey val signature = runBlocking { - PrivateKeyBuilder(identity).sign(messageBytes) + PrivateKeyBuilder(client.privateKeyBundleV1.identityKey).sign(messageBytes) } signature.toByteArray().map { it.toInt() and 0xFF } } diff --git a/src/index.ts b/src/index.ts index 5f2fcfcd2..bb9e3bb1e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -76,8 +76,14 @@ export async function createFromKeyBundle( ) } -export async function sign(message: Uint8Array): Promise { - const signatureArray = await XMTPModule.sign(Array.from(message)) +export async function sign( + clientAddress: string, + message: Uint8Array +): Promise { + const signatureArray = await XMTPModule.sign( + clientAddress, + Array.from(message) + ) return new Uint8Array(signatureArray) } diff --git a/src/lib/Client.ts b/src/lib/Client.ts index c746d3f0b..3547e900e 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -303,7 +303,7 @@ export class Client { } async sign(message: Uint8Array): Promise { - return XMTPModule.sign(message) + return XMTPModule.sign(this.address, message) } /** From 1d138f26c1fe8ee68f3c3bd0f5560ca09aa1a8ed Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 20:05:35 -0800 Subject: [PATCH 04/14] add key types --- .../expo/modules/xmtpreactnativesdk/XMTPModule.kt | 14 ++++++++++---- src/index.ts | 8 ++++++-- src/lib/Client.ts | 14 ++++++++++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index ff246650f..77b1ce6df 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -225,11 +225,11 @@ class XMTPModule : Module() { } } - AsyncFunction("sign") { clientAddress: String, message: List -> + AsyncFunction("sign") { clientAddress: String, digest: List, keyType: String, preKeyIndex: Int -> logV("sign") val client = clients[clientAddress] ?: throw XMTPException("No client") - val messageBytes = - message.foldIndexed(ByteArray(message.size)) { i, a, v -> + val digestBytes = + digest.foldIndexed(ByteArray(digest.size)) { i, a, v -> a.apply { set( i, @@ -237,8 +237,14 @@ class XMTPModule : Module() { ) } } + val privateKeyBundle = client.privateKeyBundleV1 + val key = if (keyType == "prekey") { + privateKeyBundle.preKeysList[preKeyIndex] + } else { + privateKeyBundle.identityKey + } val signature = runBlocking { - PrivateKeyBuilder(client.privateKeyBundleV1.identityKey).sign(messageBytes) + PrivateKeyBuilder(key).sign(digestBytes) } signature.toByteArray().map { it.toInt() and 0xFF } } diff --git a/src/index.ts b/src/index.ts index bb9e3bb1e..f2d51c358 100644 --- a/src/index.ts +++ b/src/index.ts @@ -78,11 +78,15 @@ export async function createFromKeyBundle( export async function sign( clientAddress: string, - message: Uint8Array + digest: Uint8Array, + keyType: string, + preKeyIndex?: number | 0 ): Promise { const signatureArray = await XMTPModule.sign( clientAddress, - Array.from(message) + Array.from(digest), + keyType, + preKeyIndex ) return new Uint8Array(signatureArray) } diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 3547e900e..efa0c63de 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -302,8 +302,13 @@ export class Client { this.codecRegistry[id] = contentCodec } - async sign(message: Uint8Array): Promise { - return XMTPModule.sign(this.address, message) + async sign(digest: Uint8Array, keyType: KeyType): Promise { + return XMTPModule.sign( + this.address, + digest, + keyType.kind, + keyType.prekeyIndex + ) } /** @@ -412,6 +417,11 @@ export type NetworkOptions = { appVersion?: string } +export type KeyType = { + kind: 'identity' | 'prekey' + prekeyIndex?: number +} + export type CallbackOptions = { preCreateIdentityCallback?: () => Promise | void preEnableIdentityCallback?: () => Promise | void From be736c6f353004eca909fc04537fd65ca522eec1 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 20:14:37 -0800 Subject: [PATCH 05/14] add export for public key --- .../java/expo/modules/xmtpreactnativesdk/XMTPModule.kt | 5 +++++ src/index.ts | 8 ++++++++ src/lib/Client.ts | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 77b1ce6df..c2c92ac61 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -249,6 +249,11 @@ class XMTPModule : Module() { signature.toByteArray().map { it.toInt() and 0xFF } } + AsyncFunction("exportPublicKeyBundle") { clientAddress: String -> + logV("exportPublicKeyBundle") + val client = clients[clientAddress] ?: throw XMTPException("No client") + client.privateKeyBundleV1.toPublicKeyBundle().toByteArray().map { it.toInt() and 0xFF } + } AsyncFunction("exportKeyBundle") { clientAddress: String -> logV("exportKeyBundle") diff --git a/src/index.ts b/src/index.ts index f2d51c358..02214f4f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -91,6 +91,14 @@ export async function sign( return new Uint8Array(signatureArray) } +export async function exportPublicKeyBundle( + clientAddress: string +): Promise { + const publicBundleArray = + await XMTPModule.exportPublicKeyBundle(clientAddress) + return new Uint8Array(publicBundleArray) +} + export async function exportKeyBundle(clientAddress: string): Promise { return await XMTPModule.exportKeyBundle(clientAddress) } diff --git a/src/lib/Client.ts b/src/lib/Client.ts index efa0c63de..43b4cd2c7 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -311,6 +311,10 @@ export class Client { ) } + async exportPublicKeyBundle(): Promise { + return XMTPModule.exportPublicKeyBundle(this.address) + } + /** * Exports the key bundle associated with the current XMTP address. * From 8f6737beb7a1125601224f2169932f022fa61899 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 20:18:48 -0800 Subject: [PATCH 06/14] compiling on android correctly --- .../src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index c2c92ac61..75ca43046 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -45,6 +45,7 @@ import org.xmtp.android.library.messages.InvitationV1ContextBuilder import org.xmtp.android.library.messages.Pagination import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.Signature +import org.xmtp.android.library.messages.toPublicKeyBundle import org.xmtp.android.library.push.XMTPPush import org.xmtp.proto.keystore.api.v1.Keystore.TopicMap.TopicData import org.xmtp.proto.message.api.v1.MessageApiOuterClass From dee03d0a2325e0d9b46732270d1264bb178425d7 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 20:28:47 -0800 Subject: [PATCH 07/14] add a test for it --- example/src/tests.ts | 14 ++++++++++++++ src/index.ts | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/example/src/tests.ts b/example/src/tests.ts index 814a091b3..b9412b352 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -173,6 +173,20 @@ test('canMessage', async () => { return canMessage }) +test('fetch a public key bundle and sign a digest', async () => { + const bob = await Client.createRandom({ env: 'local' }) + const bytes = new Uint8Array([1, 2, 3]) + const signature = await bob.sign(bytes, { kind: 'identity' }) + if (signature.length === 0) { + throw new Error('signature was not returned') + } + const keyBundle = await bob.exportPublicKeyBundle() + if (keyBundle.length === 0) { + throw new Error('key bundle was not returned') + } + return true +}) + test('createFromKeyBundle throws error for non string value', async () => { try { const bytes = [1, 2, 3] diff --git a/src/index.ts b/src/index.ts index 02214f4f7..a671bfc87 100644 --- a/src/index.ts +++ b/src/index.ts @@ -80,7 +80,7 @@ export async function sign( clientAddress: string, digest: Uint8Array, keyType: string, - preKeyIndex?: number | 0 + preKeyIndex: number = 0 ): Promise { const signatureArray = await XMTPModule.sign( clientAddress, From 3a7d925e90214835cb11ea262ccd9772fb114409 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 20:46:01 -0800 Subject: [PATCH 08/14] add the swift side --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 5 ++-- ios/XMTPModule.swift | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 75ca43046..e84e6ae62 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -46,6 +46,7 @@ import org.xmtp.android.library.messages.Pagination import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.Signature import org.xmtp.android.library.messages.toPublicKeyBundle +import org.xmtp.android.library.messages.toV2 import org.xmtp.android.library.push.XMTPPush import org.xmtp.proto.keystore.api.v1.Keystore.TopicMap.TopicData import org.xmtp.proto.message.api.v1.MessageApiOuterClass @@ -238,7 +239,7 @@ class XMTPModule : Module() { ) } } - val privateKeyBundle = client.privateKeyBundleV1 + val privateKeyBundle = client.privateKeyBundle.v2 val key = if (keyType == "prekey") { privateKeyBundle.preKeysList[preKeyIndex] } else { @@ -253,7 +254,7 @@ class XMTPModule : Module() { AsyncFunction("exportPublicKeyBundle") { clientAddress: String -> logV("exportPublicKeyBundle") val client = clients[clientAddress] ?: throw XMTPException("No client") - client.privateKeyBundleV1.toPublicKeyBundle().toByteArray().map { it.toInt() and 0xFF } + client.privateKeyBundle.toV2().toPublicKeyBundle().toByteArray().map { it.toInt() and 0xFF } } AsyncFunction("exportKeyBundle") { clientAddress: String -> diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 5ab661e2d..e21081c0e 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -124,9 +124,32 @@ public class XMTPModule: Module { throw error } } + + AsyncFunction("sign") { (clientAddress: String, digest: [UInt8], keyType: String, preKeyIndex: Int) -> [UInt8] in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + + let privateKeyBundle = client.privateKeyBundle + let key = if (keyType == "prekey") { + privateKeyBundle.v2.preKeys[preKeyIndex] + } else { + privateKeyBundle.v2.identityKey + } + let signature = await PrivateKey(key).sign(Data(digest)) + return Array(Data(signature)) + } + + AsyncFunction("exportKeyBundle") { (clientAddress: String) -> [UInt8] in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + let bundle = try client.publicKeyBundle.serializedData() + return Array(bundle) + } // Export the client's serialized key bundle. - AsyncFunction("exportKeyBundle") { (clientAddress: String) -> String in + AsyncFunction("exportPublicKeyBundle") { (clientAddress: String) -> String in guard let client = await clientsManager.getClient(key: clientAddress) else { throw Error.noClient } From ec9ecdf1838179aa8878430488091f26896da3e8 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 1 Feb 2024 20:51:47 -0800 Subject: [PATCH 09/14] swapped the name --- example/ios/Podfile.lock | 4 ++-- ios/XMTPModule.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 69c88772a..d8e373dff 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -748,6 +748,6 @@ SPEC CHECKSUMS: XMTPReactNative: 0a5a691e0e54c7be2e9f276eaac37f9ad6a8e90a Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9 -PODFILE CHECKSUM: bed59df1a015d67be871b27fb59f30a782dbf17c +PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2 -COCOAPODS: 1.14.3 +COCOAPODS: 1.13.0 diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index e21081c0e..a609111f9 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -140,7 +140,7 @@ public class XMTPModule: Module { return Array(Data(signature)) } - AsyncFunction("exportKeyBundle") { (clientAddress: String) -> [UInt8] in + AsyncFunction("exportPublicKeyBundle") { (clientAddress: String) -> [UInt8] in guard let client = await clientsManager.getClient(key: clientAddress) else { throw Error.noClient } @@ -149,7 +149,7 @@ public class XMTPModule: Module { } // Export the client's serialized key bundle. - AsyncFunction("exportPublicKeyBundle") { (clientAddress: String) -> String in + AsyncFunction("exportKeyBundle") { (clientAddress: String) -> String in guard let client = await clientsManager.getClient(key: clientAddress) else { throw Error.noClient } From 8707a93469eb427ef417b306c01f88a5a12caf72 Mon Sep 17 00:00:00 2001 From: Alex Risch Date: Wed, 14 Feb 2024 16:34:23 -0700 Subject: [PATCH 10/14] feat: Sign & exportPublicKeyBundle Additional methods for frames client --- example/ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d8e373dff..c49bef283 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -750,4 +750,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2 -COCOAPODS: 1.13.0 +COCOAPODS: 1.14.3 From 83d42426551d9f871d9a12015648972e2beefcf5 Mon Sep 17 00:00:00 2001 From: Alex Risch Date: Wed, 14 Feb 2024 17:00:35 -0700 Subject: [PATCH 11/14] feat: Sign & exportPublicKeyBundle Additional methods for frames client --- ios/XMTPModule.swift | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index a609111f9..1c177eeb7 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -129,15 +129,13 @@ public class XMTPModule: Module { guard let client = await clientsManager.getClient(key: clientAddress) else { throw Error.noClient } - - let privateKeyBundle = client.privateKeyBundle - let key = if (keyType == "prekey") { - privateKeyBundle.v2.preKeys[preKeyIndex] - } else { - privateKeyBundle.v2.identityKey - } - let signature = await PrivateKey(key).sign(Data(digest)) - return Array(Data(signature)) + let privateKeyBundle = client.keys + let key = keyType == "prekey" ? privateKeyBundle.preKeys[preKeyIndex] : privateKeyBundle.identityKey + + let privateKey = try PrivateKey(key) + let signature = try await privateKey.sign(Data(digest)) + let uint = try [UInt8](signature.serializedData()) + return uint } AsyncFunction("exportPublicKeyBundle") { (clientAddress: String) -> [UInt8] in From 26baadfb5ccec8d652a52119b1a9d216791c093f Mon Sep 17 00:00:00 2001 From: Alex Risch Date: Thu, 15 Feb 2024 15:33:56 -0700 Subject: [PATCH 12/14] Android Functionality - Frames Corrected Android build and functionality --- .../expo/modules/xmtpreactnativesdk/XMTPModule.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index e84e6ae62..151590484 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -45,8 +45,7 @@ import org.xmtp.android.library.messages.InvitationV1ContextBuilder import org.xmtp.android.library.messages.Pagination import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.Signature -import org.xmtp.android.library.messages.toPublicKeyBundle -import org.xmtp.android.library.messages.toV2 +import org.xmtp.android.library.messages.getPublicKeyBundle import org.xmtp.android.library.push.XMTPPush import org.xmtp.proto.keystore.api.v1.Keystore.TopicMap.TopicData import org.xmtp.proto.message.api.v1.MessageApiOuterClass @@ -239,14 +238,15 @@ class XMTPModule : Module() { ) } } - val privateKeyBundle = client.privateKeyBundle.v2 - val key = if (keyType == "prekey") { + val privateKeyBundle = client.keys + val signedPrivateKey = if (keyType == "prekey") { privateKeyBundle.preKeysList[preKeyIndex] } else { privateKeyBundle.identityKey } val signature = runBlocking { - PrivateKeyBuilder(key).sign(digestBytes) + val privateKey = PrivateKeyBuilder.buildFromSignedPrivateKey(signedPrivateKey) + PrivateKeyBuilder(privateKey).sign(digestBytes) } signature.toByteArray().map { it.toInt() and 0xFF } } @@ -254,7 +254,7 @@ class XMTPModule : Module() { AsyncFunction("exportPublicKeyBundle") { clientAddress: String -> logV("exportPublicKeyBundle") val client = clients[clientAddress] ?: throw XMTPException("No client") - client.privateKeyBundle.toV2().toPublicKeyBundle().toByteArray().map { it.toInt() and 0xFF } + client.keys.getPublicKeyBundle().toByteArray().map { it.toInt() and 0xFF } } AsyncFunction("exportKeyBundle") { clientAddress: String -> From a8039e861513d64970c3a8df56ade68297e7b232 Mon Sep 17 00:00:00 2001 From: Alex Risch Date: Thu, 15 Feb 2024 15:50:56 -0700 Subject: [PATCH 13/14] Frames Client Tests iOS Android updated frame client --- example/package.json | 1 + example/src/tests.ts | 38 ++++++++++++++++++++++++++++++++++++++ example/yarn.lock | 42 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/example/package.json b/example/package.json index a2b4c2db5..9c83adfa9 100644 --- a/example/package.json +++ b/example/package.json @@ -14,6 +14,7 @@ "@react-navigation/native-stack": "^6.9.12", "@thirdweb-dev/react-native": "^0.6.2", "@thirdweb-dev/react-native-compat": "^0.6.2", + "@xmtp/frames-client": "^0.3.0", "ethers": "^5.7.2", "expo": "~48.0.18", "expo-document-picker": "^11.5.4", diff --git a/example/src/tests.ts b/example/src/tests.ts index 0c1fdaaee..308ece762 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -1,3 +1,4 @@ +import { FramesClient } from '@xmtp/frames-client' import { content } from '@xmtp/proto' import ReactNativeBlobUtil from 'react-native-blob-util' import { TextEncoder, TextDecoder } from 'text-encoding' @@ -939,3 +940,40 @@ test('correctly handles lowercase addresses', async () => { } return true }) + +test('instantiate frames client correctly', async () => { + const frameUrl = + 'https://fc-polls-five.vercel.app/polls/01032f47-e976-42ee-9e3d-3aac1324f4b8' + const client = await Client.createRandom({ env: 'local' }) + const framesClient = new FramesClient(client) + const metadata = await framesClient.proxy.readMetadata(frameUrl) + if (!metadata) { + throw new Error('metadata should exist') + } + const signedPayload = await framesClient.signFrameAction({ + frameUrl, + buttonIndex: 1, + conversationTopic: 'foo', + participantAccountAddresses: ['amal', 'bola'], + }) + const postUrl = metadata.extractedTags['fc:frame:post_url'] + const response = await framesClient.proxy.post(postUrl, signedPayload) + if (!response) { + throw new Error('response should exist') + } + console.log('response', response) + if (response.extractedTags['fc:frame'] !== 'vNext') { + throw new Error('response should have expected extractedTags') + } + const imageUrl = response.extractedTags['fc:frame:image'] + const mediaUrl = framesClient.proxy.mediaUrl(imageUrl) + + const downloadedMedia = await fetch(mediaUrl) + if (!downloadedMedia.ok) { + throw new Error('downloadedMedia should be ok') + } + if (downloadedMedia.headers.get('content-type') !== 'image/png') { + throw new Error('downloadedMedia should be image/png') + } + return true +}) diff --git a/example/yarn.lock b/example/yarn.lock index 765def3de..771c7bf5b 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -4632,6 +4632,11 @@ find-up "^5.0.0" js-yaml "^4.1.0" +"@fastify/busboy@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" + integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== + "@fastify/cookie@^9.1.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@fastify/cookie/-/cookie-9.3.0.tgz#229d8cfb754a60d815b98215a600a12e7d4b83c1" @@ -5075,7 +5080,7 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== -"@noble/hashes@1.3.3", "@noble/hashes@^1.3.2", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": +"@noble/hashes@1.3.3", "@noble/hashes@^1.3.2", "@noble/hashes@^1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== @@ -6788,6 +6793,25 @@ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.13.tgz#ff34942667a4e19a9f4a0996a76814daac364cf3" integrity sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g== +"@xmtp/frames-client@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@xmtp/frames-client/-/frames-client-0.3.0.tgz#5d8848590f57ea543905df2d7719a6eacedc74c7" + integrity sha512-iUc9LRqTkYBqsD2lvnpunjgotudTMHu0h187KcHacVeq+GQYjVMZx6E06hi3DztUlmZ1OwBzq3ki30qdBFKSbg== + dependencies: + "@noble/hashes" "^1.3.3" + "@xmtp/proto" "3.41.0-beta.5" + long "^5.2.3" + +"@xmtp/proto@3.41.0-beta.5": + version "3.41.0-beta.5" + resolved "https://registry.yarnpkg.com/@xmtp/proto/-/proto-3.41.0-beta.5.tgz#fe6d2f4f0a37e69c18c516ed0796a48fb16574db" + integrity sha512-vx5zqLpAVPjTEdyqY/woXrgvWMKjbTwwco+x9WE+T1iVlv+472yp2DwFJRLpfeQByC1cHl7XQyuO2Q+8t8HL4Q== + dependencies: + long "^5.2.0" + protobufjs "^7.0.0" + rxjs "^7.8.0" + undici "^5.8.1" + JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -11465,7 +11489,7 @@ logkitty@^0.7.1: dayjs "^1.8.15" yargs "^15.1.0" -long@^5.0.0: +long@^5.0.0, long@^5.2.0, long@^5.2.3: version "5.2.3" resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== @@ -13920,6 +13944,13 @@ rxjs@^6.6.3: dependencies: tslib "^1.9.0" +rxjs@^7.8.0: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + safe-array-concat@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" @@ -15023,6 +15054,13 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici@^5.8.1: + version "5.28.3" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" + integrity sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA== + dependencies: + "@fastify/busboy" "^2.0.0" + unenv@^1.8.0: version "1.9.0" resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.9.0.tgz#469502ae85be1bd3a6aa60f810972b1a904ca312" From 9118400cbae9e60a811c709ae43f9ae8b2c3d5fc Mon Sep 17 00:00:00 2001 From: Alex Risch Date: Fri, 16 Feb 2024 11:47:40 -0700 Subject: [PATCH 14/14] Remove log bumped package --- example/package.json | 2 +- example/src/tests.ts | 1 - example/yarn.lock | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/example/package.json b/example/package.json index 9c83adfa9..62e3264b7 100644 --- a/example/package.json +++ b/example/package.json @@ -14,7 +14,7 @@ "@react-navigation/native-stack": "^6.9.12", "@thirdweb-dev/react-native": "^0.6.2", "@thirdweb-dev/react-native-compat": "^0.6.2", - "@xmtp/frames-client": "^0.3.0", + "@xmtp/frames-client": "^0.3.2", "ethers": "^5.7.2", "expo": "~48.0.18", "expo-document-picker": "^11.5.4", diff --git a/example/src/tests.ts b/example/src/tests.ts index 308ece762..f374e2365 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -961,7 +961,6 @@ test('instantiate frames client correctly', async () => { if (!response) { throw new Error('response should exist') } - console.log('response', response) if (response.extractedTags['fc:frame'] !== 'vNext') { throw new Error('response should have expected extractedTags') } diff --git a/example/yarn.lock b/example/yarn.lock index 771c7bf5b..b2fa7e152 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -6793,10 +6793,10 @@ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.13.tgz#ff34942667a4e19a9f4a0996a76814daac364cf3" integrity sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g== -"@xmtp/frames-client@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@xmtp/frames-client/-/frames-client-0.3.0.tgz#5d8848590f57ea543905df2d7719a6eacedc74c7" - integrity sha512-iUc9LRqTkYBqsD2lvnpunjgotudTMHu0h187KcHacVeq+GQYjVMZx6E06hi3DztUlmZ1OwBzq3ki30qdBFKSbg== +"@xmtp/frames-client@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@xmtp/frames-client/-/frames-client-0.3.2.tgz#6c860e11cbf7a63aa956543b4941ee72738ed211" + integrity sha512-61rxA7YcNUUKndQ9e5X44LNVwWJCrrZR6sBGOWLckfMK00LqRasoiLgom1PlR34c17a59PPZmagxoNQ2QCto7A== dependencies: "@noble/hashes" "^1.3.3" "@xmtp/proto" "3.41.0-beta.5"