Skip to content

Commit

Permalink
Always set an inbox id for V2 (#275)
Browse files Browse the repository at this point in the history
* always set an inbox id even if V3 isnt enabled

* fix the example and the tests

* fix linter up'
git st
  • Loading branch information
nplasterer authored Jul 22, 2024
1 parent b403413 commit 13fbc95
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 144 deletions.
18 changes: 15 additions & 3 deletions example/src/main/java/org/xmtp/android/example/ClientManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,34 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.xmtp.android.example.utils.KeyUtil
import org.xmtp.android.library.Client
import org.xmtp.android.library.ClientOptions
import org.xmtp.android.library.XMTPEnvironment
import org.xmtp.android.library.codecs.GroupUpdatedCodec
import org.xmtp.android.library.messages.PrivateKeyBundleV1Builder
import org.xmtp.android.library.messages.walletAddress
import java.security.SecureRandom

object ClientManager {

fun clientOptions(appContext: Context?): ClientOptions {
fun clientOptions(appContext: Context, address: String): ClientOptions {
val keyUtil = KeyUtil(appContext)
var encryptionKey = keyUtil.retrieveKey(address)
if (encryptionKey == null || encryptionKey.isEmpty()) {
encryptionKey = SecureRandom().generateSeed(32)
keyUtil.storeKey(address, encryptionKey)
}

return ClientOptions(
api = ClientOptions.Api(
XMTPEnvironment.DEV,
appVersion = "XMTPAndroidExample/v1.0.0",
isSecure = true
),
enableV3 = true,
appContext = appContext
appContext = appContext,
dbEncryptionKey = encryptionKey
)
}

Expand All @@ -46,7 +57,8 @@ object ClientManager {
try {
val v1Bundle =
PrivateKeyBundleV1Builder.fromEncodedData(data = encodedPrivateKeyData)
_client = Client().buildFrom(v1Bundle, clientOptions(appContext))
_client =
Client().buildFrom(v1Bundle, clientOptions(appContext, v1Bundle.walletAddress))
Client.register(codec = GroupUpdatedCodec())
_clientState.value = ClientState.Ready
} catch (e: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
_uiState.value = ConnectUiState.Loading
try {
val wallet = PrivateKeyBuilder()
val client = Client().create(wallet, ClientManager.clientOptions(getApplication()))
val client = Client().create(wallet, ClientManager.clientOptions(getApplication(), wallet.address))
Client.register(codec = GroupUpdatedCodec())
_uiState.value = ConnectUiState.Success(
wallet.address,
Expand All @@ -111,7 +111,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
it.copy(showWallet = true, uri = uri)
}
}
val client = Client().create(wallet, ClientManager.clientOptions(getApplication()))
val client = Client().create(wallet, ClientManager.clientOptions(getApplication(), wallet.address))
Client.register(codec = GroupUpdatedCodec())
_uiState.value = ConnectUiState.Success(
wallet.address,
Expand Down
29 changes: 29 additions & 0 deletions example/src/main/java/org/xmtp/android/example/utils/KeyUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,43 @@ package org.xmtp.android.example.utils

import android.accounts.AccountManager
import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64.NO_WRAP
import android.util.Base64.decode
import android.util.Base64.encodeToString
import org.xmtp.android.example.R
import java.security.KeyStore
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey


class KeyUtil(val context: Context) {
private val PREFS_NAME = "EncryptionPref"
fun loadKeys(): String? {
val accountManager = AccountManager.get(context)
val accounts =
accountManager.getAccountsByType(context.getString(R.string.account_type))
val account = accounts.firstOrNull() ?: return null
return accountManager.getPassword(account)
}

fun storeKey(address: String, key: ByteArray?) {
val alias = "xmtp-dev-${address.lowercase()}"

val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val editor = prefs.edit()
editor.putString(alias, encodeToString(key, NO_WRAP))
editor.apply()
}

fun retrieveKey(address: String): ByteArray? {
val alias = "xmtp-dev-${address.lowercase()}"

val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val keyString = prefs.getString(alias, null)
return if (keyString != null) {
decode(keyString, NO_WRAP)
} else null
}
}
63 changes: 39 additions & 24 deletions library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ class ClientTest {
@Test
fun testTakesAWallet() {
val fakeWallet = PrivateKeyBuilder()
Client().create(account = fakeWallet)
runBlocking { Client().create(account = fakeWallet) }
}

@Test
fun testHasPrivateKeyBundleV1() {
val fakeWallet = PrivateKeyBuilder()
val client = Client().create(account = fakeWallet)
val client = runBlocking { Client().create(account = fakeWallet) }
assertEquals(1, client.privateKeyBundleV1.preKeysList?.size)
val preKey = client.privateKeyBundleV1.preKeysList?.get(0)
assert(preKey?.publicKey?.hasSignature() ?: false)
Expand All @@ -41,7 +41,7 @@ class ClientTest {
PrivateKeyOuterClass.PrivateKeyBundleV1.newBuilder().build().generate(wallet = wallet)
val encodedData = PrivateKeyBundleV1Builder.encodeData(v1)
val v1Copy = PrivateKeyBundleV1Builder.fromEncodedData(encodedData)
val client = Client().buildFrom(v1Copy)
val client = runBlocking { Client().buildFrom(v1Copy) }
assertEquals(
wallet.address,
client.address,
Expand All @@ -51,9 +51,9 @@ class ClientTest {
@Test
fun testCanBeCreatedWithBundle() {
val fakeWallet = PrivateKeyBuilder()
val client = Client().create(account = fakeWallet)
val client = runBlocking { Client().create(account = fakeWallet) }
val bundle = client.privateKeyBundle
val clientFromV1Bundle = Client().buildFromBundle(bundle)
val clientFromV1Bundle = runBlocking { Client().buildFromBundle(bundle) }
assertEquals(client.address, clientFromV1Bundle.address)
assertEquals(
client.privateKeyBundleV1.identityKey,
Expand All @@ -68,9 +68,9 @@ class ClientTest {
@Test
fun testCanBeCreatedWithV1Bundle() {
val fakeWallet = PrivateKeyBuilder()
val client = Client().create(account = fakeWallet)
val client = runBlocking { Client().create(account = fakeWallet) }
val bundleV1 = client.v1keys
val clientFromV1Bundle = Client().buildFromV1Bundle(bundleV1)
val clientFromV1Bundle = runBlocking { Client().buildFromV1Bundle(bundleV1) }
assertEquals(client.address, clientFromV1Bundle.address)
assertEquals(
client.privateKeyBundleV1.identityKey,
Expand All @@ -93,16 +93,18 @@ class ClientTest {
appContext = context,
dbEncryptionKey = key
)
val client =
val client = runBlocking {
Client().create(account = fakeWallet, options = options)
}

runBlocking {
client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) }
}

val bundle = client.privateKeyBundle
val clientFromV1Bundle =
val clientFromV1Bundle = runBlocking {
Client().buildFromBundle(bundle, options = options)
}
assertEquals(client.address, clientFromV1Bundle.address)
assertEquals(
client.privateKeyBundleV1.identityKey,
Expand All @@ -124,7 +126,7 @@ class ClientTest {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val client =
val client = runBlocking {
Client().create(
account = fakeWallet,
options = ClientOptions(
Expand All @@ -134,6 +136,7 @@ class ClientTest {
dbEncryptionKey = key
)
)
}
runBlocking {
client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) }
}
Expand All @@ -146,7 +149,7 @@ class ClientTest {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val fakeWallet2 = PrivateKeyBuilder()
var client =
var client = runBlocking {
Client().create(
account = fakeWallet,
options = ClientOptions(
Expand All @@ -156,7 +159,8 @@ class ClientTest {
dbEncryptionKey = key
)
)
val client2 =
}
val client2 = runBlocking {
Client().create(
account = fakeWallet2,
options = ClientOptions(
Expand All @@ -166,6 +170,7 @@ class ClientTest {
dbEncryptionKey = key
)
)
}

runBlocking {
client.conversations.newGroup(listOf(client2.address))
Expand All @@ -175,7 +180,7 @@ class ClientTest {

client.deleteLocalDatabase()

client =
client = runBlocking {
Client().create(
account = fakeWallet,
options = ClientOptions(
Expand All @@ -185,7 +190,7 @@ class ClientTest {
dbEncryptionKey = key
)
)

}
runBlocking {
client.conversations.syncGroups()
assertEquals(client.conversations.listGroups().size, 0)
Expand All @@ -197,7 +202,7 @@ class ClientTest {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val client =
val client = runBlocking {
Client().create(
account = fakeWallet,
options = ClientOptions(
Expand All @@ -207,6 +212,7 @@ class ClientTest {
dbEncryptionKey = key
)
)
}
runBlocking {
client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) }
}
Expand All @@ -217,7 +223,7 @@ class ClientTest {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val client =
val client = runBlocking {
Client().create(
account = fakeWallet,
options = ClientOptions(
Expand All @@ -227,6 +233,7 @@ class ClientTest {
dbEncryptionKey = key
)
)
}
runBlocking {
client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) }
}
Expand All @@ -235,7 +242,7 @@ class ClientTest {
@Test
fun testDoesNotCreateAV3Client() {
val fakeWallet = PrivateKeyBuilder()
val client = Client().create(account = fakeWallet)
val client = runBlocking { Client().create(account = fakeWallet) }
assertThrows("Error no V3 client initialized", XMTPException::class.java) {
runBlocking {
client.canMessageV3(listOf(client.address))[client.address]?.let { assert(!it) }
Expand All @@ -258,7 +265,9 @@ class ClientTest {
val aliceWallet = PrivateKeyBuilder()
val notOnNetwork = PrivateKeyBuilder()
val opts = ClientOptions(ClientOptions.Api(XMTPEnvironment.LOCAL, false))
val aliceClient = Client().create(aliceWallet, opts)
val aliceClient = runBlocking {
Client().create(aliceWallet, opts)
}
runBlocking { aliceClient.ensureUserContactPublished() }

val canMessage = runBlocking { Client.canMessage(aliceWallet.address, opts) }
Expand All @@ -283,7 +292,9 @@ class ClientTest {
)

try {
Client().create(account = fakeWallet, options = opts)
runBlocking {
Client().create(account = fakeWallet, options = opts)
}
expectation.get(5, TimeUnit.SECONDS)
} catch (e: Exception) {
fail("Error: $e")
Expand All @@ -305,7 +316,7 @@ class ClientTest {
)

try {
Client().create(account = fakeWallet, options = opts)
runBlocking { Client().create(account = fakeWallet, options = opts) }
expectation.get(5, TimeUnit.SECONDS)
} catch (e: Exception) {
fail("Error: $e")
Expand All @@ -318,7 +329,7 @@ class ClientTest {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val fakeWallet2 = PrivateKeyBuilder()
val boClient =
val boClient = runBlocking {
Client().create(
account = fakeWallet,
options = ClientOptions(
Expand All @@ -328,7 +339,8 @@ class ClientTest {
dbEncryptionKey = key
)
)
val alixClient =
}
val alixClient = runBlocking {
Client().create(
account = fakeWallet2,
options = ClientOptions(
Expand All @@ -338,6 +350,7 @@ class ClientTest {
dbEncryptionKey = key
)
)
}

runBlocking {
boClient.conversations.newGroup(listOf(alixClient.address))
Expand Down Expand Up @@ -368,7 +381,7 @@ class ClientTest {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val alixWallet = PrivateKeyBuilder()
val boWallet = PrivateKeyBuilder()
val alixClient =
val alixClient = runBlocking {
Client().create(
account = alixWallet,
options = ClientOptions(
Expand All @@ -378,7 +391,8 @@ class ClientTest {
dbEncryptionKey = key
)
)
val boClient =
}
val boClient = runBlocking {
Client().create(
account = boWallet,
options = ClientOptions(
Expand All @@ -388,6 +402,7 @@ class ClientTest {
dbEncryptionKey = key
)
)
}
val boInboxId = runBlocking {
alixClient.inboxIdFromAddress(boClient.address)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ class CodecTest {
val alix = PrivateKeyBuilder()
val clientOptions =
ClientOptions(api = ClientOptions.Api(env = XMTPEnvironment.LOCAL, isSecure = false))
val alixClient = Client().create(alix, clientOptions)
val alixClient = runBlocking { Client().create(alix, clientOptions) }
val conversations = mutableListOf<Conversation>()
repeat(5) {
val account = PrivateKeyBuilder()
val client = Client().create(account, clientOptions)
val client = runBlocking { Client().create(account, clientOptions) }
runBlocking {
conversations.add(
alixClient.conversations.newConversation(
Expand Down
Loading

0 comments on commit 13fbc95

Please sign in to comment.