Skip to content

Commit

Permalink
get it working on android
Browse files Browse the repository at this point in the history
  • Loading branch information
nplasterer committed Jun 25, 2024
1 parent 8d5d6ae commit fae16ea
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 59 deletions.
42 changes: 23 additions & 19 deletions android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import expo.modules.kotlin.exception.Exceptions
import expo.modules.kotlin.functions.Coroutine
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
import expo.modules.xmtpreactnativesdk.wrappers.AuthParamsWrapper
import expo.modules.xmtpreactnativesdk.wrappers.ClientWrapper
import expo.modules.xmtpreactnativesdk.wrappers.ConsentWrapper
import expo.modules.xmtpreactnativesdk.wrappers.ConsentWrapper.Companion.consentStateToString
Expand Down Expand Up @@ -227,10 +228,11 @@ class XMTPModule : Module() {
// Auth functions
//
AsyncFunction("auth") {
{ address: String, environment: String, appVersion: String?, hasCreateIdentityCallback: Boolean?, hasEnableIdentityCallback: Boolean?, enableV3: Boolean?, dbEncryptionKey: List<Int>?, dbDirectory: String?, historySyncUrl: String? ->
{ address: String, hasCreateIdentityCallback: Boolean?, hasEnableIdentityCallback: Boolean?, dbEncryptionKey: List<Int>?, authParams: String ->
logV("auth")
val reactSigner = ReactNativeSigner(module = this@XMTPModule, address = address)
signer = reactSigner
val authOptions = AuthParamsWrapper.authParamsFromJson(authParams)

if (hasCreateIdentityCallback == true)
preCreateIdentityCallbackDeferred = CompletableDeferred()
Expand All @@ -240,21 +242,21 @@ class XMTPModule : Module() {
preCreateIdentityCallback.takeIf { hasCreateIdentityCallback == true }
val preEnableIdentityCallback: PreEventCallback? =
preEnableIdentityCallback.takeIf { hasEnableIdentityCallback == true }
val context = if (enableV3 == true) context else null
val context = if (authOptions.enableV3) context else null
val encryptionKeyBytes =
dbEncryptionKey?.foldIndexed(ByteArray(dbEncryptionKey.size)) { i, a, v ->
a.apply { set(i, v.toByte()) }
}

val options = ClientOptions(
api = apiEnvironments(environment, appVersion),
api = apiEnvironments(authOptions.environment, authOptions.appVersion),
preCreateIdentityCallback = preCreateIdentityCallback,
preEnableIdentityCallback = preEnableIdentityCallback,
enableV3 = enableV3 == true,
enableV3 = authOptions.enableV3,
appContext = context,
dbEncryptionKey = encryptionKeyBytes,
dbDirectory = dbDirectory,
historySyncUrl = historySyncUrl
dbDirectory = authOptions.dbDirectory,
historySyncUrl = authOptions.historySyncUrl
)
val client = Client().create(account = reactSigner, options = options)
clients[client.inboxId] = client
Expand All @@ -270,7 +272,7 @@ class XMTPModule : Module() {
}

// Generate a random wallet and set the client to that
AsyncFunction("createRandom") { environment: String, appVersion: String?, hasCreateIdentityCallback: Boolean?, hasEnableIdentityCallback: Boolean?, enableV3: Boolean?, dbEncryptionKey: List<Int>?, dbDirectory: String?, historySyncUrl: String? ->
AsyncFunction("createRandom") { hasCreateIdentityCallback: Boolean?, hasEnableIdentityCallback: Boolean?, dbEncryptionKey: List<Int>?, authParams: String ->
logV("createRandom")
val privateKey = PrivateKeyBuilder()

Expand All @@ -282,21 +284,23 @@ class XMTPModule : Module() {
preCreateIdentityCallback.takeIf { hasCreateIdentityCallback == true }
val preEnableIdentityCallback: PreEventCallback? =
preEnableIdentityCallback.takeIf { hasEnableIdentityCallback == true }
val context = if (enableV3 == true) context else null

val authOptions = AuthParamsWrapper.authParamsFromJson(authParams)
val context = if (authOptions.enableV3) context else null
val encryptionKeyBytes =
dbEncryptionKey?.foldIndexed(ByteArray(dbEncryptionKey.size)) { i, a, v ->
a.apply { set(i, v.toByte()) }
}

val options = ClientOptions(
api = apiEnvironments(environment, appVersion),
api = apiEnvironments(authOptions.environment, authOptions.appVersion),
preCreateIdentityCallback = preCreateIdentityCallback,
preEnableIdentityCallback = preEnableIdentityCallback,
enableV3 = enableV3 == true,
enableV3 = authOptions.enableV3,
appContext = context,
dbEncryptionKey = encryptionKeyBytes,
dbDirectory = dbDirectory,
historySyncUrl = historySyncUrl
dbDirectory = authOptions.dbDirectory,
historySyncUrl = authOptions.historySyncUrl

)
val randomClient = Client().create(account = privateKey, options = options)
Expand All @@ -306,22 +310,22 @@ class XMTPModule : Module() {
ClientWrapper.encodeToObj(randomClient)
}

AsyncFunction("createFromKeyBundle") { keyBundle: String, environment: String, appVersion: String?, enableV3: Boolean?, dbEncryptionKey: List<Int>?, dbDirectory: String?, historySyncUrl: String? ->
AsyncFunction("createFromKeyBundle") { keyBundle: String, dbEncryptionKey: List<Int>?, authParams: String ->
logV("createFromKeyBundle")

val authOptions = AuthParamsWrapper.authParamsFromJson(authParams)
try {
val context = if (enableV3 == true) context else null
val context = if (authOptions.enableV3) context else null
val encryptionKeyBytes =
dbEncryptionKey?.foldIndexed(ByteArray(dbEncryptionKey.size)) { i, a, v ->
a.apply { set(i, v.toByte()) }
}
val options = ClientOptions(
api = apiEnvironments(environment, appVersion),
enableV3 = enableV3 == true,
api = apiEnvironments(authOptions.environment, authOptions.appVersion),
enableV3 = authOptions.enableV3,
appContext = context,
dbEncryptionKey = encryptionKeyBytes,
dbDirectory = dbDirectory,
historySyncUrl = historySyncUrl
dbDirectory = authOptions.dbDirectory,
historySyncUrl = authOptions.historySyncUrl
)
val bundle =
PrivateKeyOuterClass.PrivateKeyBundle.parseFrom(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package expo.modules.xmtpreactnativesdk.wrappers

import com.google.gson.JsonParser

class AuthParamsWrapper(
val environment: String,
val appVersion: String?,
val enableV3: Boolean = false,
val dbDirectory: String?,
val historySyncUrl: String?,
) {
companion object {
fun authParamsFromJson(authParams: String): AuthParamsWrapper {
val jsonOptions = JsonParser.parseString(authParams).asJsonObject
return AuthParamsWrapper(
jsonOptions.get("environment").asString,
if (jsonOptions.has("appVersion")) jsonOptions.get("appVersion").asString else null,
if (jsonOptions.has("enableV3")) jsonOptions.get("enableV3").asBoolean else false,
if (jsonOptions.has("dbDirectory")) jsonOptions.get("dbDirectory").asString else null,
if (jsonOptions.has("historySyncUrl")) jsonOptions.get("historySyncUrl").asString else null
)
}
}
}
46 changes: 46 additions & 0 deletions ios/Wrappers/AuthParamsWrapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// AuthParamsWrapper.swift
// XMTPReactNative
//
// Created by Naomi Plasterer on 6/24/24.
//

import Foundation
import XMTP

class AuthParamsWrapper {
let environment: String
let appVersion: String?
let enableV3: Bool
let dbDirectory: String?
let historySyncUrl: String?

init(environment: String, appVersion: String?, enableV3: Bool, dbDirectory: String?, historySyncUrl: String?) {
self.environment = environment
self.appVersion = appVersion
self.enableV3 = enableV3
self.dbDirectory = dbDirectory
self.historySyncUrl = historySyncUrl
}

static func authParamsFromJson(_ authParams: String) -> AuthParamsWrapper? {
guard let data = authParams.data(using: .utf8),
let jsonOptions = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
return nil
}

let environment = jsonOptions["environment"] as? String ?? ""
let appVersion = jsonOptions["appVersion"] as? String
let enableV3 = jsonOptions["enableV3"] as? Bool ?? false
let dbDirectory = jsonOptions["dbDirectory"] as? String
let historySyncUrl = jsonOptions["historySyncUrl"] as? String

return AuthParamsWrapper(
environment: environment,
appVersion: appVersion,
enableV3: enableV3,
dbDirectory: dbDirectory,
historySyncUrl: historySyncUrl
)
}
}
49 changes: 25 additions & 24 deletions ios/XMTPModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,35 +137,33 @@ public class XMTPModule: Module {
//
// Auth functions
//
AsyncFunction("auth") {
{ (address: String, environment: String, appVersion: String?, hasCreateIdentityCallback: Bool?, hasEnableIdentityCallback: Bool?, enableV3: Bool?, dbEncryptionKey: [UInt8]?, dbDirectory: String?, historySyncUrl: String?) in

let signer = ReactNativeSigner(module: self, address: address)
self.signer = signer
if(hasCreateIdentityCallback ?? false) {
self.preCreateIdentityCallbackDeferred = DispatchSemaphore(value: 0)
}
if(hasEnableIdentityCallback ?? false) {
self.preEnableIdentityCallbackDeferred = DispatchSemaphore(value: 0)
}
let preCreateIdentityCallback: PreEventCallback? = hasCreateIdentityCallback ?? false ? self.preCreateIdentityCallback : nil
let preEnableIdentityCallback: PreEventCallback? = hasEnableIdentityCallback ?? false ? self.preEnableIdentityCallback : nil
let encryptionKeyData = dbEncryptionKey == nil ? nil : Data(dbEncryptionKey!)

let options = self.createClientConfig(env: environment, appVersion: appVersion, preEnableIdentityCallback: preEnableIdentityCallback, preCreateIdentityCallback: preCreateIdentityCallback, enableV3: enableV3 == true, dbEncryptionKey: encryptionKeyData, dbDirectory: dbDirectory, historySyncUrl: historySyncUrl)
let client = try await XMTP.Client.create(account: signer, options: options)
await self.clientsManager.updateClient(key: client.inboxID, client: client)
self.signer = nil
self.sendEvent("authed", try ClientWrapper.encodeToObj(client))
AsyncFunction("auth") { (address: String, hasCreateIdentityCallback: Bool?, hasEnableIdentityCallback: Bool?, dbEncryptionKey: [UInt8]?, authParams: String) in
let signer = ReactNativeSigner(module: self, address: address)
self.signer = signer
if(hasCreateIdentityCallback ?? false) {
self.preCreateIdentityCallbackDeferred = DispatchSemaphore(value: 0)
}
if(hasEnableIdentityCallback ?? false) {
self.preEnableIdentityCallbackDeferred = DispatchSemaphore(value: 0)
}
let preCreateIdentityCallback: PreEventCallback? = hasCreateIdentityCallback ?? false ? self.preCreateIdentityCallback : nil
let preEnableIdentityCallback: PreEventCallback? = hasEnableIdentityCallback ?? false ? self.preEnableIdentityCallback : nil
let encryptionKeyData = dbEncryptionKey == nil ? nil : Data(dbEncryptionKey!)
let authOptions = AuthParamsWrapper.authParamsFromJson(authParams)

let options = self.createClientConfig(env: authOptions.environment, appVersion: authOptions?.appVersion, preEnableIdentityCallback: preEnableIdentityCallback, preCreateIdentityCallback: preCreateIdentityCallback, enableV3: authOptions.enableV3, dbEncryptionKey: encryptionKeyData, dbDirectory: authOptions?.dbDirectory, historySyncUrl: authOptions?.historySyncUrl)
let client = try await XMTP.Client.create(account: signer, options: options)
await self.clientsManager.updateClient(key: client.inboxID, client: client)
self.signer = nil
self.sendEvent("authed", try ClientWrapper.encodeToObj(client))
}

Function("receiveSignature") { (requestID: String, signature: String) in
try signer?.handle(id: requestID, signature: signature)
}

// Generate a random wallet and set the client to that
AsyncFunction("createRandom") { (environment: String, appVersion: String?, hasCreateIdentityCallback: Bool?, hasEnableIdentityCallback: Bool?, enableV3: Bool?, dbEncryptionKey: [UInt8]?, dbDirectory: String?, historySyncUrl: String?) -> [String: String] in
AsyncFunction("createRandom") { (hasCreateIdentityCallback: Bool?, hasEnableIdentityCallback: Bool?, dbEncryptionKey: [UInt8]?, authParams: String) -> [String: String] in

let privateKey = try PrivateKey.generate()
if(hasCreateIdentityCallback ?? false) {
Expand All @@ -177,16 +175,17 @@ public class XMTPModule: Module {
let preCreateIdentityCallback: PreEventCallback? = hasCreateIdentityCallback ?? false ? self.preCreateIdentityCallback : nil
let preEnableIdentityCallback: PreEventCallback? = hasEnableIdentityCallback ?? false ? self.preEnableIdentityCallback : nil
let encryptionKeyData = dbEncryptionKey == nil ? nil : Data(dbEncryptionKey!)
let authOptions = AuthParamsWrapper.authParamsFromJson(authParams)

let options = createClientConfig(env: environment, appVersion: appVersion, preEnableIdentityCallback: preEnableIdentityCallback, preCreateIdentityCallback: preCreateIdentityCallback, enableV3: enableV3 == true, dbEncryptionKey: encryptionKeyData, dbDirectory: dbDirectory, historySyncUrl: historySyncUrl)
let options = createClientConfig(env: authOptions.environment, appVersion: authOptions.appVersion, preEnableIdentityCallback: preEnableIdentityCallback, preCreateIdentityCallback: preCreateIdentityCallback, enableV3: authOptions.enableV3, dbEncryptionKey: encryptionKeyData, dbDirectory: authOptions.dbDirectory, historySyncUrl: authOptions.historySyncUrl)
let client = try await Client.create(account: privateKey, options: options)

await clientsManager.updateClient(key: client.inboxID, client: client)
return try ClientWrapper.encodeToObj(client)
}

// Create a client using its serialized key bundle.
AsyncFunction("createFromKeyBundle") { (keyBundle: String, environment: String, appVersion: String?, enableV3: Bool?, dbEncryptionKey: [UInt8]?, dbDirectory: String?, historySyncUrl: String?) -> [String: String] in
AsyncFunction("createFromKeyBundle") { (keyBundle: String, dbEncryptionKey: [UInt8]?, authParams: String) -> [String: String] in

do {
guard let keyBundleData = Data(base64Encoded: keyBundle),
Expand All @@ -195,7 +194,9 @@ public class XMTPModule: Module {
throw Error.invalidKeyBundle
}
let encryptionKeyData = dbEncryptionKey == nil ? nil : Data(dbEncryptionKey!)
let options = createClientConfig(env: environment, appVersion: appVersion, enableV3: enableV3 == true, dbEncryptionKey: encryptionKeyData, dbDirectory: dbDirectory, historySyncUrl: historySyncUrl)
let authOptions = AuthParamsWrapper.authParamsFromJson(authParams)

let options = createClientConfig(env: authOptions.environment, appVersion: authOptions.appVersion, enableV3: authOptions.enableV3, dbEncryptionKey: encryptionKeyData, dbDirectory: authOptions.dbDirectory, historySyncUrl: authOptions.historySyncUrl)
let client = try await Client.from(bundle: bundle, options: options)
await clientsManager.updateClient(key: client.inboxID, client: client)
return try ClientWrapper.encodeToObj(client)
Expand Down
61 changes: 45 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export async function requestMessageHistorySync(inboxId: string) {
}

export async function auth(
inboxId: string,
address: string,
environment: 'local' | 'dev' | 'production',
appVersion?: string | undefined,
hasCreateIdentityCallback?: boolean | undefined,
Expand All @@ -80,16 +80,23 @@ export async function auth(
dbDirectory?: string | undefined,
historySyncUrl?: string | undefined
) {
return await XMTPModule.auth(
inboxId,
const encryptionKey = dbEncryptionKey
? Array.from(dbEncryptionKey)
: undefined

const authParams: AuthParams = {
environment,
appVersion,
hasCreateIdentityCallback,
hasEnableIdentityCallback,
enableV3,
dbEncryptionKey ? Array.from(dbEncryptionKey) : undefined,
dbDirectory,
historySyncUrl
historySyncUrl,
}
return await XMTPModule.auth(
address,
hasCreateIdentityCallback,
hasEnableIdentityCallback,
encryptionKey,
JSON.stringify(authParams)
)
}

Expand All @@ -107,15 +114,22 @@ export async function createRandom(
dbDirectory?: string | undefined,
historySyncUrl?: string | undefined
): Promise<string> {
return await XMTPModule.createRandom(
const encryptionKey = dbEncryptionKey
? Array.from(dbEncryptionKey)
: undefined

const authParams: AuthParams = {
environment,
appVersion,
hasCreateIdentityCallback,
hasEnableIdentityCallback,
enableV3,
dbEncryptionKey ? Array.from(dbEncryptionKey) : undefined,
dbDirectory,
historySyncUrl
historySyncUrl,
}
return await XMTPModule.createRandom(
hasCreateIdentityCallback,
hasEnableIdentityCallback,
encryptionKey,
JSON.stringify(authParams)
)
}

Expand All @@ -128,14 +142,21 @@ export async function createFromKeyBundle(
dbDirectory?: string | undefined,
historySyncUrl?: string | undefined
): Promise<string> {
return await XMTPModule.createFromKeyBundle(
keyBundle,
const encryptionKey = dbEncryptionKey
? Array.from(dbEncryptionKey)
: undefined

const authParams: AuthParams = {
environment,
appVersion,
enableV3,
dbEncryptionKey ? Array.from(dbEncryptionKey) : undefined,
dbDirectory,
historySyncUrl
historySyncUrl,
}
return await XMTPModule.createFromKeyBundle(
keyBundle,
encryptionKey,
JSON.stringify(authParams)
)
}

Expand Down Expand Up @@ -927,6 +948,14 @@ export async function processWelcomeMessage<

export const emitter = new EventEmitter(XMTPModule ?? NativeModulesProxy.XMTP)

interface AuthParams {
environment: string
appVersion?: string
enableV3?: boolean
dbDirectory?: string
historySyncUrl?: string
}

export * from './XMTP.types'
export { Client } from './lib/Client'
export * from './lib/ContentCodec'
Expand Down

0 comments on commit fae16ea

Please sign in to comment.