diff --git a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt index b313bad6b..d75ef654b 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt @@ -3,7 +3,6 @@ package org.xmtp.android.library import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull import org.junit.Assert.fail import org.junit.Ignore import org.junit.Test @@ -91,10 +90,7 @@ class ClientTest { ) val client = Client().create(account = fakeWallet, options = options) - assertEquals( - client.address.lowercase(), - client.libXMTPClient?.accountAddress()?.lowercase() - ) + assert(client.canMessageV3(listOf(client.address))) val bundle = client.privateKeyBundle val clientFromV1Bundle = Client().buildFromBundle(bundle, account = fakeWallet, options = options) @@ -103,9 +99,12 @@ class ClientTest { client.privateKeyBundleV1.identityKey, clientFromV1Bundle.privateKeyBundleV1.identityKey, ) + + assert(clientFromV1Bundle.canMessageV3(listOf(client.address))) + assertEquals( - client.libXMTPClient?.accountAddress(), - clientFromV1Bundle.libXMTPClient?.accountAddress() + client.address, + clientFromV1Bundle.address ) } @@ -122,8 +121,7 @@ class ClientTest { appContext = context ) ) - val v3Client = client.libXMTPClient - assertEquals(client.address.lowercase(), v3Client?.accountAddress()?.lowercase()) + assert(client.canMessageV3(listOf(client.address))) } @Test @@ -139,16 +137,14 @@ class ClientTest { appContext = context ) ) - val v3Client = client.libXMTPClient - assertEquals(client.address.lowercase(), v3Client?.accountAddress()?.lowercase()) + assert(client.canMessageV3(listOf(client.address))) } @Test fun testDoesNotCreateAV3Client() { val fakeWallet = PrivateKeyBuilder() val client = Client().create(account = fakeWallet) - val v3Client = client.libXMTPClient - assertNull(v3Client) + assert(!client.canMessageV3(listOf(client.address))) } @Test diff --git a/library/src/main/java/org/xmtp/android/library/Client.kt b/library/src/main/java/org/xmtp/android/library/Client.kt index fb48b8f4d..568e27e22 100644 --- a/library/src/main/java/org/xmtp/android/library/Client.kt +++ b/library/src/main/java/org/xmtp/android/library/Client.kt @@ -66,6 +66,8 @@ data class ClientOptions( val preEnableIdentityCallback: PreEventCallback? = null, val appContext: Context? = null, val enableAlphaMls: Boolean = false, + val dbPath: String? = null, + val dbEncryptionKey: ByteArray? = null, ) { data class Api( val env: XMTPEnvironment = XMTPEnvironment.DEV, @@ -81,8 +83,8 @@ class Client() { lateinit var contacts: Contacts lateinit var conversations: Conversations var logger: XMTPLogger = XMTPLogger() - var libXMTPClient: FfiXmtpClient? = null val libXMTPVersion: String = getVersionInfo() + private var libXMTPClient: FfiXmtpClient? = null companion object { private const val TAG = "Client" @@ -296,32 +298,44 @@ class Client() { if (isAlphaMlsEnabled(options)) { val alias = "xmtp-${options!!.api.env}-${accountAddress.lowercase()}" - val dbDir = File(appContext?.filesDir?.absolutePath, "xmtp_db") - dbDir.mkdir() - val dbPath: String = dbDir.absolutePath + "/$alias.db3" - - val keyStore = KeyStore.getInstance("AndroidKeyStore") - withContext(Dispatchers.IO) { - keyStore.load(null) + val dbPath = if (options.dbPath == null) { + val dbDir = File(appContext?.filesDir?.absolutePath, "xmtp_db") + dbDir.mkdir() + dbDir.absolutePath + "/$alias.db3" + } else { + options.dbPath } - val entry = keyStore.getEntry(alias, null) - - val retrievedKey: SecretKey = if (entry is KeyStore.SecretKeyEntry) { - entry.secretKey + val encryptionKey = if (options.dbEncryptionKey == null) { + val keyStore = KeyStore.getInstance("AndroidKeyStore") + withContext(Dispatchers.IO) { + keyStore.load(null) + } + + val entry = keyStore.getEntry(alias, null) + + val retrievedKey: SecretKey = if (entry is KeyStore.SecretKeyEntry) { + entry.secretKey + } else { + val keyGenerator = + KeyGenerator.getInstance( + KeyProperties.KEY_ALGORITHM_AES, + "AndroidKeyStore" + ) + val keyGenParameterSpec = KeyGenParameterSpec.Builder( + alias, + KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT + ).setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .setKeySize(256) + .build() + + keyGenerator.init(keyGenParameterSpec) + keyGenerator.generateKey() + } + retrievedKey.encoded } else { - val keyGenerator = - KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") - val keyGenParameterSpec = KeyGenParameterSpec.Builder( - alias, - KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT - ).setBlockModes(KeyProperties.BLOCK_MODE_GCM) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) - .setKeySize(256) - .build() - - keyGenerator.init(keyGenParameterSpec) - keyGenerator.generateKey() + options.dbEncryptionKey } createClient( @@ -329,7 +343,7 @@ class Client() { host = if (options.api.env == XMTPEnvironment.LOCAL) "http://${options.api.env.getValue()}:5556" else "https://${options.api.env.getValue()}:443", isSecure = options.api.isSecure, db = dbPath, - encryptionKey = retrievedKey.encoded, + encryptionKey = encryptionKey, accountAddress = accountAddress, legacyIdentitySource = legacyIdentitySource, legacySignedPrivateKeyProto = privateKeyBundleV1.toV2().identityKey.toByteArray() @@ -564,10 +578,12 @@ class Client() { return runBlocking { query(Topic.contact(peerAddress)).envelopesList.size > 0 } } - fun canMessage(addresses: List): Boolean { - return runBlocking { - libXMTPClient != null && !libXMTPClient!!.canMessage(addresses).contains(false) + fun canMessageV3(addresses: List): Boolean { + if (libXMTPClient == null) return false + val statuses = runBlocking { + libXMTPClient!!.canMessage(addresses) } + return !statuses.contains(false) } val privateKeyBundle: PrivateKeyBundle diff --git a/library/src/main/java/org/xmtp/android/library/Conversations.kt b/library/src/main/java/org/xmtp/android/library/Conversations.kt index b171b7849..428815918 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversations.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversations.kt @@ -104,7 +104,7 @@ data class Conversations( ) { throw XMTPException("Recipient is sender") } - if (!client.canMessage(accountAddresses)) { + if (!client.canMessageV3(accountAddresses)) { throw XMTPException("Recipient not on network") }