From 7a0eb30f0fd5cb458ac948438a672b02c7651278 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 24 Jul 2023 16:12:33 -0700 Subject: [PATCH 01/12] try to bring the client options more inline with what users expect from javascript --- src/lib/Client.ts | 58 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 92e631274..793139701 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -1,10 +1,16 @@ import { Signer, utils } from "ethers"; import Conversations from "./Conversations"; +import { DecodedMessage } from "./DecodedMessage"; import { Query } from "./Query"; import { hexToBytes } from "./util"; import * as XMTPModule from "../index"; -import { DecodedMessage } from "./DecodedMessage"; + +export const ApiUrls = { + local: "http://localhost:5555", + dev: "https://dev.xmtp.network", + production: "https://production.xmtp.network", +} as const; declare const Buffer; export class Client { @@ -13,8 +19,9 @@ export class Client { static async create( signer: Signer, - environment: "local" | "dev" | "production" + opts?: Partial ): Promise { + const options = defaultOptions(opts); return new Promise((resolve, reject) => { (async () => { XMTPModule.emitter.addListener( @@ -40,25 +47,25 @@ export class Client { const address = await signer.getAddress(); resolve(new Client(address)); }); - XMTPModule.auth(await signer.getAddress(), environment); + XMTPModule.auth(await signer.getAddress(), options.env); })(); }); } - static async createRandom( - environment: "local" | "dev" | "production" - ): Promise { - const address = await XMTPModule.createRandom(environment); + static async createRandom(opts?: Partial): Promise { + const options = defaultOptions(opts); + const address = await XMTPModule.createRandom(options.env); return new Client(address); } static async createFromKeyBundle( keyBundle: string, - environment: "local" | "dev" | "production" + opts?: Partial ): Promise { + const options = defaultOptions(opts); const address = await XMTPModule.createFromKeyBundle( keyBundle, - environment + options.env ); return new Client(address); } @@ -89,3 +96,36 @@ export class Client { } } } + +export type ClientOptions = NetworkOptions; +export type XmtpEnv = keyof typeof ApiUrls; +export type NetworkOptions = { + /** + * Specify which XMTP environment to connect to. (default: `dev`) + */ + env: XmtpEnv; + /** + * identifier that's included with API requests. + * + * For example, you can use the following format: + * `appVersion: APP_NAME + '/' + APP_VERSION`. + * Setting this value provides telemetry that shows which apps are + * using the XMTP client SDK. This information can help XMTP developers + * provide app support, especially around communicating important + * SDK updates, including deprecations and required upgrades. + */ + appVersion?: string; +}; + +/** + * Provide a default client configuration. These settings can be used on their own, or as a starting point for custom configurations + * + * @param opts additional options to override the default settings + */ +export function defaultOptions(opts?: Partial): ClientOptions { + const _defaultOptions: ClientOptions = { + env: "dev", + }; + + return { ..._defaultOptions, ...opts } as ClientOptions; +} From 12b4711d46f3d820a339abdd933731f630db350d Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 24 Jul 2023 16:50:29 -0700 Subject: [PATCH 02/12] bump the pod spec --- example/ios/Podfile.lock | 14 +++++++------- ios/XMTPReactNative.podspec | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 54cee0eea..0c063e281 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -409,16 +409,16 @@ PODS: - GenericJSON (~> 2.0) - Logging (~> 1.0.0) - secp256k1.swift (~> 0.1) - - XMTP (0.4.0-alpha0): + - XMTP (0.4.1-alpha0): - Connect-Swift - GzipSwift - web3.swift - - XMTPRust (= 0.3.0-beta0) + - XMTPRust (= 0.3.1-beta0) - XMTPReactNative (0.1.0): - ExpoModulesCore - MessagePacker - - XMTP (= 0.4.0-alpha0) - - XMTPRust (0.3.0-beta0) + - XMTP (= 0.4.1-alpha0) + - XMTPRust (0.3.1-beta0) - Yoga (1.14.0) DEPENDENCIES: @@ -660,9 +660,9 @@ SPEC CHECKSUMS: secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634 SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989 web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959 - XMTP: 8bb7ef01ba2ed0db8bbf699164d2da22dd989a25 - XMTPReactNative: c8f5e3f2d2f1e9102b9fd888047b34919be057d4 - XMTPRust: 233518ed46fbe3ea9e3bc3035de9a620dba09ce5 + XMTP: a5be4f9bcae69a821b258c76b7aaed2701961cac + XMTPReactNative: 74eb825a1acf17580a9e6bacb0aadb15724a4dd4 + XMTPRust: 78f65f77b1454392980da244961777aee955652f Yoga: ba09b6b11e6139e3df8229238aa794205ca6a02a PODFILE CHECKSUM: 522d88edc2d5fac4825e60a121c24abc18983367 diff --git a/ios/XMTPReactNative.podspec b/ios/XMTPReactNative.podspec index 385377475..afc7d4206 100644 --- a/ios/XMTPReactNative.podspec +++ b/ios/XMTPReactNative.podspec @@ -25,5 +25,5 @@ Pod::Spec.new do |s| s.source_files = "**/*.{h,m,swift}" s.dependency "MessagePacker" - s.dependency "XMTP", "= 0.4.0-alpha0" + s.dependency "XMTP", "= 0.4.1-alpha0" end From ef481bdcec0a45d4102c9cdb40f5d5eb3108b94c Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 24 Jul 2023 17:00:56 -0700 Subject: [PATCH 03/12] do the kotlin side --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 0b39c268b..3abc21e9a 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -81,11 +81,27 @@ fun Conversation.cacheKey(clientAddress: String): String { } class XMTPModule : Module() { - private val apiEnvironments = mapOf( - "local" to ClientOptions.Api(env = XMTPEnvironment.LOCAL, isSecure = false), - "dev" to ClientOptions.Api(env = XMTPEnvironment.DEV, isSecure = true), - "production" to ClientOptions.Api(env = XMTPEnvironment.PRODUCTION, isSecure = true) - ) + private fun apiEnvironments(env: String, appVersion: String?): ClientOptions.Api { + return when (env) { + "local" -> ClientOptions.Api( + env = XMTPEnvironment.LOCAL, + isSecure = false, + appVersion = appVersion + ) + + "production" -> ClientOptions.Api( + env = XMTPEnvironment.PRODUCTION, + isSecure = true, + appVersion = appVersion + ) + + else -> ClientOptions.Api( + env = XMTPEnvironment.DEV, + isSecure = true, + appVersion = appVersion + ) + } + } private var clients: MutableMap = mutableMapOf() private var xmtpPush: XMTPPush? = null @@ -107,12 +123,11 @@ class XMTPModule : Module() { // // Auth functions // - AsyncFunction("auth") { address: String, environment: String -> + AsyncFunction("auth") { address: String, environment: String, appVersion: String -> logV("auth") val reactSigner = ReactNativeSigner(module = this@XMTPModule, address = address) signer = reactSigner - val options = - ClientOptions(api = apiEnvironments[environment] ?: apiEnvironments["dev"]!!) + val options = ClientOptions(api = apiEnvironments(environment, appVersion)) clients[address] = Client().create(account = reactSigner, options = options) signer = null sendEvent("authed") @@ -124,21 +139,19 @@ class XMTPModule : Module() { } // Generate a random wallet and set the client to that - AsyncFunction("createRandom") { environment: String -> + AsyncFunction("createRandom") { environment: String, appVersion: String -> logV("createRandom") val privateKey = PrivateKeyBuilder() - val options = - ClientOptions(api = apiEnvironments[environment] ?: apiEnvironments["dev"]!!) + val options = ClientOptions(api = apiEnvironments(environment, appVersion)) val randomClient = Client().create(account = privateKey, options = options) clients[randomClient.address] = randomClient randomClient.address } - AsyncFunction("createFromKeyBundle") { keyBundle: String, environment: String -> + AsyncFunction("createFromKeyBundle") { keyBundle: String, environment: String, appVersion: String -> try { logV("createFromKeyBundle") - val options = - ClientOptions(api = apiEnvironments[environment] ?: apiEnvironments["dev"]!!) + val options = ClientOptions(api = apiEnvironments(environment, appVersion)) val bundle = PrivateKeyOuterClass.PrivateKeyBundle.parseFrom( Base64.decode( From 1e4ea867c4c1d667de10845abd27a9fbb4ca149f Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 24 Jul 2023 17:37:09 -0700 Subject: [PATCH 04/12] get the tests passing on android --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 16 +++++++----- example/src/tests.ts | 26 ++++++++++--------- src/index.ts | 19 +++++++++----- src/lib/Client.ts | 23 ++++++++-------- 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 3abc21e9a..5b845c74f 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -123,7 +123,7 @@ class XMTPModule : Module() { // // Auth functions // - AsyncFunction("auth") { address: String, environment: String, appVersion: String -> + AsyncFunction("auth") { address: String, environment: String, appVersion: String? -> logV("auth") val reactSigner = ReactNativeSigner(module = this@XMTPModule, address = address) signer = reactSigner @@ -139,16 +139,20 @@ class XMTPModule : Module() { } // Generate a random wallet and set the client to that - AsyncFunction("createRandom") { environment: String, appVersion: String -> + AsyncFunction("createRandom") { environment: String, appVersion: String? -> logV("createRandom") val privateKey = PrivateKeyBuilder() val options = ClientOptions(api = apiEnvironments(environment, appVersion)) - val randomClient = Client().create(account = privateKey, options = options) - clients[randomClient.address] = randomClient - randomClient.address + try { + val randomClient = Client().create(account = privateKey, options = options) + clients[randomClient.address] = randomClient + randomClient.address + } catch (e: Exception) { + Log.d("LOPI", e.message.toString()) + } } - AsyncFunction("createFromKeyBundle") { keyBundle: String, environment: String, appVersion: String -> + AsyncFunction("createFromKeyBundle") { keyBundle: String, environment: String, appVersion: String? -> try { logV("createFromKeyBundle") val options = ClientOptions(api = apiEnvironments(environment, appVersion)) diff --git a/example/src/tests.ts b/example/src/tests.ts index be86c7ca7..02059421c 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -27,7 +27,7 @@ function test(name: string, perform: () => Promise) { // }); test("can make a client", async () => { - const client = await XMTP.Client.createRandom("local"); + const client = await XMTP.Client.createRandom({ env: "local" }); return client.address.length > 0; }); @@ -44,8 +44,8 @@ test("can send and receive a text codec", async () => { const data = content.EncodedContent.encode(encodedContent).finish(); - const bob = await XMTP.Client.createRandom("local"); - const alice = await XMTP.Client.createRandom("local"); + const bob = await XMTP.Client.createRandom({ env: "local" }); + const alice = await XMTP.Client.createRandom({ env: "local" }); if (bob.address === alice.address) { throw new Error("bob and alice should be different"); @@ -89,8 +89,8 @@ test("can pass a custom filter date and receive message objects with expected da const data = content.EncodedContent.encode(encodedContent).finish(); - const bob = await XMTP.Client.createRandom("local"); - const alice = await XMTP.Client.createRandom("local"); + const bob = await XMTP.Client.createRandom({ env: "local" }); + const alice = await XMTP.Client.createRandom({ env: "local" }); if (bob.address === alice.address) { throw new Error("bob and alice should be different"); @@ -129,8 +129,8 @@ test("can pass a custom filter date and receive message objects with expected da }); test("canMessage", async () => { - const bob = await XMTP.Client.createRandom("local"); - const alice = await XMTP.Client.createRandom("local"); + const bob = await XMTP.Client.createRandom({ env: "local" }); + const alice = await XMTP.Client.createRandom({ env: "local" }); const canMessage = await bob.canMessage(alice.address); return canMessage; @@ -201,8 +201,8 @@ test("can send and receive number codec", async () => { const data = content.EncodedContent.encode(encodedContent).finish(); - const bob = await XMTP.Client.createRandom("local"); - const alice = await XMTP.Client.createRandom("local"); + const bob = await XMTP.Client.createRandom({ env: "local" }); + const alice = await XMTP.Client.createRandom({ env: "local" }); if (bob.address === alice.address) { throw new Error("bob and alice should be different"); @@ -235,7 +235,9 @@ test("can send and receive number codec", async () => { test("createFromKeyBundle throws error for non string value", async () => { try { const bytes = randomBytes(32); - await XMTP.Client.createFromKeyBundle(JSON.stringify(bytes), "local"); + await XMTP.Client.createFromKeyBundle(JSON.stringify(bytes), { + env: "local", + }); } catch (e) { return true; } @@ -255,8 +257,8 @@ test("can list batch messages", async () => { const data = content.EncodedContent.encode(encodedContent).finish(); - const bob = await XMTP.Client.createRandom("local"); - const alice = await XMTP.Client.createRandom("local"); + const bob = await XMTP.Client.createRandom({ env: "local" }); + const alice = await XMTP.Client.createRandom({ env: "local" }); if (bob.address === alice.address) { throw new Error("bob and alice should be different"); diff --git a/src/index.ts b/src/index.ts index c88a9f4fd..25d01b7b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,9 +14,10 @@ export function address(): string { export async function auth( address: string, - environment: "local" | "dev" | "production" + environment: "local" | "dev" | "production", + appVersion?: string | undefined ) { - return await XMTPModule.auth(address, environment); + return await XMTPModule.auth(address, environment, appVersion); } export async function receiveSignature(requestID: string, signature: string) { @@ -24,16 +25,22 @@ export async function receiveSignature(requestID: string, signature: string) { } export async function createRandom( - environment: "local" | "dev" | "production" + environment: "local" | "dev" | "production", + appVersion?: string | undefined ): Promise { - return await XMTPModule.createRandom(environment); + return await XMTPModule.createRandom(environment, appVersion); } export async function createFromKeyBundle( keyBundle: string, - environment: "local" | "dev" | "production" + environment: "local" | "dev" | "production", + appVersion?: string | undefined ): Promise { - return await XMTPModule.createFromKeyBundle(keyBundle, environment); + return await XMTPModule.createFromKeyBundle( + keyBundle, + environment, + appVersion + ); } export async function exportKeyBundle(clientAddress: string): Promise { diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 793139701..a92c3beed 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -6,12 +6,6 @@ import { Query } from "./Query"; import { hexToBytes } from "./util"; import * as XMTPModule from "../index"; -export const ApiUrls = { - local: "http://localhost:5555", - dev: "https://dev.xmtp.network", - production: "https://production.xmtp.network", -} as const; - declare const Buffer; export class Client { address: string; @@ -47,14 +41,21 @@ export class Client { const address = await signer.getAddress(); resolve(new Client(address)); }); - XMTPModule.auth(await signer.getAddress(), options.env); + XMTPModule.auth( + await signer.getAddress(), + options.env, + options.appVersion + ); })(); }); } static async createRandom(opts?: Partial): Promise { const options = defaultOptions(opts); - const address = await XMTPModule.createRandom(options.env); + const address = await XMTPModule.createRandom( + options.env, + options.appVersion + ); return new Client(address); } @@ -65,7 +66,8 @@ export class Client { const options = defaultOptions(opts); const address = await XMTPModule.createFromKeyBundle( keyBundle, - options.env + options.env, + options.appVersion ); return new Client(address); } @@ -98,12 +100,11 @@ export class Client { } export type ClientOptions = NetworkOptions; -export type XmtpEnv = keyof typeof ApiUrls; export type NetworkOptions = { /** * Specify which XMTP environment to connect to. (default: `dev`) */ - env: XmtpEnv; + env: "local" | "dev" | "production"; /** * identifier that's included with API requests. * From 9a85c56eff15d00e93d2da9c8958c80cc7005e95 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 24 Jul 2023 17:39:39 -0700 Subject: [PATCH 05/12] add a test for it --- .../java/expo/modules/xmtpreactnativesdk/XMTPModule.kt | 10 +++------- example/src/tests.ts | 5 ++++- 2 files changed, 7 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 5b845c74f..c6d1c0a79 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -143,13 +143,9 @@ class XMTPModule : Module() { logV("createRandom") val privateKey = PrivateKeyBuilder() val options = ClientOptions(api = apiEnvironments(environment, appVersion)) - try { - val randomClient = Client().create(account = privateKey, options = options) - clients[randomClient.address] = randomClient - randomClient.address - } catch (e: Exception) { - Log.d("LOPI", e.message.toString()) - } + val randomClient = Client().create(account = privateKey, options = options) + clients[randomClient.address] = randomClient + randomClient.address } AsyncFunction("createFromKeyBundle") { keyBundle: String, environment: String, appVersion: String? -> diff --git a/example/src/tests.ts b/example/src/tests.ts index 02059421c..c937f8185 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -27,7 +27,10 @@ function test(name: string, perform: () => Promise) { // }); test("can make a client", async () => { - const client = await XMTP.Client.createRandom({ env: "local" }); + const client = await XMTP.Client.createRandom({ + env: "local", + appVersion: "Testing/0.0.0", + }); return client.address.length > 0; }); From 6d83588095958b0379a3d1cbdad7d8557dacfd04 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 24 Jul 2023 17:42:33 -0700 Subject: [PATCH 06/12] fix up the example app --- example/src/AuthView.tsx | 10 ++++++++-- example/src/tests.ts | 6 +----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/example/src/AuthView.tsx b/example/src/AuthView.tsx index 645cc8f99..230254245 100644 --- a/example/src/AuthView.tsx +++ b/example/src/AuthView.tsx @@ -19,14 +19,20 @@ function AuthView({ useEffect(() => { (async () => { if (signer) { - const client = await XMTP.Client.create(signer, "dev"); + const client = await XMTP.Client.create(signer, { + env: "dev", + appVersion: "XMTP_RN_EX/0.0.1", + }); setClient(client); } })(); }, [signer]); const generateWallet = async () => { - const client = await XMTP.Client.createRandom("dev"); + const client = await XMTP.Client.createRandom({ + env: "dev", + appVersion: "XMTP_RN_EX/0.0.1", + }); setClient(client); }; diff --git a/example/src/tests.ts b/example/src/tests.ts index c937f8185..6f10d7044 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -1,15 +1,11 @@ import { content } from "@xmtp/proto"; +import { randomBytes } from "crypto"; import { NumberCodec, TextCodec } from "./test_utils"; import * as XMTP from "../../src/index"; import { DecodedMessage, Query } from "../../src/index"; import { CodecError } from "../../src/lib/CodecError"; import { CodecRegistry } from "../../src/lib/CodecRegistry"; -import { randomBytes } from "crypto"; - -function sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} export type Test = { name: string; From b3cd58c267d04393e25bae5877c35572f587b502 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 24 Jul 2023 17:58:02 -0700 Subject: [PATCH 07/12] first pass on docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a11abe2d4..0a04e959e 100644 --- a/README.md +++ b/README.md @@ -289,7 +289,7 @@ const { Client } = require('@xmtp/xmtp-react-native') async function main() { //Create a random wallet for example purposes. On the frontend you should replace it with the user's wallet (metamask, rainbow, etc) //Initialize the xmtp client - const xmtp = await XMTP.Client.createRandom("dev"); + const xmtp = await XMTP.Client.createRandom({ env: "dev" }); //In this example we are going to broadcast to the GM_BOT wallet (already activated) and a random wallet (not activated) const GM_BOT = '0x937C0d4a6294cdfa575de17382c7076b579DC176' From a6fe61eb7b21226812c24733e7bf8aaa76167bff Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 25 Jul 2023 18:43:26 -0700 Subject: [PATCH 08/12] add swift implementation --- ios/XMTPModule.swift | 48 ++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 9ee31a8d6..3a1ca0685 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -70,20 +70,28 @@ extension Conversation { } public class XMTPModule: Module { - var apiEnvironments = [ - "local": XMTP.ClientOptions.Api( - env: XMTP.XMTPEnvironment.local, - isSecure: false - ), - "dev": XMTP.ClientOptions.Api( - env: XMTP.XMTPEnvironment.dev, - isSecure: true - ), - "production": XMTP.ClientOptions.Api( - env: XMTP.XMTPEnvironment.production, - isSecure: true - ), - ] + private func apiEnvironments(env: String, appVersion: String?) -> XMTP.ClientOptions.Api { + switch env { + case "local": + return XMTP.ClientOptions.Api( + env: XMTP.XMTPEnvironment.local, + isSecure: false, + appVersion: appVersion + ), + case "production": + return XMTP.ClientOptions.Api( + env: XMTP.XMTPEnvironment.production, + isSecure: false, + appVersion: appVersion + ) + case default: + return XMTP.ClientOptions.Api( + env: XMTP.XMTPEnvironment.dev, + isSecure: false, + appVersion: appVersion + ), + } + } var clients: [String: XMTP.Client] = [:] var signer: ReactNativeSigner? @@ -111,10 +119,10 @@ public class XMTPModule: Module { // // Auth functions // - AsyncFunction("auth") { (address: String, environment: String) in + AsyncFunction("auth") { (address: String, environment: String, appVersion: String?) in let signer = ReactNativeSigner(module: self, address: address) self.signer = signer - let options = XMTP.ClientOptions(api: apiEnvironments[environment] ?? apiEnvironments["local"]!) + let options = XMTP.ClientOptions(api: apiEnvironments(env: environment, appVersion: appVersion)) self.clients[address] = try await XMTP.Client.create(account: signer, options: options) self.signer = nil sendEvent("authed") @@ -125,9 +133,9 @@ public class XMTPModule: Module { } // Generate a random wallet and set the client to that - AsyncFunction("createRandom") { (environment: String) -> String in + AsyncFunction("createRandom") { (environment: String, appVersion: String?) -> String in let privateKey = try PrivateKey.generate() - let options = XMTP.ClientOptions(api: apiEnvironments[environment] ?? apiEnvironments["dev"]!) + let options = XMTP.ClientOptions(api: apiEnvironments(env: environment, appVersion: appVersion)) let client = try await Client.create(account: privateKey, options: options) self.clients[client.address] = client @@ -135,14 +143,14 @@ public class XMTPModule: Module { } // Create a client using its serialized key bundle. - AsyncFunction("createFromKeyBundle") { (keyBundle: String, environment: String) -> String in + AsyncFunction("createFromKeyBundle") { (keyBundle: String, environment: String, appVersion: String?) -> String in do { guard let keyBundleData = Data(base64Encoded: keyBundle), let bundle = try? PrivateKeyBundle(serializedData: keyBundleData) else { throw Error.invalidKeyBundle } - let options = XMTP.ClientOptions(api: apiEnvironments[environment] ?? apiEnvironments["dev"]!) + let options = XMTP.ClientOptions(api: apiEnvironments(env: environment, appVersion: appVersion)) let client = try await Client.from(bundle: bundle, options: options) self.clients[client.address] = client return client.address From 917567a6d3dc2efe181076fe8d8c9f982ab542b0 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 25 Jul 2023 18:47:48 -0700 Subject: [PATCH 09/12] all the swift stuff working as expected --- ios/XMTPModule.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 3a1ca0685..87230a6d7 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -77,19 +77,19 @@ public class XMTPModule: Module { env: XMTP.XMTPEnvironment.local, isSecure: false, appVersion: appVersion - ), + ) case "production": return XMTP.ClientOptions.Api( env: XMTP.XMTPEnvironment.production, isSecure: false, appVersion: appVersion ) - case default: + default: return XMTP.ClientOptions.Api( env: XMTP.XMTPEnvironment.dev, isSecure: false, appVersion: appVersion - ), + ) } } From d417cbe930f5240c3ef509adb04a7c7377f60844 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 25 Jul 2023 18:53:35 -0700 Subject: [PATCH 10/12] small tweak to the read me --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a04e959e..2377c6f3c 100644 --- a/README.md +++ b/README.md @@ -362,7 +362,7 @@ import { Client } from '@xmtp/xmtp-react-native' // Get the keys using a valid Signer. Save them somewhere secure. const keys = await Client.exportKeyBundle() // Create a client using keys returned from getKeys -const client = await Client.createFromKeyBundle(keys, "dev") +const client = await Client.createFromKeyBundle(keys, { env: "dev" }) ``` The keys returned by `exportKeyBundle` should be treated with the utmost care as compromise of these keys will allow an attacker to impersonate the user on the XMTP network. Ensure these keys are stored somewhere secure and encrypted. From 8aa50cb403728e83b0ed5cb70968138ae7fe42a5 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 26 Jul 2023 11:31:39 -0700 Subject: [PATCH 11/12] fix is secure --- ios/XMTPModule.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 87230a6d7..5ba0e718e 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -81,13 +81,13 @@ public class XMTPModule: Module { case "production": return XMTP.ClientOptions.Api( env: XMTP.XMTPEnvironment.production, - isSecure: false, + isSecure: true, appVersion: appVersion ) default: return XMTP.ClientOptions.Api( env: XMTP.XMTPEnvironment.dev, - isSecure: false, + isSecure: true, appVersion: appVersion ) } From c6e48b96496486df0ce92650584a47a732058601 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 26 Jul 2023 12:26:30 -0700 Subject: [PATCH 12/12] feat: add client options with a version id