Skip to content

Commit

Permalink
Improve V3 Client Create (#183)
Browse files Browse the repository at this point in the history
* add dates to example and a test around removing members

* allow passing of encryption key and database path

* feat: fix up the tests

* fix linter
  • Loading branch information
nplasterer authored Feb 20, 2024
1 parent 78c26eb commit 6f8209f
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
)
}

Expand All @@ -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
Expand All @@ -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
Expand Down
72 changes: 44 additions & 28 deletions library/src/main/java/org/xmtp/android/library/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"
Expand Down Expand Up @@ -296,40 +298,52 @@ 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(
logger = logger,
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()
Expand Down Expand Up @@ -564,10 +578,12 @@ class Client() {
return runBlocking { query(Topic.contact(peerAddress)).envelopesList.size > 0 }
}

fun canMessage(addresses: List<String>): Boolean {
return runBlocking {
libXMTPClient != null && !libXMTPClient!!.canMessage(addresses).contains(false)
fun canMessageV3(addresses: List<String>): Boolean {
if (libXMTPClient == null) return false
val statuses = runBlocking {
libXMTPClient!!.canMessage(addresses)
}
return !statuses.contains(false)
}

val privateKeyBundle: PrivateKeyBundle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand Down

0 comments on commit 6f8209f

Please sign in to comment.