diff --git a/example/src/main/java/org/xmtp/android/example/ClientManager.kt b/example/src/main/java/org/xmtp/android/example/ClientManager.kt index 19820ef88..725549d9d 100644 --- a/example/src/main/java/org/xmtp/android/example/ClientManager.kt +++ b/example/src/main/java/org/xmtp/android/example/ClientManager.kt @@ -12,7 +12,6 @@ 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 @@ -20,11 +19,8 @@ object ClientManager { 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) - } + val encryptionKey = keyUtil.retrieveKey(address)?.takeUnless { it.isEmpty() } + ?: SecureRandom().generateSeed(32).also { keyUtil.storeKey(address, it) } return ClientOptions( api = ClientOptions.Api( @@ -32,7 +28,6 @@ object ClientManager { appVersion = "XMTPAndroidExample/v1.0.0", isSecure = true ), - enableV3 = true, appContext = appContext, dbEncryptionKey = encryptionKey ) @@ -51,14 +46,12 @@ object ClientManager { } @UiThread - fun createClient(encodedPrivateKeyData: String, appContext: Context) { + fun createClient(address: String, appContext: Context) { if (clientState.value is ClientState.Ready) return GlobalScope.launch(Dispatchers.IO) { try { - val v1Bundle = - PrivateKeyBundleV1Builder.fromEncodedData(data = encodedPrivateKeyData) _client = - Client().buildFrom(v1Bundle, clientOptions(appContext, v1Bundle.walletAddress)) + Client().build(address, clientOptions(appContext, address)) Client.register(codec = GroupUpdatedCodec()) _clientState.value = ClientState.Ready } catch (e: Exception) { diff --git a/example/src/main/java/org/xmtp/android/example/MainActivity.kt b/example/src/main/java/org/xmtp/android/example/MainActivity.kt index 239a36a89..2c05d2eb2 100644 --- a/example/src/main/java/org/xmtp/android/example/MainActivity.kt +++ b/example/src/main/java/org/xmtp/android/example/MainActivity.kt @@ -128,7 +128,7 @@ class MainActivity : AppCompatActivity(), ConversationDetailActivity.intent( this, topic = conversation.topic, - peerAddress = conversation.peerAddress + peerAddress = conversation.id ) ) } diff --git a/example/src/main/java/org/xmtp/android/example/MainViewModel.kt b/example/src/main/java/org/xmtp/android/example/MainViewModel.kt index ffaa068ac..ec57cb807 100644 --- a/example/src/main/java/org/xmtp/android/example/MainViewModel.kt +++ b/example/src/main/java/org/xmtp/android/example/MainViewModel.kt @@ -45,7 +45,7 @@ class MainViewModel : ViewModel() { viewModelScope.launch(Dispatchers.IO) { val listItems = mutableListOf() try { - val conversations = ClientManager.client.conversations.list(includeGroups = true) + val conversations = ClientManager.client.conversations.list() val hmacKeysResult = ClientManager.client.conversations.getHmacKeys() val subscriptions: MutableList = conversations.map { val hmacKeys = hmacKeysResult.hmacKeysMap @@ -61,7 +61,6 @@ class MainViewModel : ViewModel() { sub.addAllHmacKeys(result) } sub.topic = it.topic - sub.isSilent = it.version == Conversation.Version.V1 }.build() }.toMutableList() @@ -105,7 +104,7 @@ class MainViewModel : ViewModel() { val stream: StateFlow = stateFlow(viewModelScope, null) { subscriptionCount -> if (ClientManager.clientState.value is ClientManager.ClientState.Ready) { - ClientManager.client.conversations.streamAll() + ClientManager.client.conversations.stream() .flowWhileShared( subscriptionCount, SharingStarted.WhileSubscribed(1000L) diff --git a/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletFragment.kt b/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletFragment.kt index 711736eae..f3b2de2ff 100644 --- a/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletFragment.kt +++ b/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletFragment.kt @@ -81,10 +81,7 @@ class ConnectWalletFragment : Fragment() { when (uiState) { is ConnectWalletViewModel.ConnectUiState.Error -> showError(uiState.message) ConnectWalletViewModel.ConnectUiState.Loading -> showLoading() - is ConnectWalletViewModel.ConnectUiState.Success -> signIn( - uiState.address, - uiState.encodedKeyData - ) + is ConnectWalletViewModel.ConnectUiState.Success -> signIn(uiState.address) ConnectWalletViewModel.ConnectUiState.Unknown -> Unit } @@ -103,10 +100,10 @@ class ConnectWalletFragment : Fragment() { } } - private fun signIn(address: String, encodedKey: String) { + private fun signIn(address: String) { val accountManager = AccountManager.get(requireContext()) Account(address, resources.getString(R.string.account_type)).also { account -> - accountManager.addAccountExplicitly(account, encodedKey, null) + accountManager.addAccountExplicitly(account, address, null) } requireActivity().startActivity(Intent(requireActivity(), MainActivity::class.java)) requireActivity().finish() diff --git a/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletViewModel.kt b/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletViewModel.kt index b773b5e88..627947746 100644 --- a/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletViewModel.kt +++ b/example/src/main/java/org/xmtp/android/example/connect/ConnectWalletViewModel.kt @@ -21,7 +21,6 @@ import org.xmtp.android.library.Client import org.xmtp.android.library.XMTPException import org.xmtp.android.library.codecs.GroupUpdatedCodec import org.xmtp.android.library.messages.PrivateKeyBuilder -import org.xmtp.android.library.messages.PrivateKeyBundleV1Builder class ConnectWalletViewModel(application: Application) : AndroidViewModel(application) { @@ -89,8 +88,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic val client = Client().create(wallet, ClientManager.clientOptions(getApplication(), wallet.address)) Client.register(codec = GroupUpdatedCodec()) _uiState.value = ConnectUiState.Success( - wallet.address, - PrivateKeyBundleV1Builder.encodeData(client.v1keys) + wallet.address ) } catch (e: XMTPException) { _uiState.value = ConnectUiState.Error(e.message.orEmpty()) @@ -114,8 +112,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic val client = Client().create(wallet, ClientManager.clientOptions(getApplication(), wallet.address)) Client.register(codec = GroupUpdatedCodec()) _uiState.value = ConnectUiState.Success( - wallet.address, - PrivateKeyBundleV1Builder.encodeData(client.v1keys) + wallet.address ) } catch (e: Exception) { _uiState.value = ConnectUiState.Error(e.message.orEmpty()) @@ -132,7 +129,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic sealed class ConnectUiState { object Unknown : ConnectUiState() object Loading : ConnectUiState() - data class Success(val address: String, val encodedKeyData: String) : ConnectUiState() + data class Success(val address: String) : ConnectUiState() data class Error(val message: String) : ConnectUiState() } diff --git a/example/src/main/java/org/xmtp/android/example/conversation/ConversationDetailViewModel.kt b/example/src/main/java/org/xmtp/android/example/conversation/ConversationDetailViewModel.kt index a9444e979..98df784d8 100644 --- a/example/src/main/java/org/xmtp/android/example/conversation/ConversationDetailViewModel.kt +++ b/example/src/main/java/org/xmtp/android/example/conversation/ConversationDetailViewModel.kt @@ -51,10 +51,7 @@ class ConversationDetailViewModel(private val savedStateHandle: SavedStateHandle val listItems = mutableListOf() try { if (conversation == null) { - conversation = ClientManager.client.fetchConversation( - conversationTopic, - includeGroups = true - ) + conversation = ClientManager.client.findConversationByTopic(conversationTopic!!) } conversation?.let { if (conversation is Conversation.Group) { @@ -79,10 +76,7 @@ class ConversationDetailViewModel(private val savedStateHandle: SavedStateHandle if (conversation == null) { conversation = runBlocking { - ClientManager.client.fetchConversation( - conversationTopic, - includeGroups = false - ) + ClientManager.client.findConversationByTopic(conversationTopic!!) } } if (conversation != null) { diff --git a/example/src/main/java/org/xmtp/android/example/conversation/ConversationViewHolder.kt b/example/src/main/java/org/xmtp/android/example/conversation/ConversationViewHolder.kt index 34a1ab895..fa76a042e 100644 --- a/example/src/main/java/org/xmtp/android/example/conversation/ConversationViewHolder.kt +++ b/example/src/main/java/org/xmtp/android/example/conversation/ConversationViewHolder.kt @@ -27,14 +27,7 @@ class ConversationViewHolder( fun bind(item: MainViewModel.MainListItem.ConversationItem) { conversation = item.conversation - binding.peerAddress.text = if (item.conversation.peerAddress.contains(",")) { - val addresses = item.conversation.peerAddress.split(",") - addresses.joinToString(" & ") { - it.truncatedAddress() - } - } else { - item.conversation.peerAddress.truncatedAddress() - } + binding.peerAddress.text = item.conversation.id.truncatedAddress() val messageBody: String = if (item.mostRecentMessage?.content() is String) { item.mostRecentMessage.body.orEmpty() diff --git a/example/src/main/java/org/xmtp/android/example/conversation/NewConversationBottomSheet.kt b/example/src/main/java/org/xmtp/android/example/conversation/NewConversationBottomSheet.kt index 512ea892c..3aa293e22 100644 --- a/example/src/main/java/org/xmtp/android/example/conversation/NewConversationBottomSheet.kt +++ b/example/src/main/java/org/xmtp/android/example/conversation/NewConversationBottomSheet.kt @@ -81,7 +81,7 @@ class NewConversationBottomSheet : BottomSheetDialogFragment() { ConversationDetailActivity.intent( requireContext(), topic = uiState.conversation.topic, - peerAddress = uiState.conversation.peerAddress + peerAddress = uiState.conversation.id ) ) dismiss() diff --git a/example/src/main/java/org/xmtp/android/example/conversation/NewGroupBottomSheet.kt b/example/src/main/java/org/xmtp/android/example/conversation/NewGroupBottomSheet.kt index 300f00530..aad1710a9 100644 --- a/example/src/main/java/org/xmtp/android/example/conversation/NewGroupBottomSheet.kt +++ b/example/src/main/java/org/xmtp/android/example/conversation/NewGroupBottomSheet.kt @@ -97,7 +97,7 @@ class NewGroupBottomSheet : BottomSheetDialogFragment() { ConversationDetailActivity.intent( requireContext(), topic = uiState.conversation.topic, - peerAddress = uiState.conversation.peerAddress + peerAddress = uiState.conversation.id ) ) dismiss() diff --git a/example/src/main/java/org/xmtp/android/example/pushnotifications/PushNotificationsService.kt b/example/src/main/java/org/xmtp/android/example/pushnotifications/PushNotificationsService.kt index 7fb476c7f..1b11d33f6 100644 --- a/example/src/main/java/org/xmtp/android/example/pushnotifications/PushNotificationsService.kt +++ b/example/src/main/java/org/xmtp/android/example/pushnotifications/PushNotificationsService.kt @@ -20,11 +20,8 @@ import org.xmtp.android.example.R import org.xmtp.android.example.conversation.ConversationDetailActivity import org.xmtp.android.example.extension.truncatedAddress import org.xmtp.android.example.utils.KeyUtil -import org.xmtp.android.library.Conversation import org.xmtp.android.library.codecs.GroupUpdated -import org.xmtp.android.library.messages.EnvelopeBuilder import org.xmtp.android.library.messages.Topic -import java.util.Date class PushNotificationsService : FirebaseMessagingService() { @@ -70,14 +67,14 @@ class PushNotificationsService : FirebaseMessagingService() { ConversationDetailActivity.intent( this, topic = group.topic, - peerAddress = Conversation.Group(group).peerAddress + peerAddress = group.id ), (PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) ) NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_xmtp_white) - .setContentTitle(Conversation.Group(group).peerAddress.truncatedAddress()) + .setContentTitle(group.id.truncatedAddress()) .setContentText("New Group Chat") .setAutoCancel(true) .setColor(ContextCompat.getColor(this, R.color.black)) @@ -86,19 +83,15 @@ class PushNotificationsService : FirebaseMessagingService() { .setContentIntent(pendingIntent) } else { val conversation = - runBlocking { ClientManager.client.fetchConversation(topic, includeGroups = true) } + runBlocking { ClientManager.client.findConversationByTopic(topic) } if (conversation == null) { Log.e(TAG, topic) Log.e(TAG, "No keys or conversation persisted") return } - val decodedMessage = if (conversation is Conversation.Group) { - runBlocking { conversation.group.processMessage(encryptedMessageData).decode() } - } else { - val envelope = EnvelopeBuilder.buildFromString(topic, Date(), encryptedMessageData) - conversation.decode(envelope) - } - val peerAddress = conversation.peerAddress + val decodedMessage = + runBlocking { conversation.processMessage(encryptedMessageData).decode() } + val peerAddress = conversation.id val body: String = if (decodedMessage.content() is String) { decodedMessage.body diff --git a/example/src/main/java/org/xmtp/android/example/utils/KeyUtil.kt b/example/src/main/java/org/xmtp/android/example/utils/KeyUtil.kt index 88c065623..0061913d1 100644 --- a/example/src/main/java/org/xmtp/android/example/utils/KeyUtil.kt +++ b/example/src/main/java/org/xmtp/android/example/utils/KeyUtil.kt @@ -23,12 +23,12 @@ class KeyUtil(val context: Context) { return accountManager.getPassword(account) } - fun storeKey(address: String, key: ByteArray?) { + fun storeKey(address: String, dbEncryptionKey: 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.putString(alias, encodeToString(dbEncryptionKey, NO_WRAP)) editor.apply() } diff --git a/library/build.gradle b/library/build.gradle index 886ffba89..bea9cc977 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -92,6 +92,7 @@ dependencies { api 'org.xmtp:proto-kotlin:3.71.0' testImplementation 'junit:junit:4.13.2' + testImplementation 'androidx.test:monitor:1.7.2' androidTestImplementation 'app.cash.turbine:turbine:1.1.0' androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0' androidTestImplementation 'androidx.test.ext:junit:1.1.5' diff --git a/library/src/androidTest/java/org/xmtp/android/library/AttachmentTest.kt b/library/src/androidTest/java/org/xmtp/android/library/AttachmentTest.kt index d42908f33..8dac7c006 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/AttachmentTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/AttachmentTest.kt @@ -24,9 +24,9 @@ class AttachmentTest { Client.register(codec = AttachmentCodec()) val fixtures = fixtures() - val aliceClient = fixtures.aliceClient + val aliceClient = fixtures.alixClient val aliceConversation = runBlocking { - aliceClient.conversations.newConversation(fixtures.bob.walletAddress) + aliceClient.conversations.newConversation(fixtures.bo.walletAddress) } runBlocking { @@ -36,8 +36,8 @@ class AttachmentTest { ) } val messages = runBlocking { aliceConversation.messages() } - assertEquals(messages.size, 1) - if (messages.size == 1) { + assertEquals(messages.size, 2) + if (messages.size == 2) { val content: Attachment? = messages[0].content() assertEquals("test.txt", content?.filename) assertEquals("text/plain", content?.mimeType) 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 15f221f67..3d512f8c5 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt @@ -9,9 +9,6 @@ import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.messages.PrivateKeyBuilder -import org.xmtp.android.library.messages.PrivateKeyBundleV1Builder -import org.xmtp.android.library.messages.generate -import org.xmtp.proto.message.contents.PrivateKeyOuterClass import uniffi.xmtpv3.GenericException import java.security.SecureRandom import java.util.concurrent.CompletableFuture @@ -19,77 +16,13 @@ import java.util.concurrent.TimeUnit @RunWith(AndroidJUnit4::class) class ClientTest { - @Test - fun testTakesAWallet() { - val fakeWallet = PrivateKeyBuilder() - runBlocking { Client().create(account = fakeWallet) } - } - - @Test - fun testHasPrivateKeyBundleV1() { - val fakeWallet = PrivateKeyBuilder() - val client = runBlocking { Client().create(account = fakeWallet) } - assertEquals(1, client.v1keys.preKeysList?.size) - val preKey = client.v1keys.preKeysList?.get(0) - assert(preKey?.publicKey?.hasSignature() ?: false) - } - - @Test - fun testSerialization() { - val wallet = PrivateKeyBuilder() - val v1 = - PrivateKeyOuterClass.PrivateKeyBundleV1.newBuilder().build().generate(wallet = wallet) - val encodedData = PrivateKeyBundleV1Builder.encodeData(v1) - val v1Copy = PrivateKeyBundleV1Builder.fromEncodedData(encodedData) - val client = runBlocking { Client().buildFrom(v1Copy) } - assertEquals( - wallet.address, - client.address, - ) - } - @Test fun testCanBeCreatedWithBundle() { - val fakeWallet = PrivateKeyBuilder() - val client = runBlocking { Client().create(account = fakeWallet) } - val bundle = client.privateKeyBundle - val clientFromV1Bundle = runBlocking { Client().buildFromBundle(bundle) } - assertEquals(client.address, clientFromV1Bundle.address) - assertEquals( - client.v1keys.identityKey, - clientFromV1Bundle.v1keys.identityKey, - ) - assertEquals( - client.v1keys.preKeysList, - clientFromV1Bundle.v1keys.preKeysList, - ) - } - - @Test - fun testCanBeCreatedWithV1Bundle() { - val fakeWallet = PrivateKeyBuilder() - val client = runBlocking { Client().create(account = fakeWallet) } - val bundleV1 = client.v1keys - val clientFromV1Bundle = runBlocking { Client().buildFromV1Bundle(bundleV1) } - assertEquals(client.address, clientFromV1Bundle.address) - assertEquals( - client.v1keys.identityKey, - clientFromV1Bundle.v1keys.identityKey, - ) - assertEquals( - client.v1keys.preKeysList, - clientFromV1Bundle.v1keys.preKeysList, - ) - } - - @Test - fun testV3CanBeCreatedWithBundle() { val key = SecureRandom().generateSeed(32) val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() val options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -98,37 +31,27 @@ class ClientTest { } runBlocking { - client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) } + client.canMessage(listOf(client.address))[client.address]?.let { assert(it) } } - val bundle = client.privateKeyBundle - val clientFromV1Bundle = runBlocking { - Client().buildFromBundle(bundle, options = options) + val fromBundle = runBlocking { + Client().build(fakeWallet.address, options = options) } - assertEquals(client.address, clientFromV1Bundle.address) - assertEquals( - client.v1keys.identityKey, - clientFromV1Bundle.v1keys.identityKey, - ) + assertEquals(client.address, fromBundle.address) + assertEquals(client.inboxId, fromBundle.inboxId) runBlocking { - clientFromV1Bundle.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) } + fromBundle.canMessage(listOf(client.address))[client.address]?.let { assert(it) } } - - assertEquals( - client.address, - clientFromV1Bundle.address - ) } @Test - fun testCreatesAV3Client() { + fun testCreatesAClient() { val key = SecureRandom().generateSeed(32) val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() val options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -140,49 +63,12 @@ class ClientTest { ) } runBlocking { - client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) } + client.canMessage(listOf(client.address))[client.address]?.let { assert(it) } } assert(client.installationId.isNotEmpty()) assertEquals(inboxId, client.inboxId) } - @Test - fun testCreatesAV3OnlyClient() { - val key = SecureRandom().generateSeed(32) - val context = InstrumentationRegistry.getInstrumentation().targetContext - val fakeWallet = PrivateKeyBuilder() - val options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - val inboxId = runBlocking { Client.getOrCreateInboxId(options, fakeWallet.address) } - val client = runBlocking { - Client().createV3( - account = fakeWallet, - options = options - ) - } - runBlocking { - client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) } - } - assert(client.installationId.isNotEmpty()) - assertEquals(inboxId, client.inboxId) - - val sameClient = runBlocking { - Client().buildV3( - address = fakeWallet.address, - options = options - ) - } - runBlocking { - client.canMessageV3(listOf(sameClient.address))[sameClient.address]?.let { assert(it) } - } - assert(sameClient.installationId.isNotEmpty()) - assertEquals(client.inboxId, sameClient.inboxId) - } - @Test fun testCanDeleteDatabase() { val key = SecureRandom().generateSeed(32) @@ -194,7 +80,6 @@ class ClientTest { account = fakeWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -205,7 +90,6 @@ class ClientTest { account = fakeWallet2, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -226,7 +110,6 @@ class ClientTest { account = fakeWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -239,7 +122,7 @@ class ClientTest { } @Test - fun testCreatesAV3DevClient() { + fun testCreatesADevClient() { val key = SecureRandom().generateSeed(32) val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() @@ -248,19 +131,18 @@ class ClientTest { account = fakeWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.DEV, true), - enableV3 = true, appContext = context, dbEncryptionKey = key ) ) } runBlocking { - client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) } + client.canMessage(listOf(client.address))[client.address]?.let { assert(it) } } } @Test - fun testCreatesAV3ProductionClient() { + fun testCreatesAProductionClient() { val key = SecureRandom().generateSeed(32) val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() @@ -269,98 +151,13 @@ class ClientTest { account = fakeWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.PRODUCTION, true), - enableV3 = true, appContext = context, dbEncryptionKey = key ) ) } runBlocking { - client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) } - } - } - - @Test - fun testDoesNotCreateAV3Client() { - val fakeWallet = PrivateKeyBuilder() - 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) } - } - } - } - - @Test - fun testCanMessage() { - val fixtures = fixtures() - val notOnNetwork = PrivateKeyBuilder() - val canMessage = runBlocking { fixtures.aliceClient.canMessage(fixtures.bobClient.address) } - val cannotMessage = runBlocking { fixtures.aliceClient.canMessage(notOnNetwork.address) } - assert(canMessage) - assert(!cannotMessage) - } - - @Test - fun testPublicCanMessage() { - val aliceWallet = PrivateKeyBuilder() - val notOnNetwork = PrivateKeyBuilder() - val opts = ClientOptions(ClientOptions.Api(XMTPEnvironment.LOCAL, false)) - val aliceClient = runBlocking { - Client().create(aliceWallet, opts) - } - runBlocking { aliceClient.ensureUserContactPublished() } - - val canMessage = runBlocking { Client.canMessage(aliceWallet.address, opts) } - val cannotMessage = runBlocking { Client.canMessage(notOnNetwork.address, opts) } - - assert(canMessage) - assert(!cannotMessage) - } - - @Test - fun testPreEnableIdentityCallback() { - val fakeWallet = PrivateKeyBuilder() - val expectation = CompletableFuture() - - val preEnableIdentityCallback: suspend () -> Unit = { - expectation.complete(Unit) - } - - val opts = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - preEnableIdentityCallback = preEnableIdentityCallback - ) - - try { - runBlocking { - Client().create(account = fakeWallet, options = opts) - } - expectation.get(5, TimeUnit.SECONDS) - } catch (e: Exception) { - fail("Error: $e") - } - } - - @Test - fun testPreCreateIdentityCallback() { - val fakeWallet = PrivateKeyBuilder() - val expectation = CompletableFuture() - - val preCreateIdentityCallback: suspend () -> Unit = { - expectation.complete(Unit) - } - - val opts = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - preCreateIdentityCallback = preCreateIdentityCallback - ) - - try { - runBlocking { Client().create(account = fakeWallet, options = opts) } - expectation.get(5, TimeUnit.SECONDS) - } catch (e: Exception) { - fail("Error: $e") + client.canMessage(listOf(client.address))[client.address]?.let { assert(it) } } } @@ -378,7 +175,6 @@ class ClientTest { val opts = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), preAuthenticateToInboxCallback = preAuthenticateToInboxCallback, - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -402,7 +198,6 @@ class ClientTest { account = fakeWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -413,7 +208,6 @@ class ClientTest { account = fakeWallet2, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -454,7 +248,6 @@ class ClientTest { account = alixWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -465,7 +258,6 @@ class ClientTest { account = boWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -487,7 +279,6 @@ class ClientTest { account = alixWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -499,7 +290,6 @@ class ClientTest { account = alixWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -513,7 +303,6 @@ class ClientTest { account = alixWallet, options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) diff --git a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt index 1f65c045e..b25d160af 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -49,9 +49,9 @@ class CodecTest { fun testCanRoundTripWithCustomContentType() { Client.register(codec = NumberCodec()) val fixtures = fixtures() - val aliceClient = fixtures.aliceClient + val aliceClient = fixtures.alixClient val aliceConversation = runBlocking { - aliceClient.conversations.newConversation(fixtures.bob.walletAddress) + aliceClient.conversations.newConversation(fixtures.bo.walletAddress) } runBlocking { aliceConversation.send( @@ -60,8 +60,8 @@ class CodecTest { ) } val messages = runBlocking { aliceConversation.messages() } - assertEquals(messages.size, 1) - if (messages.size == 1) { + assertEquals(messages.size, 2) + if (messages.size == 2) { val content: Double? = messages[0].content() assertEquals(3.14, content) assertEquals("Error: This app does not support numbers.", messages[0].fallbackContent) diff --git a/library/src/androidTest/java/org/xmtp/android/library/ContactsTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ContactsTest.kt deleted file mode 100644 index bceb66c4d..000000000 --- a/library/src/androidTest/java/org/xmtp/android/library/ContactsTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -package org.xmtp.android.library - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith -import org.xmtp.android.library.messages.walletAddress - -@RunWith(AndroidJUnit4::class) -class ContactsTest { - - @Test - fun testNormalizesAddresses() { - val fixtures = fixtures() - runBlocking { fixtures.bobClient.ensureUserContactPublished() } - val bobAddressLowerCased = fixtures.bobClient.address.lowercase() - val bobContact = fixtures.aliceClient.getUserContact(peerAddress = bobAddressLowerCased) - assert(bobContact != null) - } - - @Test - fun testCanFindContact() { - val fixtures = fixtures() - runBlocking { fixtures.bobClient.ensureUserContactPublished() } - val contactBundle = fixtures.aliceClient.contacts.find(fixtures.bob.walletAddress) - assertEquals(contactBundle?.walletAddress, fixtures.bob.walletAddress) - } - - @Test - fun testAllowAddress() { - val fixtures = fixtures() - - val contacts = fixtures.bobClient.contacts - var result = runBlocking { contacts.isAllowed(fixtures.alice.walletAddress) } - - assert(!result) - - runBlocking { contacts.allow(listOf(fixtures.alice.walletAddress)) } - - result = runBlocking { contacts.isAllowed(fixtures.alice.walletAddress) } - assert(result) - } - - @Test - fun testDenyAddress() { - val fixtures = fixtures() - - val contacts = fixtures.bobClient.contacts - var result = runBlocking { contacts.isAllowed(fixtures.alice.walletAddress) } - - assert(!result) - - runBlocking { contacts.deny(listOf(fixtures.alice.walletAddress)) } - - result = runBlocking { contacts.isDenied(fixtures.alice.walletAddress) } - assert(result) - } -} diff --git a/library/src/androidTest/java/org/xmtp/android/library/ConversationsTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ConversationsTest.kt new file mode 100644 index 000000000..239b1a58c --- /dev/null +++ b/library/src/androidTest/java/org/xmtp/android/library/ConversationsTest.kt @@ -0,0 +1,170 @@ +package org.xmtp.android.library + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.xmtp.android.library.libxmtp.Message.* +import org.xmtp.android.library.messages.PrivateKey +import org.xmtp.android.library.messages.PrivateKeyBuilder +import org.xmtp.android.library.messages.walletAddress + +@RunWith(AndroidJUnit4::class) +class ConversationsTest { + private lateinit var alixWallet: PrivateKeyBuilder + private lateinit var boWallet: PrivateKeyBuilder + private lateinit var alix: PrivateKey + private lateinit var alixClient: Client + private lateinit var bo: PrivateKey + private lateinit var boClient: Client + private lateinit var caroWallet: PrivateKeyBuilder + private lateinit var caro: PrivateKey + private lateinit var caroClient: Client + private lateinit var fixtures: Fixtures + + @Before + fun setUp() { + fixtures = fixtures() + alixWallet = fixtures.alixAccount + alix = fixtures.alix + boWallet = fixtures.boAccount + bo = fixtures.bo + caroWallet = fixtures.caroAccount + caro = fixtures.caro + + alixClient = fixtures.alixClient + boClient = fixtures.boClient + caroClient = fixtures.caroClient + } + + @Test + fun testsCanFindConversationByTopic() { + val group = + runBlocking { boClient.conversations.newGroup(listOf(caro.walletAddress)) } + val dm = runBlocking { boClient.conversations.findOrCreateDm(caro.walletAddress) } + + val sameDm = boClient.findConversationByTopic(dm.topic) + val sameGroup = boClient.findConversationByTopic(group.topic) + assertEquals(group.id, sameGroup?.id) + assertEquals(dm.id, sameDm?.id) + } + + @Test + fun testsCanListConversations() { + val dm = runBlocking { boClient.conversations.findOrCreateDm(caro.walletAddress) } + val group = + runBlocking { boClient.conversations.newGroup(listOf(caro.walletAddress)) } + assertEquals(runBlocking { boClient.conversations.list().size }, 2) + assertEquals(runBlocking { boClient.conversations.listDms().size }, 1) + assertEquals(runBlocking { boClient.conversations.listGroups().size }, 1) + + runBlocking { caroClient.conversations.syncConversations() } + assertEquals( + runBlocking { caroClient.conversations.list().size }, + 2 + ) + assertEquals(runBlocking { caroClient.conversations.listGroups().size }, 1) + } + + @Test + fun testsCanListConversationsFiltered() { + val dm = runBlocking { boClient.conversations.findOrCreateDm(caro.walletAddress) } + val group = + runBlocking { boClient.conversations.newGroup(listOf(caro.walletAddress)) } + assertEquals(runBlocking { boClient.conversations.list().size }, 2) + assertEquals( + runBlocking { boClient.conversations.list(consentState = ConsentState.ALLOWED).size }, + 2 + ) + runBlocking { group.updateConsentState(ConsentState.DENIED) } + assertEquals( + runBlocking { boClient.conversations.list(consentState = ConsentState.ALLOWED).size }, + 1 + ) + assertEquals( + runBlocking { boClient.conversations.list(consentState = ConsentState.DENIED).size }, + 1 + ) + assertEquals(runBlocking { boClient.conversations.list().size }, 2) + } + + @Test + fun testCanListConversationsOrder() { + val dm = runBlocking { boClient.conversations.findOrCreateDm(caro.walletAddress) } + val group1 = + runBlocking { boClient.conversations.newGroup(listOf(caro.walletAddress)) } + val group2 = + runBlocking { boClient.conversations.newGroup(listOf(caro.walletAddress)) } + runBlocking { dm.send("Howdy") } + runBlocking { group2.send("Howdy") } + runBlocking { boClient.conversations.syncAllConversations() } + val conversations = runBlocking { boClient.conversations.list() } + val conversationsOrdered = + runBlocking { boClient.conversations.list(order = Conversations.ConversationOrder.LAST_MESSAGE) } + assertEquals(conversations.size, 3) + assertEquals(conversationsOrdered.size, 3) + assertEquals(conversations.map { it.id }, listOf(dm.id, group1.id, group2.id)) + assertEquals(conversationsOrdered.map { it.id }, listOf(group2.id, dm.id, group1.id)) + } + + @Test + fun testCanStreamAllMessages() { + val group = + runBlocking { caroClient.conversations.newGroup(listOf(bo.walletAddress)) } + val conversation = + runBlocking { boClient.conversations.findOrCreateDm(caro.walletAddress) } + runBlocking { boClient.conversations.syncConversations() } + + val allMessages = mutableListOf() + + val job = CoroutineScope(Dispatchers.IO).launch { + try { + boClient.conversations.streamAllMessages() + .collect { message -> + allMessages.add(message) + } + } catch (e: Exception) { + } + } + Thread.sleep(1000) + runBlocking { + group.send("hi") + conversation.send("hi") + } + Thread.sleep(1000) + assertEquals(2, allMessages.size) + job.cancel() + } + + @Test + fun testCanStreamGroupsAndConversations() { + val allMessages = mutableListOf() + + val job = CoroutineScope(Dispatchers.IO).launch { + try { + boClient.conversations.stream() + .collect { message -> + allMessages.add(message.topic) + } + } catch (e: Exception) { + } + } + Thread.sleep(1000) + + runBlocking { + caroClient.conversations.newGroup(listOf(bo.walletAddress)) + Thread.sleep(1000) + boClient.conversations.findOrCreateDm(caro.walletAddress) + } + + Thread.sleep(2000) + assertEquals(2, allMessages.size) + job.cancel() + } +} diff --git a/library/src/androidTest/java/org/xmtp/android/library/DmTest.kt b/library/src/androidTest/java/org/xmtp/android/library/DmTest.kt index 71a388b93..77751dc68 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/DmTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/DmTest.kt @@ -37,48 +37,17 @@ class DmTest { @Before fun setUp() { - val key = SecureRandom().generateSeed(32) - val context = InstrumentationRegistry.getInstrumentation().targetContext - alixWallet = PrivateKeyBuilder() - alix = alixWallet.getPrivateKey() - alixClient = runBlocking { - Client().createV3( - account = alixWallet, - options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - ) - } - boWallet = PrivateKeyBuilder() - bo = boWallet.getPrivateKey() - boClient = runBlocking { - Client().createV3( - account = boWallet, - options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - ) - } - - caroWallet = PrivateKeyBuilder() - caro = caroWallet.getPrivateKey() - caroClient = runBlocking { - Client().createV3( - account = caroWallet, - options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - ) - } + val fixtures = fixtures() + alixWallet = fixtures.alixAccount + alix = fixtures.alix + boWallet = fixtures.boAccount + bo = fixtures.bo + caroWallet = fixtures.caroAccount + caro = fixtures.caro + + alixClient = fixtures.alixClient + boClient = fixtures.boClient + caroClient = fixtures.caroClient } @Test @@ -127,7 +96,6 @@ class DmTest { fun testCannotCreateDmWithMemberNotOnV3() { val chuxAccount = PrivateKeyBuilder() val chux: PrivateKey = chuxAccount.getPrivateKey() - runBlocking { Client().create(account = chuxAccount) } assertThrows("Recipient not on network", XMTPException::class.java) { runBlocking { boClient.conversations.findOrCreateDm(chux.walletAddress) } @@ -148,8 +116,7 @@ class DmTest { dm.send("howdy") dm.send("gm") dm.sync() - assert(boClient.contacts.isGroupAllowed(dm.id)) - assertEquals(boClient.contacts.consentList.groupState(dm.id), ConsentState.ALLOWED) + assertEquals(boClient.preferences.consentList.groupState(dm.id), ConsentState.ALLOWED) assertEquals(dm.consentState(), ConsentState.ALLOWED) } } @@ -293,15 +260,32 @@ class DmTest { runBlocking { val dm = boClient.conversations.findOrCreateDm(alix.walletAddress) - assert(boClient.contacts.isGroupAllowed(dm.id)) + assertEquals(boClient.preferences.consentList.groupState(dm.id), ConsentState.ALLOWED) + assertEquals(dm.consentState(), ConsentState.ALLOWED) - boClient.contacts.denyGroups(listOf(dm.id)) - assert(boClient.contacts.isGroupDenied(dm.id)) + boClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + dm.id, + EntryType.GROUP_ID, + ConsentState.DENIED + ) + ) + ) + assertEquals(boClient.preferences.consentList.groupState(dm.id), ConsentState.DENIED) assertEquals(dm.consentState(), ConsentState.DENIED) - dm.updateConsentState(ConsentState.ALLOWED) - assert(boClient.contacts.isGroupAllowed(dm.id)) + boClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + dm.id, + EntryType.GROUP_ID, + ConsentState.ALLOWED + ) + ) + ) + assertEquals(boClient.preferences.consentList.groupState(dm.id), ConsentState.ALLOWED) assertEquals(dm.consentState(), ConsentState.ALLOWED) } } diff --git a/library/src/androidTest/java/org/xmtp/android/library/FramesTest.kt b/library/src/androidTest/java/org/xmtp/android/library/FramesTest.kt index db0bc52c8..4a7969b45 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/FramesTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/FramesTest.kt @@ -1,71 +1,71 @@ -package org.xmtp.android.library - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotNull -import org.junit.Test -import org.junit.runner.RunWith -import org.xmtp.android.library.frames.ConversationActionInputs -import org.xmtp.android.library.frames.DmActionInputs -import org.xmtp.android.library.frames.FrameActionInputs -import org.xmtp.android.library.frames.FramePostPayload -import org.xmtp.android.library.frames.FramesClient -import org.xmtp.android.library.frames.GetMetadataResponse -import java.net.HttpURLConnection -import java.net.URL - -@RunWith(AndroidJUnit4::class) -class FramesTest { - @Test - fun testFramesClient() { - val frameUrl = "https://fc-polls-five.vercel.app/polls/01032f47-e976-42ee-9e3d-3aac1324f4b8" - val fixtures = fixtures() - val aliceClient = fixtures.aliceClient - - val framesClient = FramesClient(xmtpClient = aliceClient) - val conversationTopic = "foo" - val participantAccountAddresses = listOf("alix", "bo") - val metadata: GetMetadataResponse - runBlocking { - metadata = framesClient.proxy.readMetadata(url = frameUrl) - } - - val dmInputs = DmActionInputs( - conversationTopic = conversationTopic, - participantAccountAddresses = participantAccountAddresses - ) - val conversationInputs = ConversationActionInputs.Dm(dmInputs) - val frameInputs = FrameActionInputs( - frameUrl = frameUrl, - buttonIndex = 1, - inputText = null, - state = null, - conversationInputs = conversationInputs - ) - val signedPayload: FramePostPayload - runBlocking { - signedPayload = framesClient.signFrameAction(inputs = frameInputs) - } - val postUrl = metadata.extractedTags["fc:frame:post_url"] - assertNotNull(postUrl) - val response: GetMetadataResponse - runBlocking { - response = framesClient.proxy.post(url = postUrl!!, payload = signedPayload) - } - - assertEquals(response.extractedTags["fc:frame"], "vNext") - - val imageUrl = response.extractedTags["fc:frame:image"] - assertNotNull(imageUrl) - - val mediaUrl = framesClient.proxy.mediaUrl(url = imageUrl!!) - - val url = URL(mediaUrl) - val connection = url.openConnection() as HttpURLConnection - connection.requestMethod = "GET" - val responseCode = connection.responseCode - assertEquals(responseCode, 200) - assertEquals(connection.contentType, "image/png") - } -} +//package org.xmtp.android.library +// +//import androidx.test.ext.junit.runners.AndroidJUnit4 +//import kotlinx.coroutines.runBlocking +//import org.junit.Assert.assertEquals +//import org.junit.Assert.assertNotNull +//import org.junit.Test +//import org.junit.runner.RunWith +//import org.xmtp.android.library.frames.ConversationActionInputs +//import org.xmtp.android.library.frames.DmActionInputs +//import org.xmtp.android.library.frames.FrameActionInputs +//import org.xmtp.android.library.frames.FramePostPayload +//import org.xmtp.android.library.frames.FramesClient +//import org.xmtp.android.library.frames.GetMetadataResponse +//import java.net.HttpURLConnection +//import java.net.URL +// +//@RunWith(AndroidJUnit4::class) +//class FramesTest { +// @Test +// fun testFramesClient() { +// val frameUrl = "https://fc-polls-five.vercel.app/polls/01032f47-e976-42ee-9e3d-3aac1324f4b8" +// val fixtures = fixtures() +// val aliceClient = fixtures.aliceClient +// +// val framesClient = FramesClient(xmtpClient = aliceClient) +// val conversationTopic = "foo" +// val participantAccountAddresses = listOf("alix", "bo") +// val metadata: GetMetadataResponse +// runBlocking { +// metadata = framesClient.proxy.readMetadata(url = frameUrl) +// } +// +// val dmInputs = DmActionInputs( +// conversationTopic = conversationTopic, +// participantAccountAddresses = participantAccountAddresses +// ) +// val conversationInputs = ConversationActionInputs.Dm(dmInputs) +// val frameInputs = FrameActionInputs( +// frameUrl = frameUrl, +// buttonIndex = 1, +// inputText = null, +// state = null, +// conversationInputs = conversationInputs +// ) +// val signedPayload: FramePostPayload +// runBlocking { +// signedPayload = framesClient.signFrameAction(inputs = frameInputs) +// } +// val postUrl = metadata.extractedTags["fc:frame:post_url"] +// assertNotNull(postUrl) +// val response: GetMetadataResponse +// runBlocking { +// response = framesClient.proxy.post(url = postUrl!!, payload = signedPayload) +// } +// +// assertEquals(response.extractedTags["fc:frame"], "vNext") +// +// val imageUrl = response.extractedTags["fc:frame:image"] +// assertNotNull(imageUrl) +// +// val mediaUrl = framesClient.proxy.mediaUrl(url = imageUrl!!) +// +// val url = URL(mediaUrl) +// val connection = url.openConnection() as HttpURLConnection +// connection.requestMethod = "GET" +// val responseCode = connection.responseCode +// assertEquals(responseCode, 200) +// assertEquals(connection.contentType, "image/png") +// } +//} diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupPermissionsTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupPermissionsTest.kt index 00dbcf707..c92cfa287 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupPermissionsTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupPermissionsTest.kt @@ -35,24 +35,16 @@ class GroupPermissionsTest { fun setUp() { val key = SecureRandom().generateSeed(32) val context = InstrumentationRegistry.getInstrumentation().targetContext - fixtures = - fixtures( - clientOptions = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - ) - alixWallet = fixtures.aliceAccount - alix = fixtures.alice - boWallet = fixtures.bobAccount - bo = fixtures.bob + fixtures = fixtures() + alixWallet = fixtures.alixAccount + alix = fixtures.alix + boWallet = fixtures.boAccount + bo = fixtures.bo caroWallet = fixtures.caroAccount caro = fixtures.caro - alixClient = fixtures.aliceClient - boClient = fixtures.bobClient + alixClient = fixtures.alixClient + boClient = fixtures.boClient caroClient = fixtures.caroClient } diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt index b5b0f63c3..cde3be6c2 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt @@ -1,7 +1,6 @@ package org.xmtp.android.library import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry import app.cash.turbine.test import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -26,7 +25,6 @@ import org.xmtp.android.library.messages.walletAddress import org.xmtp.proto.mls.message.contents.TranscriptMessages import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.GroupPermissionPreconfiguration import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionOption -import java.security.SecureRandom @RunWith(AndroidJUnit4::class) class GroupTest { @@ -39,39 +37,21 @@ class GroupTest { private lateinit var caroWallet: PrivateKeyBuilder private lateinit var caro: PrivateKey private lateinit var caroClient: Client - private lateinit var davonV3Wallet: PrivateKeyBuilder - private lateinit var davonV3: PrivateKey - private lateinit var davonV3Client: Client private lateinit var fixtures: Fixtures @Before fun setUp() { - val key = SecureRandom().generateSeed(32) - val context = InstrumentationRegistry.getInstrumentation().targetContext - val options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - fixtures = - fixtures( - clientOptions = options - ) - alixWallet = fixtures.aliceAccount - alix = fixtures.alice - boWallet = fixtures.bobAccount - bo = fixtures.bob + fixtures = fixtures() + alixWallet = fixtures.alixAccount + alix = fixtures.alix + boWallet = fixtures.boAccount + bo = fixtures.bo caroWallet = fixtures.caroAccount caro = fixtures.caro - davonV3Wallet = PrivateKeyBuilder() - davonV3 = davonV3Wallet.getPrivateKey() - alixClient = fixtures.aliceClient - boClient = fixtures.bobClient + alixClient = fixtures.alixClient + boClient = fixtures.boClient caroClient = fixtures.caroClient - davonV3Client = - runBlocking { Client().createV3(account = davonV3Wallet, options = options) } } @Test @@ -130,9 +110,12 @@ class GroupTest { assert(alixGroup.id.isNotEmpty()) runBlocking { - assertEquals(boClient.contacts.consentList.groupState(boGroup.id), ConsentState.ALLOWED) assertEquals( - alixClient.contacts.consentList.groupState(alixGroup.id), + boClient.preferences.consentList.groupState(boGroup.id), + ConsentState.ALLOWED + ) + assertEquals( + alixClient.preferences.consentList.groupState(alixGroup.id), ConsentState.UNKNOWN ) } @@ -386,7 +369,6 @@ class GroupTest { runBlocking { boClient.conversations.newGroup(listOf(alix.walletAddress)) boClient.conversations.newGroup(listOf(caro.walletAddress)) - davonV3Client.conversations.findOrCreateDm(bo.walletAddress) boClient.conversations.syncConversations() } val groups = runBlocking { boClient.conversations.listGroups() } @@ -399,7 +381,6 @@ class GroupTest { boClient.conversations.newGroup(listOf(alix.walletAddress)) boClient.conversations.newGroup(listOf(caro.walletAddress)) boClient.conversations.newConversation(alix.walletAddress) - davonV3Client.conversations.findOrCreateDm(bo.walletAddress) boClient.conversations.syncConversations() } val convos = runBlocking { boClient.conversations.list() } @@ -410,7 +391,6 @@ class GroupTest { fun testCannotSendMessageToGroupMemberNotOnV3() { val chuxAccount = PrivateKeyBuilder() val chux: PrivateKey = chuxAccount.getPrivateKey() - runBlocking { Client().create(account = chuxAccount) } assertThrows("Recipient not on network", XMTPException::class.java) { runBlocking { boClient.conversations.newGroup(listOf(chux.walletAddress)) } @@ -437,8 +417,11 @@ class GroupTest { group.send("howdy") group.send("gm") group.sync() - assert(boClient.contacts.isGroupAllowed(group.id)) - assertEquals(boClient.contacts.consentList.groupState(group.id), ConsentState.ALLOWED) + assertEquals(group.consentState(), ConsentState.ALLOWED) + assertEquals( + boClient.preferences.consentList.groupState(group.id), + ConsentState.ALLOWED + ) } } @@ -592,7 +575,6 @@ class GroupTest { @Test fun testCanStreamAllGroupMessages() { val group = runBlocking { caroClient.conversations.newGroup(listOf(alix.walletAddress)) } - val dm = runBlocking { davonV3Client.conversations.findOrCreateDm(alix.walletAddress) } runBlocking { alixClient.conversations.syncConversations() } val allMessages = mutableListOf() @@ -607,7 +589,6 @@ class GroupTest { } Thread.sleep(2500) - runBlocking { dm.send("should not stream") } for (i in 0 until 2) { runBlocking { group.send(text = "Message $i") @@ -633,7 +614,6 @@ class GroupTest { @Test fun testCanStreamAllMessages() { val group = runBlocking { caroClient.conversations.newGroup(listOf(alix.walletAddress)) } - val dm = runBlocking { davonV3Client.conversations.findOrCreateDm(alix.walletAddress) } val conversation = runBlocking { boClient.conversations.newConversation(alix.walletAddress) } runBlocking { alixClient.conversations.syncConversations() } @@ -654,7 +634,6 @@ class GroupTest { runBlocking { group.send("hi") conversation.send("hi") - dm.send("should not stream") } Thread.sleep(1000) @@ -673,9 +652,6 @@ class GroupTest { val group2 = caroClient.conversations.newGroup(listOf(bo.walletAddress)) assertEquals(group2.id, awaitItem().id) - davonV3Client.conversations.findOrCreateDm(bo.walletAddress) - expectNoEvents() - cancelAndConsumeRemainingEvents() } } @@ -695,7 +671,6 @@ class GroupTest { Thread.sleep(2500) runBlocking { - davonV3Client.conversations.findOrCreateDm(alix.walletAddress) alixClient.conversations.newConversation(bo.walletAddress) Thread.sleep(2500) caroClient.conversations.newGroup(listOf(alix.walletAddress)) @@ -718,15 +693,29 @@ class GroupTest { caro.walletAddress ) ) - assert(boClient.contacts.isGroupAllowed(group.id)) + assertEquals( + boClient.preferences.consentList.groupState(group.id), + ConsentState.ALLOWED + ) assertEquals(group.consentState(), ConsentState.ALLOWED) - boClient.contacts.denyGroups(listOf(group.id)) - assert(boClient.contacts.isGroupDenied(group.id)) + boClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + group.id, + EntryType.GROUP_ID, + ConsentState.DENIED + ) + ) + ) + assertEquals(boClient.preferences.consentList.groupState(group.id), ConsentState.DENIED) assertEquals(group.consentState(), ConsentState.DENIED) group.updateConsentState(ConsentState.ALLOWED) - assert(boClient.contacts.isGroupAllowed(group.id)) + assertEquals( + boClient.preferences.consentList.groupState(group.id), + ConsentState.ALLOWED + ) assertEquals(group.consentState(), ConsentState.ALLOWED) } } @@ -735,30 +724,64 @@ class GroupTest { fun testCanAllowAndDenyInboxId() { runBlocking { val boGroup = boClient.conversations.newGroup(listOf(alix.walletAddress)) - assert(!boClient.contacts.isInboxAllowed(alixClient.inboxId)) - assert(!boClient.contacts.isInboxDenied(alixClient.inboxId)) - - boClient.contacts.allowInboxes(listOf(alixClient.inboxId)) + assertEquals( + boClient.preferences.consentList.inboxIdState(alixClient.inboxId), + ConsentState.UNKNOWN + ) + boClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + alixClient.inboxId, + EntryType.INBOX_ID, + ConsentState.ALLOWED + ) + ) + ) var alixMember = boGroup.members().firstOrNull { it.inboxId == alixClient.inboxId } assertEquals(alixMember!!.consentState, ConsentState.ALLOWED) - assert(boClient.contacts.isInboxAllowed(alixClient.inboxId)) - assert(!boClient.contacts.isInboxDenied(alixClient.inboxId)) + assertEquals( + boClient.preferences.consentList.inboxIdState(alixClient.inboxId), + ConsentState.ALLOWED + ) - boClient.contacts.denyInboxes(listOf(alixClient.inboxId)) + boClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + alixClient.inboxId, + EntryType.INBOX_ID, + ConsentState.DENIED + ) + ) + ) alixMember = boGroup.members().firstOrNull { it.inboxId == alixClient.inboxId } assertEquals(alixMember!!.consentState, ConsentState.DENIED) - assert(!boClient.contacts.isInboxAllowed(alixClient.inboxId)) - assert(boClient.contacts.isInboxDenied(alixClient.inboxId)) + assertEquals( + boClient.preferences.consentList.inboxIdState(alixClient.inboxId), + ConsentState.DENIED + ) + - boClient.contacts.allow(listOf(alixClient.address)) + boClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + alixClient.address, + EntryType.ADDRESS, + ConsentState.ALLOWED + ) + ) + ) alixMember = boGroup.members().firstOrNull { it.inboxId == alixClient.inboxId } assertEquals(alixMember!!.consentState, ConsentState.ALLOWED) - assert(boClient.contacts.isInboxAllowed(alixClient.inboxId)) - assert(!boClient.contacts.isInboxDenied(alixClient.inboxId)) - assert(boClient.contacts.isAllowed(alixClient.address)) - assert(!boClient.contacts.isDenied(alixClient.address)) + assertEquals( + boClient.preferences.consentList.inboxIdState(alixClient.inboxId), + ConsentState.ALLOWED + ) + assertEquals( + boClient.preferences.consentList.addressState(alixClient.address), + ConsentState.ALLOWED + ) } } @@ -809,9 +832,9 @@ class GroupTest { } runBlocking { alixClient.conversations.syncConversations() } val alixGroup: Group = alixClient.findGroup(boGroup.id)!! - runBlocking { assert(!alixClient.contacts.isGroupAllowed(boGroup.id)) } + runBlocking { assertEquals(alixGroup.consentState(), ConsentState.UNKNOWN) } val preparedMessageId = runBlocking { alixGroup.prepareMessage("Test text") } - runBlocking { assert(alixClient.contacts.isGroupAllowed(boGroup.id)) } + runBlocking { assertEquals(alixGroup.consentState(), ConsentState.ALLOWED) } assertEquals(alixGroup.messages().size, 1) assertEquals(alixGroup.messages(deliveryStatus = MessageDeliveryStatus.PUBLISHED).size, 0) assertEquals(alixGroup.messages(deliveryStatus = MessageDeliveryStatus.UNPUBLISHED).size, 1) diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupUpdatedTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupUpdatedTest.kt index 2bedbeb63..dd2547eab 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupUpdatedTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupUpdatedTest.kt @@ -33,23 +33,16 @@ class GroupUpdatedTest { @Before fun setUp() { val key = SecureRandom().generateSeed(32) - fixtures = fixtures( - clientOptions = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - ) - alixWallet = fixtures.aliceAccount - alix = fixtures.alice - boWallet = fixtures.bobAccount - bo = fixtures.bob + fixtures = fixtures() + alixWallet = fixtures.alixAccount + alix = fixtures.alix + boWallet = fixtures.boAccount + bo = fixtures.bo caroWallet = fixtures.caroAccount caro = fixtures.caro - alixClient = fixtures.aliceClient - boClient = fixtures.bobClient + alixClient = fixtures.alixClient + boClient = fixtures.boClient caroClient = fixtures.caroClient } diff --git a/library/src/androidTest/java/org/xmtp/android/library/InvitationTest.kt b/library/src/androidTest/java/org/xmtp/android/library/InvitationTest.kt deleted file mode 100644 index 104a42da1..000000000 --- a/library/src/androidTest/java/org/xmtp/android/library/InvitationTest.kt +++ /dev/null @@ -1,197 +0,0 @@ -package org.xmtp.android.library - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.google.protobuf.kotlin.toByteString -import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotEquals -import org.junit.Test -import org.junit.runner.RunWith -import org.web3j.utils.Numeric -import org.xmtp.android.library.messages.InvitationV1 -import org.xmtp.android.library.messages.InvitationV1ContextBuilder -import org.xmtp.android.library.messages.PrivateKey -import org.xmtp.android.library.messages.PrivateKeyBuilder -import org.xmtp.android.library.messages.PrivateKeyBundle -import org.xmtp.android.library.messages.PrivateKeyBundleV1 -import org.xmtp.android.library.messages.SealedInvitation -import org.xmtp.android.library.messages.SealedInvitationBuilder -import org.xmtp.android.library.messages.createDeterministic -import org.xmtp.android.library.messages.generate -import org.xmtp.android.library.messages.getInvitation -import org.xmtp.android.library.messages.getPublicKeyBundle -import org.xmtp.android.library.messages.header -import org.xmtp.android.library.messages.sharedSecret -import org.xmtp.android.library.messages.toPublicKeyBundle -import org.xmtp.android.library.messages.toV2 -import java.util.Date - -@RunWith(AndroidJUnit4::class) -class InvitationTest { - @Test - fun testExistingWallet() { - // Generated from JS script - val ints = arrayOf( - 31, 116, 198, 193, 189, 122, 19, 254, 191, 189, 211, 215, 255, 131, - 171, 239, 243, 33, 4, 62, 143, 86, 18, 195, 251, 61, 128, 90, 34, 126, 219, 236 - ) - val bytes = - ints.foldIndexed(ByteArray(ints.size)) { i, a, v -> a.apply { set(i, v.toByte()) } } - val key = PrivateKey.newBuilder().also { - it.secp256K1 = - it.secp256K1.toBuilder().also { builder -> builder.bytes = bytes.toByteString() } - .build() - it.publicKey = it.publicKey.toBuilder().also { builder -> - builder.secp256K1Uncompressed = - builder.secp256K1Uncompressed.toBuilder().also { keyBuilder -> - keyBuilder.bytes = - KeyUtil.addUncompressedByte(KeyUtil.getPublicKey(bytes)).toByteString() - }.build() - }.build() - }.build() - - val client = runBlocking { Client().create(account = PrivateKeyBuilder(key)) } - val conversations = runBlocking { client.conversations.list() } - assertEquals(1, conversations.size) - val message = runBlocking { conversations[0].messages().firstOrNull() } - assertEquals(message?.body, "hello") - } - - @Test - fun testGenerateSealedInvitation() { - val aliceWallet = FakeWallet.generate() - val bobWallet = FakeWallet.generate() - val alice = PrivateKeyBundleV1.newBuilder().build().generate(wallet = aliceWallet) - val bob = PrivateKeyBundleV1.newBuilder().build().generate(wallet = bobWallet) - val invitation = InvitationV1.newBuilder().build().createDeterministic( - sender = alice.toV2(), - recipient = bob.toV2().getPublicKeyBundle() - ) - val newInvitation = SealedInvitationBuilder.buildFromV1( - sender = alice.toV2(), - recipient = bob.toV2().getPublicKeyBundle(), - created = Date(), - invitation = invitation - ) - val deserialized = SealedInvitation.parseFrom(newInvitation.toByteArray()) - assert(!deserialized.v1.headerBytes.isEmpty) - assertEquals(newInvitation, deserialized) - val header = newInvitation.v1.header - // Ensure the headers haven't been mangled - assertEquals(header.sender, alice.toV2().getPublicKeyBundle()) - assertEquals(header.recipient, bob.toV2().getPublicKeyBundle()) - // Ensure alice can decrypt the invitation - val aliceInvite = newInvitation.v1.getInvitation(viewer = alice.toV2()) - assertEquals(aliceInvite.topic, invitation.topic) - assertEquals( - aliceInvite.aes256GcmHkdfSha256.keyMaterial, - invitation.aes256GcmHkdfSha256.keyMaterial - ) - // Ensure bob can decrypt the invitation - val bobInvite = newInvitation.v1.getInvitation(viewer = bob.toV2()) - assertEquals(bobInvite.topic, invitation.topic) - assertEquals( - bobInvite.aes256GcmHkdfSha256.keyMaterial, - invitation.aes256GcmHkdfSha256.keyMaterial - ) - } - - @Test - fun testDeterministicInvite() { - val aliceWallet = FakeWallet.generate() - val bobWallet = FakeWallet.generate() - val alice = PrivateKeyBundleV1.newBuilder().build().generate(wallet = aliceWallet) - val bob = PrivateKeyBundleV1.newBuilder().build().generate(wallet = bobWallet) - val makeInvite = { conversationId: String -> - InvitationV1.newBuilder().build().createDeterministic( - sender = alice.toV2(), - recipient = bob.toV2().getPublicKeyBundle(), - context = InvitationV1ContextBuilder.buildFromConversation(conversationId) - ) - } - // Repeatedly making the same invite should use the same topic/keys - val original = makeInvite("example.com/conversation-foo") - for (i in 1..10) { - val invite = makeInvite("example.com/conversation-foo") - assertEquals(original.topic, invite.topic) - } - // But when the conversationId changes then it use a new topic/keys - val invite = makeInvite("example.com/conversation-bar") - assertNotEquals(original.topic, invite.topic) - } - - @Test - fun testGeneratesKnownDeterministicTopic() { - // address = 0xF56d1F3b1290204441Cb3843C2Cac1C2f5AEd690 - val aliceKeyData = - Numeric.hexStringToByteArray("0x0a8a030ac20108c192a3f7923112220a2068d2eb2ef8c50c4916b42ce638c5610e44ff4eb3ecb098c9dacf032625c72f101a940108c192a3f7923112460a440a40fc9822283078c323c9319c45e60ab42c65f6e1744ed8c23c52728d456d33422824c98d307e8b1c86a26826578523ba15fe6f04a17fca176664ee8017ec8ba59310011a430a410498dc2315dd45d99f5e900a071e7b56142de344540f07fbc73a0f9a5d5df6b52eb85db06a3825988ab5e04746bc221fcdf5310a44d9523009546d4bfbfbb89cfb12c20108eb92a3f7923112220a20788be9da8e1a1a08b05f7cbf22d86980bc056b130c482fa5bd26ccb8d29b30451a940108eb92a3f7923112460a440a40a7afa25cb6f3fbb98f9e5cd92a1df1898452e0dfa1d7e5affe9eaf9b72dd14bc546d86c399768badf983f07fa7dd16eee8d793357ce6fccd676807d87bcc595510011a430a410422931e6295c3c93a5f6f5e729dc02e1754e916cb9be16d36dc163a300931f42a0cd5fde957d75c2068e1980c5f86843daf16aba8ae57e8160b8b9f0191def09e") - val aliceKeys = PrivateKeyBundle.parseFrom(aliceKeyData).v1.toV2() - - // address = 0x3De402A325323Bb97f00cE3ad5bFAc96A11F9A34 - val bobKeyData = - Numeric.hexStringToByteArray("0x0a88030ac001088cd68df7923112220a209057f8d813314a2aae74e6c4c30f909c1c496b6037ce32a12c613558a8e961681a9201088cd68df7923112440a420a40501ae9b4f75d5bb5bae3ca4ecfda4ede9edc5a9b7fc2d56dc7325b837957c23235cc3005b46bb9ef485f106404dcf71247097ed509635590f4b7987b833d03661a430a4104e61a7ae511567f4a2b5551221024b6932d6cdb8ecf3876ec64cf29be4291dd5428fc0301963cdf6939978846e2c35fd38fcb70c64296a929f166ef6e4e91045712c20108b8d68df7923112220a2027707399474d417bf6aae4baa3d73b285bf728353bc3e156b0e32461ebb48f8c1a940108b8d68df7923112460a440a40fb96fa38c3f013830abb61cf6b39776e0475eb1379c66013569c3d2daecdd48c7fbee945dcdbdc5717d1f4ffd342c4d3f1b7215912829751a94e3ae11007e0a110011a430a4104952b7158cfe819d92743a4132e2e3ae867d72f6a08292aebf471d0a7a2907f3e9947719033e20edc9ca9665874bd88c64c6b62c01928065f6069c5c80c699924") - val bobKeys = PrivateKeyBundle.parseFrom(bobKeyData).v1.toV2() - - val aliceInvite = InvitationV1.newBuilder().build().createDeterministic( - sender = aliceKeys, - recipient = bobKeys.getPublicKeyBundle(), - context = InvitationV1ContextBuilder.buildFromConversation("test") - ) - - assertEquals( - aliceInvite.topic, - "/xmtp/0/m-4b52be1e8567d72d0bc407debe2d3c7fca2ae93a47e58c3f9b5c5068aff80ec5/proto" - ) - - val bobInvite = InvitationV1.newBuilder().build().createDeterministic( - sender = bobKeys, - recipient = aliceKeys.getPublicKeyBundle(), - context = InvitationV1ContextBuilder.buildFromConversation("test") - ) - - assertEquals( - aliceInvite.topic, - "/xmtp/0/m-4b52be1e8567d72d0bc407debe2d3c7fca2ae93a47e58c3f9b5c5068aff80ec5/proto" - ) - - assertEquals( - bobInvite.topic, - "/xmtp/0/m-4b52be1e8567d72d0bc407debe2d3c7fca2ae93a47e58c3f9b5c5068aff80ec5/proto" - ) - } - - @Test - fun testCreatesDeterministicTopicsBidirectionally() { - val aliceWallet = FakeWallet.generate() - val bobWallet = FakeWallet.generate() - val alice = PrivateKeyBundleV1.newBuilder().build().generate(wallet = aliceWallet) - val bob = PrivateKeyBundleV1.newBuilder().build().generate(wallet = bobWallet) - - val aliceInvite = InvitationV1.newBuilder().build().createDeterministic( - sender = alice.toV2(), - recipient = bob.toV2().getPublicKeyBundle(), - context = null - ) - - val bobInvite = InvitationV1.newBuilder().build().createDeterministic( - sender = bob.toV2(), - recipient = alice.toV2().getPublicKeyBundle(), - context = null - ) - - val aliceSharedSecret = alice.sharedSecret( - bob.toPublicKeyBundle(), - alice.getPreKeys(0).publicKey, - false - ) - - val bobSharedSecret = bob.sharedSecret( - alice.toPublicKeyBundle(), bob.getPreKeys(0).publicKey, - true - ) - - assertEquals(aliceSharedSecret.contentToString(), bobSharedSecret.contentToString()) - - assertEquals(aliceInvite.topic, bobInvite.topic) - } -} diff --git a/library/src/androidTest/java/org/xmtp/android/library/ReactionTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ReactionTest.kt index 4ccd65486..94f292961 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ReactionTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ReactionTest.kt @@ -66,9 +66,9 @@ class ReactionTest { Client.register(codec = ReactionCodec()) val fixtures = fixtures() - val aliceClient = fixtures.aliceClient + val aliceClient = fixtures.alixClient val aliceConversation = runBlocking { - aliceClient.conversations.newConversation(fixtures.bob.walletAddress) + aliceClient.conversations.newConversation(fixtures.bo.walletAddress) } runBlocking { aliceConversation.send(text = "hey alice 2 bob") } @@ -89,8 +89,8 @@ class ReactionTest { ) } val messages = runBlocking { aliceConversation.messages() } - assertEquals(messages.size, 2) - if (messages.size == 2) { + assertEquals(messages.size, 3) + if (messages.size == 3) { val content: Reaction? = messages.first().content() assertEquals("U+1F603", content?.content) assertEquals(messageToReact.id, content?.reference) diff --git a/library/src/androidTest/java/org/xmtp/android/library/ReadReceiptTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ReadReceiptTest.kt index 8a3fc8df9..058506a2d 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ReadReceiptTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ReadReceiptTest.kt @@ -18,9 +18,9 @@ class ReadReceiptTest { Client.register(codec = ReadReceiptCodec()) val fixtures = fixtures() - val aliceClient = fixtures.aliceClient + val aliceClient = fixtures.alixClient val aliceConversation = runBlocking { - aliceClient.conversations.newConversation(fixtures.bob.walletAddress) + aliceClient.conversations.newConversation(fixtures.bo.walletAddress) } runBlocking { aliceConversation.send(text = "hey alice 2 bob") } @@ -34,8 +34,8 @@ class ReadReceiptTest { ) } val messages = runBlocking { aliceConversation.messages() } - assertEquals(messages.size, 2) - if (messages.size == 2) { + assertEquals(messages.size, 3) + if (messages.size == 3) { val contentType: String = messages.first().encodedContent.type.typeId assertEquals(contentType, "readReceipt") } diff --git a/library/src/androidTest/java/org/xmtp/android/library/ReplyTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ReplyTest.kt index 75cb66675..413a9644a 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ReplyTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ReplyTest.kt @@ -19,9 +19,9 @@ class ReplyTest { Client.register(codec = ReplyCodec()) val fixtures = fixtures() - val aliceClient = fixtures.aliceClient + val aliceClient = fixtures.alixClient val aliceConversation = runBlocking { - aliceClient.conversations.newConversation(fixtures.bob.walletAddress) + aliceClient.conversations.newConversation(fixtures.bo.walletAddress) } runBlocking { aliceConversation.send(text = "hey alice 2 bob") } @@ -41,8 +41,8 @@ class ReplyTest { ) } val messages = runBlocking { aliceConversation.messages() } - assertEquals(messages.size, 2) - if (messages.size == 2) { + assertEquals(messages.size, 3) + if (messages.size == 3) { val content: Reply? = messages.first().content() assertEquals("Hello", content?.content) assertEquals(messageToReact.id, content?.reference) diff --git a/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt b/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt index 15ebf5436..1fb09e925 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt @@ -39,7 +39,6 @@ class SmartContractWalletTest { val context = InstrumentationRegistry.getInstrumentation().targetContext options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, appContext = context, dbEncryptionKey = key ) @@ -48,7 +47,7 @@ class SmartContractWalletTest { boV3Wallet = PrivateKeyBuilder() boV3 = boV3Wallet.getPrivateKey() boV3Client = runBlocking { - Client().createV3( + Client().create( account = boV3Wallet, options = options ) @@ -57,7 +56,7 @@ class SmartContractWalletTest { // SCW davonSCW = FakeSCWWallet.generate(ANVIL_TEST_PRIVATE_KEY_1) davonSCWClient = runBlocking { - Client().createV3( + Client().create( account = davonSCW, options = options ) @@ -66,7 +65,7 @@ class SmartContractWalletTest { // SCW eriSCW = FakeSCWWallet.generate(ANVIL_TEST_PRIVATE_KEY_2) eriSCWClient = runBlocking { - Client().createV3( + Client().create( account = eriSCW, options = options ) @@ -77,7 +76,7 @@ class SmartContractWalletTest { @Test fun testCanBuildASCW() { val davonSCWClient2 = runBlocking { - Client().buildV3( + Client().build( address = davonSCW.address, options = options ) @@ -159,15 +158,29 @@ class SmartContractWalletTest { ) ) } - assert(davonSCWClient.contacts.isGroupAllowed(davonGroup.id)) + assertEquals( + davonSCWClient.preferences.consentList.groupState(davonGroup.id), + ConsentState.ALLOWED + ) assertEquals(davonGroup.consentState(), ConsentState.ALLOWED) - davonSCWClient.contacts.denyGroups(listOf(davonGroup.id)) - assert(davonSCWClient.contacts.isGroupDenied(davonGroup.id)) + davonSCWClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + davonGroup.id, + EntryType.GROUP_ID, + ConsentState.DENIED + ) + ) + ) + assertEquals(davonSCWClient.preferences.consentList.groupState(davonGroup.id), ConsentState.DENIED) assertEquals(davonGroup.consentState(), ConsentState.DENIED) davonGroup.updateConsentState(ConsentState.ALLOWED) - assert(davonSCWClient.contacts.isGroupAllowed(davonGroup.id)) + assertEquals( + davonSCWClient.preferences.consentList.groupState(davonGroup.id), + ConsentState.ALLOWED + ) assertEquals(davonGroup.consentState(), ConsentState.ALLOWED) } } @@ -183,30 +196,64 @@ class SmartContractWalletTest { ) ) } - assert(!davonSCWClient.contacts.isInboxAllowed(boV3Client.inboxId)) - assert(!davonSCWClient.contacts.isInboxDenied(boV3Client.inboxId)) + assertEquals( + davonSCWClient.preferences.consentList.inboxIdState(boV3Client.inboxId), + ConsentState.UNKNOWN + ) + davonSCWClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + boV3Client.inboxId, + EntryType.INBOX_ID, + ConsentState.ALLOWED + ) + ) + ) + var alixMember = davonGroup.members().firstOrNull { it.inboxId == boV3Client.inboxId } + assertEquals(alixMember!!.consentState, ConsentState.ALLOWED) - davonSCWClient.contacts.allowInboxes(listOf(boV3Client.inboxId)) - var caroMember = davonGroup.members().firstOrNull { it.inboxId == boV3Client.inboxId } - assertEquals(caroMember!!.consentState, ConsentState.ALLOWED) + assertEquals( + davonSCWClient.preferences.consentList.inboxIdState(boV3Client.inboxId), + ConsentState.ALLOWED + ) - assert(davonSCWClient.contacts.isInboxAllowed(boV3Client.inboxId)) - assert(!davonSCWClient.contacts.isInboxDenied(boV3Client.inboxId)) - assert(davonSCWClient.contacts.isAllowed(boV3Client.address)) - assert(!davonSCWClient.contacts.isDenied(boV3Client.address)) + davonSCWClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + boV3Client.inboxId, + EntryType.INBOX_ID, + ConsentState.DENIED + ) + ) + ) + alixMember = davonGroup.members().firstOrNull { it.inboxId == boV3Client.inboxId } + assertEquals(alixMember!!.consentState, ConsentState.DENIED) - davonSCWClient.contacts.denyInboxes(listOf(boV3Client.inboxId)) - caroMember = davonGroup.members().firstOrNull { it.inboxId == boV3Client.inboxId } - assertEquals(caroMember!!.consentState, ConsentState.DENIED) + assertEquals( + davonSCWClient.preferences.consentList.inboxIdState(boV3Client.inboxId), + ConsentState.DENIED + ) - assert(!davonSCWClient.contacts.isInboxAllowed(boV3Client.inboxId)) - assert(davonSCWClient.contacts.isInboxDenied(boV3Client.inboxId)) - davonSCWClient.contacts.allow(listOf(eriSCWClient.address)) - assert(davonSCWClient.contacts.isAllowed(eriSCWClient.address)) - assert(!davonSCWClient.contacts.isDenied(eriSCWClient.address)) - assert(davonSCWClient.contacts.isInboxAllowed(eriSCWClient.inboxId)) - assert(!davonSCWClient.contacts.isInboxDenied(eriSCWClient.inboxId)) + davonSCWClient.preferences.consentList.setConsentState( + listOf( + ConsentListEntry( + eriSCWClient.address, + EntryType.ADDRESS, + ConsentState.ALLOWED + ) + ) + ) + alixMember = davonGroup.members().firstOrNull { it.inboxId == eriSCWClient.inboxId } + assertEquals(alixMember!!.consentState, ConsentState.ALLOWED) + assertEquals( + davonSCWClient.preferences.consentList.inboxIdState(eriSCWClient.inboxId), + ConsentState.ALLOWED + ) + assertEquals( + davonSCWClient.preferences.consentList.addressState(eriSCWClient.address), + ConsentState.ALLOWED + ) } } diff --git a/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt b/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt index 2b68048b0..78fcfde49 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt @@ -1,5 +1,6 @@ package org.xmtp.android.library +import androidx.test.platform.app.InstrumentationRegistry import kotlinx.coroutines.runBlocking import org.web3j.abi.FunctionEncoder import org.web3j.abi.datatypes.DynamicBytes @@ -12,17 +13,13 @@ import org.web3j.tx.gas.DefaultGasProvider import org.web3j.utils.Numeric import org.xmtp.android.library.artifact.CoinbaseSmartWallet import org.xmtp.android.library.artifact.CoinbaseSmartWalletFactory -import org.xmtp.android.library.messages.ContactBundle -import org.xmtp.android.library.messages.Envelope import org.xmtp.android.library.messages.PrivateKey import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.Signature -import org.xmtp.android.library.messages.Topic import org.xmtp.android.library.messages.ethHash -import org.xmtp.android.library.messages.toPublicKeyBundle import org.xmtp.android.library.messages.walletAddress import java.math.BigInteger -import java.util.Date +import java.security.SecureRandom class FakeWallet : SigningKey { private var privateKey: PrivateKey @@ -143,43 +140,30 @@ class FakeSCWWallet : SigningKey { } } -data class Fixtures( - val clientOptions: ClientOptions? = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, isSecure = false) - ), -) { - val aliceAccount = PrivateKeyBuilder() - val bobAccount = PrivateKeyBuilder() +class Fixtures { + val key = SecureRandom().generateSeed(32) + val context = InstrumentationRegistry.getInstrumentation().targetContext + val clientOptions = ClientOptions( + ClientOptions.Api(XMTPEnvironment.LOCAL, isSecure = false), + dbEncryptionKey = key, + appContext = context, + ) + val alixAccount = PrivateKeyBuilder() + val boAccount = PrivateKeyBuilder() val caroAccount = PrivateKeyBuilder() - val davonV3Account = PrivateKeyBuilder() - var alice: PrivateKey = aliceAccount.getPrivateKey() - var aliceClient: Client = - runBlocking { Client().create(account = aliceAccount, options = clientOptions) } + var alix: PrivateKey = alixAccount.getPrivateKey() + var alixClient: Client = + runBlocking { Client().create(account = alixAccount, options = clientOptions) } - var bob: PrivateKey = bobAccount.getPrivateKey() - var bobClient: Client = - runBlocking { Client().create(account = bobAccount, options = clientOptions) } + var bo: PrivateKey = boAccount.getPrivateKey() + var boClient: Client = + runBlocking { Client().create(account = boAccount, options = clientOptions) } var caro: PrivateKey = caroAccount.getPrivateKey() var caroClient: Client = runBlocking { Client().create(account = caroAccount, options = clientOptions) } - - fun publishLegacyContact(client: Client) { - val contactBundle = ContactBundle.newBuilder().also { builder -> - builder.v1 = builder.v1.toBuilder().also { - it.keyBundle = client.v1keys.toPublicKeyBundle() - }.build() - }.build() - val envelope = Envelope.newBuilder().apply { - contentTopic = Topic.contact(client.address).description - timestampNs = (Date().time * 1_000_000) - message = contactBundle.toByteString() - }.build() - - runBlocking { client.publish(envelopes = listOf(envelope)) } - } } -fun fixtures(clientOptions: ClientOptions? = null): Fixtures = - Fixtures(clientOptions) +fun fixtures(): Fixtures = + Fixtures() diff --git a/library/src/androidTest/java/org/xmtp/android/library/V3ClientTest.kt b/library/src/androidTest/java/org/xmtp/android/library/V3ClientTest.kt deleted file mode 100644 index 17e0051b6..000000000 --- a/library/src/androidTest/java/org/xmtp/android/library/V3ClientTest.kt +++ /dev/null @@ -1,396 +0,0 @@ -package org.xmtp.android.library - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.junit.Assert -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.xmtp.android.library.libxmtp.Message -import org.xmtp.android.library.libxmtp.Message.* -import org.xmtp.android.library.messages.PrivateKey -import org.xmtp.android.library.messages.PrivateKeyBuilder -import org.xmtp.android.library.messages.walletAddress -import java.security.SecureRandom - -@RunWith(AndroidJUnit4::class) -class V3ClientTest { - private lateinit var alixV2Wallet: PrivateKeyBuilder - private lateinit var boV3Wallet: PrivateKeyBuilder - private lateinit var alixV2: PrivateKey - private lateinit var alixV2Client: Client - private lateinit var boV3: PrivateKey - private lateinit var boV3Client: Client - private lateinit var caroV2V3Wallet: PrivateKeyBuilder - private lateinit var caroV2V3: PrivateKey - private lateinit var caroV2V3Client: Client - - @Before - fun setUp() { - val key = SecureRandom().generateSeed(32) - val context = InstrumentationRegistry.getInstrumentation().targetContext - - // Pure V2 - alixV2Wallet = PrivateKeyBuilder() - alixV2 = alixV2Wallet.getPrivateKey() - alixV2Client = runBlocking { - Client().create( - account = alixV2Wallet, - options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, isSecure = false) - ) - ) - } - - // Pure V3 - boV3Wallet = PrivateKeyBuilder() - boV3 = boV3Wallet.getPrivateKey() - boV3Client = runBlocking { - Client().createV3( - account = boV3Wallet, - options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - ) - } - - // Both V3 & V2 - caroV2V3Wallet = PrivateKeyBuilder() - caroV2V3 = caroV2V3Wallet.getPrivateKey() - caroV2V3Client = - runBlocking { - Client().create( - account = caroV2V3Wallet, - options = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableV3 = true, - appContext = context, - dbEncryptionKey = key - ) - ) - } - } - - @Test - fun testsCanCreateGroup() { - val group = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - assertEquals( - runBlocking { group.members().map { it.inboxId }.sorted() }, - listOf(caroV2V3Client.inboxId, boV3Client.inboxId).sorted() - ) - - Assert.assertThrows("Recipient not on network", XMTPException::class.java) { - runBlocking { boV3Client.conversations.newGroup(listOf(alixV2.walletAddress)) } - } - } - - @Test - fun testsCanCreateDm() { - val dm = runBlocking { boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) } - assertEquals( - runBlocking { dm.members().map { it.inboxId }.sorted() }, - listOf(caroV2V3Client.inboxId, boV3Client.inboxId).sorted() - ) - - val sameDm = runBlocking { boV3Client.findDm(caroV2V3.walletAddress) } - assertEquals(sameDm?.id, dm.id) - - runBlocking { caroV2V3Client.conversations.syncConversations() } - val caroDm = runBlocking { caroV2V3Client.findDm(boV3Client.address) } - assertEquals(caroDm?.id, dm.id) - - Assert.assertThrows("Recipient not on network", XMTPException::class.java) { - runBlocking { boV3Client.conversations.findOrCreateDm(alixV2.walletAddress) } - } - } - - @Test - fun testsCanFindConversationByTopic() { - val group = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - val dm = runBlocking { boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) } - - val sameDm = boV3Client.findConversationByTopic(dm.topic) - val sameGroup = boV3Client.findConversationByTopic(group.topic) - assertEquals(group.id, sameGroup?.id) - assertEquals(dm.id, sameDm?.id) - } - - @Test - fun testsCanListConversations() { - val dm = runBlocking { boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) } - val group = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - assertEquals(runBlocking { boV3Client.conversations.list().size }, 2) - assertEquals(runBlocking { boV3Client.conversations.listDms().size }, 1) - assertEquals(runBlocking { boV3Client.conversations.listGroups().size }, 1) - - runBlocking { caroV2V3Client.conversations.syncConversations() } - assertEquals( - runBlocking { caroV2V3Client.conversations.list().size }, - 1 - ) - assertEquals(runBlocking { caroV2V3Client.conversations.listGroups().size }, 1) - } - - @Test - fun testsCanListConversationsFiltered() { - val dm = runBlocking { boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) } - val group = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - assertEquals(runBlocking { boV3Client.conversations.list().size }, 2) - assertEquals( - runBlocking { boV3Client.conversations.list(consentState = ConsentState.ALLOWED).size }, - 2 - ) - runBlocking { group.updateConsentState(ConsentState.DENIED) } - assertEquals( - runBlocking { boV3Client.conversations.list(consentState = ConsentState.ALLOWED).size }, - 1 - ) - assertEquals( - runBlocking { boV3Client.conversations.list(consentState = ConsentState.DENIED).size }, - 1 - ) - assertEquals(runBlocking { boV3Client.conversations.list().size }, 2) - } - - @Test - fun testCanListConversationsOrder() { - val dm = runBlocking { boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) } - val group1 = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - val group2 = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - runBlocking { dm.send("Howdy") } - runBlocking { group2.send("Howdy") } - runBlocking { boV3Client.conversations.syncAllConversations() } - val conversations = runBlocking { boV3Client.conversations.list() } - val conversationsOrdered = - runBlocking { boV3Client.conversations.list(order = Conversations.ConversationOrder.LAST_MESSAGE) } - assertEquals(conversations.size, 3) - assertEquals(conversationsOrdered.size, 3) - assertEquals(conversations.map { it.id }, listOf(dm.id, group1.id, group2.id)) - assertEquals(conversationsOrdered.map { it.id }, listOf(group2.id, dm.id, group1.id)) - } - - @Test - fun testsCanSendMessagesToGroup() { - val group = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - runBlocking { group.send("howdy") } - val messageId = runBlocking { group.send("gm") } - runBlocking { group.sync() } - assertEquals(group.messages().first().body, "gm") - assertEquals(group.messages().first().id, messageId) - assertEquals(group.messages().first().deliveryStatus, MessageDeliveryStatus.PUBLISHED) - assertEquals(group.messages().size, 3) - - runBlocking { caroV2V3Client.conversations.syncConversations() } - val sameGroup = runBlocking { caroV2V3Client.conversations.listGroups().last() } - runBlocking { sameGroup.sync() } - assertEquals(sameGroup.messages().size, 2) - assertEquals(sameGroup.messages().first().body, "gm") - } - - @Test - fun testsCanSendMessagesToDm() { - var boDm = - runBlocking { boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) } - runBlocking { boDm.send("howdy") } - var messageId = runBlocking { boDm.send("gm") } - var boDmMessage = runBlocking { boDm.messages() } - assertEquals(boDmMessage.first().body, "gm") - assertEquals(boDmMessage.first().id, messageId) - assertEquals(boDmMessage.first().deliveryStatus, MessageDeliveryStatus.PUBLISHED) - assertEquals(boDmMessage.size, 3) - - runBlocking { caroV2V3Client.conversations.syncConversations() } - val caroDm = runBlocking { caroV2V3Client.findDm(boV3.walletAddress) } - runBlocking { caroDm!!.sync() } - var caroDmMessage = runBlocking { caroDm!!.messages() } - assertEquals(caroDmMessage.size, 2) - assertEquals(caroDmMessage.first().body, "gm") - - runBlocking { caroDm!!.send("howdy") } - messageId = runBlocking { caroDm!!.send("gm") } - caroDmMessage = runBlocking { caroDm!!.messages() } - assertEquals(caroDmMessage.first().body, "gm") - assertEquals(caroDmMessage.first().id, messageId) - assertEquals(caroDmMessage.first().deliveryStatus, MessageDeliveryStatus.PUBLISHED) - assertEquals(caroDmMessage.size, 4) - - runBlocking { boV3Client.conversations.syncConversations() } - boDm = runBlocking { boV3Client.findDm(caroV2V3.walletAddress)!! } - runBlocking { boDm.sync() } - boDmMessage = runBlocking { boDm.messages() } - assertEquals(boDmMessage.size, 5) - assertEquals(boDmMessage.first().body, "gm") - } - - @Test - fun testGroupConsent() { - runBlocking { - val group = boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) - assert(boV3Client.contacts.isGroupAllowed(group.id)) - assertEquals(group.consentState(), ConsentState.ALLOWED) - - boV3Client.contacts.denyGroups(listOf(group.id)) - assert(boV3Client.contacts.isGroupDenied(group.id)) - assertEquals(group.consentState(), ConsentState.DENIED) - - group.updateConsentState(ConsentState.ALLOWED) - assert(boV3Client.contacts.isGroupAllowed(group.id)) - assertEquals(group.consentState(), ConsentState.ALLOWED) - } - } - - @Test - fun testCanAllowAndDenyInboxId() { - runBlocking { - val boGroup = boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) - assert(!boV3Client.contacts.isInboxAllowed(caroV2V3Client.inboxId)) - assert(!boV3Client.contacts.isInboxDenied(caroV2V3Client.inboxId)) - - boV3Client.contacts.allowInboxes(listOf(caroV2V3Client.inboxId)) - var caroMember = boGroup.members().firstOrNull { it.inboxId == caroV2V3Client.inboxId } - assertEquals(caroMember!!.consentState, ConsentState.ALLOWED) - - assert(boV3Client.contacts.isInboxAllowed(caroV2V3Client.inboxId)) - assert(!boV3Client.contacts.isInboxDenied(caroV2V3Client.inboxId)) - assert(boV3Client.contacts.isAllowed(caroV2V3Client.address)) - assert(!boV3Client.contacts.isDenied(caroV2V3Client.address)) - - boV3Client.contacts.denyInboxes(listOf(caroV2V3Client.inboxId)) - caroMember = boGroup.members().firstOrNull { it.inboxId == caroV2V3Client.inboxId } - assertEquals(caroMember!!.consentState, ConsentState.DENIED) - - assert(!boV3Client.contacts.isInboxAllowed(caroV2V3Client.inboxId)) - assert(boV3Client.contacts.isInboxDenied(caroV2V3Client.inboxId)) - - // Cannot check inboxId for alix because they do not have an inboxID as V2 only client. - boV3Client.contacts.allow(listOf(alixV2Client.address)) - assert(boV3Client.contacts.isAllowed(alixV2Client.address)) - assert(!boV3Client.contacts.isDenied(alixV2Client.address)) - } - } - - @Test - fun testCanStreamAllMessagesFromV3Users() { - val group = - runBlocking { caroV2V3Client.conversations.newGroup(listOf(boV3.walletAddress)) } - val conversation = - runBlocking { boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) } - runBlocking { boV3Client.conversations.syncConversations() } - - val allMessages = mutableListOf() - - val job = CoroutineScope(Dispatchers.IO).launch { - try { - boV3Client.conversations.streamAllMessages() - .collect { message -> - allMessages.add(message) - } - } catch (e: Exception) { - } - } - Thread.sleep(1000) - runBlocking { - group.send("hi") - conversation.send("hi") - } - Thread.sleep(1000) - assertEquals(2, allMessages.size) - job.cancel() - } - - @Test - fun testCanStreamGroupsAndConversationsFromV3Users() { - val allMessages = mutableListOf() - - val job = CoroutineScope(Dispatchers.IO).launch { - try { - boV3Client.conversations.stream() - .collect { message -> - allMessages.add(message.topic) - } - } catch (e: Exception) { - } - } - Thread.sleep(1000) - - runBlocking { - caroV2V3Client.conversations.newGroup(listOf(boV3.walletAddress)) - Thread.sleep(1000) - boV3Client.conversations.findOrCreateDm(caroV2V3.walletAddress) - } - - Thread.sleep(2000) - assertEquals(2, allMessages.size) - job.cancel() - } - - @Test - fun testCanStreamAllMessagesFromV2andV3Users() { - val group = - runBlocking { boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) } - val conversation = - runBlocking { alixV2Client.conversations.newConversation(caroV2V3.walletAddress) } - runBlocking { caroV2V3Client.conversations.syncConversations() } - - val allMessages = mutableListOf() - - val job = CoroutineScope(Dispatchers.IO).launch { - try { - caroV2V3Client.conversations.streamAllMessages() - .collect { message -> - allMessages.add(message) - } - } catch (e: Exception) { - } - } - Thread.sleep(1000) - runBlocking { - group.send("hi") - conversation.send("hi") - } - Thread.sleep(1000) - assertEquals(2, allMessages.size) - job.cancel() - } - - @Test - fun testCanStreamGroupsAndConversationsFromV2andV3Users() { - val allMessages = mutableListOf() - - val job = CoroutineScope(Dispatchers.IO).launch { - try { - caroV2V3Client.conversations.stream() - .collect { message -> - allMessages.add(message.topic) - } - } catch (e: Exception) { - } - } - Thread.sleep(1000) - - runBlocking { - alixV2Client.conversations.newConversation(caroV2V3.walletAddress) - Thread.sleep(1000) - boV3Client.conversations.newGroup(listOf(caroV2V3.walletAddress)) - } - - Thread.sleep(2000) - assertEquals(2, allMessages.size) - job.cancel() - } -} 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 60e907d8c..f22fa5c48 100644 --- a/library/src/main/java/org/xmtp/android/library/Client.kt +++ b/library/src/main/java/org/xmtp/android/library/Client.kt @@ -43,10 +43,10 @@ class Client() { lateinit var preferences: PrivatePreferences lateinit var conversations: Conversations lateinit var environment: XMTPEnvironment - lateinit var ffiClient: FfiXmtpClient lateinit var dbPath: String var logger: XMTPLogger = XMTPLogger() val libXMTPVersion: String = getVersionInfo() + private lateinit var ffiClient: FfiXmtpClient companion object { private const val TAG = "Client" @@ -84,7 +84,7 @@ class Client() { environment: XMTPEnvironment, ) : this() { this.address = address - this.preferences = PrivatePreferences(client = this) + this.preferences = PrivatePreferences(client = this, ffiClient = libXMTPClient) this.ffiClient = libXMTPClient this.conversations = Conversations(client = this, libXMTPConversations = libXMTPClient.conversations()) diff --git a/library/src/main/java/org/xmtp/android/library/PrivatePreferences.kt b/library/src/main/java/org/xmtp/android/library/PrivatePreferences.kt index 0f4a40854..50787141b 100644 --- a/library/src/main/java/org/xmtp/android/library/PrivatePreferences.kt +++ b/library/src/main/java/org/xmtp/android/library/PrivatePreferences.kt @@ -3,6 +3,7 @@ package org.xmtp.android.library import uniffi.xmtpv3.FfiConsent import uniffi.xmtpv3.FfiConsentEntityType import uniffi.xmtpv3.FfiConsentState +import uniffi.xmtpv3.FfiXmtpClient enum class ConsentState { ALLOWED, @@ -86,9 +87,10 @@ data class ConsentListEntry( class ConsentList( val client: Client, + private val ffiClient: FfiXmtpClient ) { suspend fun setConsentState(entries: List) { - client.ffiClient.setConsentStates(entries.map { it.toFfiConsent() }) + ffiClient.setConsentStates(entries.map { it.toFfiConsent() }) } private fun ConsentListEntry.toFfiConsent(): FfiConsent { @@ -101,7 +103,7 @@ class ConsentList( suspend fun addressState(address: String): ConsentState { return ConsentState.fromFfiConsentState( - client.ffiClient.getConsentState( + ffiClient.getConsentState( FfiConsentEntityType.ADDRESS, address ) @@ -110,7 +112,7 @@ class ConsentList( suspend fun groupState(groupId: String): ConsentState { return ConsentState.fromFfiConsentState( - client.ffiClient.getConsentState( + ffiClient.getConsentState( FfiConsentEntityType.CONVERSATION_ID, groupId ) @@ -119,7 +121,7 @@ class ConsentList( suspend fun inboxIdState(inboxId: String): ConsentState { return ConsentState.fromFfiConsentState( - client.ffiClient.getConsentState( + ffiClient.getConsentState( FfiConsentEntityType.INBOX_ID, inboxId ) @@ -129,5 +131,6 @@ class ConsentList( data class PrivatePreferences( var client: Client, - var consentList: ConsentList = ConsentList(client), + private val ffiClient: FfiXmtpClient, + var consentList: ConsentList = ConsentList(client, ffiClient), ) diff --git a/library/src/main/java/org/xmtp/android/library/SigningKey.kt b/library/src/main/java/org/xmtp/android/library/SigningKey.kt index f680766ce..5f34bae3e 100644 --- a/library/src/main/java/org/xmtp/android/library/SigningKey.kt +++ b/library/src/main/java/org/xmtp/android/library/SigningKey.kt @@ -1,20 +1,6 @@ package org.xmtp.android.library -import com.google.protobuf.kotlin.toByteString -import kotlinx.coroutines.runBlocking -import org.web3j.crypto.ECDSASignature -import org.web3j.crypto.Keys -import org.web3j.crypto.Sign -import org.xmtp.android.library.messages.PublicKey -import org.xmtp.android.library.messages.Signature -import org.xmtp.android.library.messages.createIdentityText -import org.xmtp.android.library.messages.ethHash -import org.xmtp.android.library.messages.rawData -import org.xmtp.proto.message.contents.PrivateKeyOuterClass -import org.xmtp.proto.message.contents.PublicKeyOuterClass import org.xmtp.proto.message.contents.SignatureOuterClass -import java.math.BigInteger -import java.util.Date interface SigningKey { val address: String diff --git a/library/src/main/java/org/xmtp/android/library/messages/PrivateKey.kt b/library/src/main/java/org/xmtp/android/library/messages/PrivateKey.kt index f67a0d4e4..7f251d33b 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/PrivateKey.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/PrivateKey.kt @@ -1,13 +1,10 @@ package org.xmtp.android.library.messages import com.google.protobuf.kotlin.toByteString -import kotlinx.coroutines.runBlocking import org.web3j.crypto.ECKeyPair -import org.web3j.crypto.Hash import org.web3j.crypto.Sign import org.xmtp.android.library.KeyUtil import org.xmtp.android.library.SigningKey -import org.xmtp.proto.message.contents.PublicKeyOuterClass import org.xmtp.proto.message.contents.SignatureOuterClass import java.security.SecureRandom import java.util.Date @@ -97,15 +94,3 @@ fun PrivateKey.generate(): PrivateKey { val PrivateKey.walletAddress: String get() = publicKey.walletAddress - -fun PrivateKey.sign(key: PublicKeyOuterClass.UnsignedPublicKey): PublicKeyOuterClass.SignedPublicKey { - val bytes = key.toByteArray() - val signedPublicKey = PublicKeyOuterClass.SignedPublicKey.newBuilder() - val builder = PrivateKeyBuilder(this) - val signature = runBlocking { - builder.sign(Hash.sha256(bytes)) - } - signedPublicKey.signature = signature - signedPublicKey.keyBytes = bytes.toByteString() - return signedPublicKey.build() -} diff --git a/library/src/main/java/org/xmtp/android/library/messages/PublicKey.kt b/library/src/main/java/org/xmtp/android/library/messages/PublicKey.kt index c3e6b0387..ada795f49 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/PublicKey.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/PublicKey.kt @@ -1,50 +1,10 @@ package org.xmtp.android.library.messages -import com.google.protobuf.kotlin.toByteString import org.bouncycastle.util.Arrays import org.web3j.crypto.Keys -import org.web3j.crypto.Sign -import org.xmtp.android.library.KeyUtil -import org.xmtp.android.library.XMTPException import org.xmtp.android.library.toHex -import org.xmtp.proto.message.contents.PublicKeyOuterClass -import java.util.Date typealias PublicKey = org.xmtp.proto.message.contents.PublicKeyOuterClass.PublicKey - -class PublicKeyBuilder { - companion object { - fun buildFromSignedPublicKey(signedPublicKey: PublicKeyOuterClass.SignedPublicKey): PublicKey { - val unsignedPublicKey = PublicKey.parseFrom(signedPublicKey.keyBytes) - return PublicKey.newBuilder().apply { - timestamp = unsignedPublicKey.timestamp - secp256K1Uncompressed = secp256K1Uncompressed.toBuilder().also { - it.bytes = unsignedPublicKey.secp256K1Uncompressed.bytes - }.build() - var sig = signedPublicKey.signature - if (!sig.walletEcdsaCompact.bytes.isEmpty) { - sig = sig.toBuilder().apply { - ecdsaCompact = ecdsaCompact.toBuilder().also { - it.bytes = signedPublicKey.signature.walletEcdsaCompact.bytes - it.recovery = signedPublicKey.signature.walletEcdsaCompact.recovery - }.build() - }.build() - } - signature = sig - }.build() - } - - fun buildFromBytes(data: ByteArray): PublicKey { - return PublicKey.newBuilder().apply { - timestamp = Date().time - secp256K1Uncompressed = secp256K1Uncompressed.toBuilder().apply { - bytes = data.toByteString() - }.build() - }.build() - } - } -} - val PublicKey.walletAddress: String get() { val address = Keys.getAddress( @@ -55,25 +15,4 @@ val PublicKey.walletAddress: String ) ) return Keys.toChecksumAddress(address.toHex()) - } - -fun PublicKey.recoverWalletSignerPublicKey(): PublicKey { - if (!hasSignature()) { - throw XMTPException("No signature found") - } - - val slimKey = PublicKey.newBuilder().also { - it.timestamp = timestamp - it.secp256K1Uncompressed = it.secp256K1Uncompressed.toBuilder().also { keyBuilder -> - keyBuilder.bytes = secp256K1Uncompressed.bytes - }.build() - }.build() - val signatureClass = Signature.newBuilder().build() - val sigText = signatureClass.createIdentityText(slimKey.toByteArray()) - val sigHash = signatureClass.ethHash(sigText) - val pubKeyData = Sign.signedMessageHashToKey( - sigHash, - KeyUtil.getSignatureData(signature.rawDataWithNormalizedRecovery) - ) - return PublicKeyBuilder.buildFromBytes(KeyUtil.addUncompressedByte(pubKeyData.toByteArray())) -} + } \ No newline at end of file diff --git a/library/src/main/java/org/xmtp/android/library/messages/Signature.kt b/library/src/main/java/org/xmtp/android/library/messages/Signature.kt index 6fe92e792..46fac0585 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/Signature.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/Signature.kt @@ -29,26 +29,6 @@ fun Signature.ethHash(message: String): ByteArray { return Util.keccak256(input.toByteArray()) } -/** - * This is the text that users sign when they want to create - * an identity key associated with their wallet. - * @param key bytes contains an unsigned [xmtp.PublicKey] of the identity key to be created. - * @return The resulting signature is then published to prove that the - * identity key is authorized on behalf of the wallet. - */ -fun Signature.createIdentityText(key: ByteArray): String = - ("XMTP : Create Identity\n" + "${key.toHex()}\n" + "\n" + "For more info: https://xmtp.org/signatures/") - -/** - * This is the text that users sign when they want to save (encrypt) - * or to load (decrypt) keys using the network private storage. - * @param key bytes contains the `walletPreKey` of the encrypted bundle. - * @return The resulting signature is the shared secret used to encrypt and - * decrypt the saved keys. - */ -fun Signature.enableIdentityText(key: ByteArray): String = - ("XMTP : Enable Identity\n" + "${key.toHex()}\n" + "\n" + "For more info: https://xmtp.org/signatures/") - fun Signature.consentProofText(peerAddress: String, timestamp: Long): String { val formatter = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'") formatter.timeZone = TimeZone.getTimeZone("UTC") diff --git a/library/src/test/java/org/xmtp/android/library/AuthenticationTest.kt b/library/src/test/java/org/xmtp/android/library/AuthenticationTest.kt deleted file mode 100644 index 3a5ca4f06..000000000 --- a/library/src/test/java/org/xmtp/android/library/AuthenticationTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -package org.xmtp.android.library - -import com.google.protobuf.kotlin.toByteStringUtf8 -import junit.framework.TestCase.fail -import org.junit.Assert.assertEquals -import org.junit.Test -import org.xmtp.android.library.messages.AuthData -import org.xmtp.android.library.messages.PrivateKey -import org.xmtp.android.library.messages.PrivateKeyBuilder -import org.xmtp.android.library.messages.Token -import org.xmtp.android.library.messages.decrypted -import org.xmtp.android.library.messages.encrypted -import org.xmtp.android.library.messages.generate - -class AuthenticationTest { - - @Test - fun testCreateToken() { - val privateKey = PrivateKeyBuilder() - val identity = PrivateKey.newBuilder().build().generate() - // Prompt them to sign "XMTP : Create Identity ..." - val authorized = privateKey.createIdentity(identity) - // Create the `Authorization: Bearer $authToken` for API calls. - val authToken = authorized.createAuthToken() - val tokenData = authToken.toByteStringUtf8().toByteArray() - val base64TokenData = com.google.crypto.tink.subtle.Base64.decode(tokenData, 2) - if (tokenData.isEmpty() || base64TokenData.isEmpty()) { - fail("could not get token data") - return - } - val token = Token.parseFrom(base64TokenData) - val authData = AuthData.parseFrom(token.authDataBytes) - assertEquals(authData.walletAddr, authorized.address) - } - - @Test - fun testEnablingSavingAndLoadingOfStoredKeys() { - val alice = PrivateKeyBuilder() - val identity = PrivateKey.newBuilder().build().generate() - val authorized = alice.createIdentity(identity) - val bundle = authorized.toBundle - val encryptedBundle = bundle.encrypted(alice) - val decrypted = encryptedBundle.decrypted(alice) - assertEquals(decrypted.v1.identityKey.secp256K1.bytes, identity.secp256K1.bytes) - assertEquals(decrypted.v1.identityKey.publicKey, authorized.authorized) - } -} diff --git a/library/src/test/java/org/xmtp/android/library/ContactTest.kt b/library/src/test/java/org/xmtp/android/library/ContactTest.kt deleted file mode 100644 index 0e22b37e8..000000000 --- a/library/src/test/java/org/xmtp/android/library/ContactTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -package org.xmtp.android.library - -import com.google.protobuf.kotlin.toByteString -import org.junit.Assert.assertEquals -import org.junit.Test -import org.xmtp.android.library.messages.ContactBundleBuilder -import org.xmtp.android.library.messages.Envelope -import org.xmtp.android.library.messages.identityAddress -import org.xmtp.android.library.messages.walletAddress - -class ContactTest { - - @Test - fun testParsingV2Bundle() { - val ints = arrayOf( - 18, 181, 2, 10, 178, 2, 10, 150, 1, 10, 76, 8, 140, 241, 170, 138, 182, 48, 26, 67, 10, - 65, 4, 33, 132, 132, 43, 80, 179, 54, 132, 47, 151, 245, 23, 108, 148, 94, 190, 2, 33, - 232, 232, 185, 73, 64, 44, 47, 65, 168, 25, 56, 252, 1, 58, 243, 20, 103, 8, 253, 118, - 10, 1, 108, 158, 125, 149, 128, 37, 28, 250, 204, 1, 66, 194, 61, 119, 197, 121, 158, - 210, 234, 92, 79, 181, 1, 150, 18, 70, 18, 68, 10, 64, 43, 154, 228, 249, 69, 206, 218, - 165, 35, 55, 141, 145, 183, 129, 104, 75, 106, 62, 28, 73, 69, 7, 170, 65, 66, 93, 11, - 184, 229, 204, 140, 101, 71, 74, 0, 227, 140, 89, 53, 35, 203, 180, 87, 102, 89, 176, - 57, 128, 165, 42, 214, 173, 199, 17, 159, 200, 254, 25, 80, 227, 20, 16, 189, 92, 16, 1, - 18, 150, 1, 10, 76, 8, 244, 246, 171, 138, 182, 48, 26, 67, 10, 65, 4, 104, 191, 167, - 212, 49, 159, 46, 123, 133, 52, 69, 73, 137, 157, 76, 63, 233, 223, 129, 64, 138, 86, - 91, 26, 191, 241, 109, 249, 216, 96, 226, 255, 103, 29, 192, 3, 181, 228, 63, 52, 101, - 88, 96, 141, 236, 194, 111, 16, 105, 88, 127, 215, 255, 63, 92, 135, 251, 14, 176, 85, - 65, 211, 88, 80, 18, 70, 10, 68, 10, 64, 252, 165, 96, 161, 187, 19, 203, 60, 89, 195, - 73, 176, 189, 203, 109, 113, 106, 39, 71, 116, 44, 101, 180, 16, 243, 70, 128, 58, 46, - 10, 55, 243, 43, 115, 21, 23, 153, 241, 208, 212, 162, 205, 197, 139, 2, 117, 1, 40, - 200, 252, 136, 148, 18, 125, 39, 175, 130, 113, 103, 83, 120, 60, 232, 109, 16, 1 - ) - val data = - ints.foldIndexed(ByteArray(ints.size)) { i, a, v -> a.apply { set(i, v.toByte()) } } - val envelope = Envelope.newBuilder().apply { - message = data.toByteString() - }.build() - val contactBundle = ContactBundleBuilder.buildFromEnvelope(envelope) - assert(!contactBundle.v1.hasKeyBundle()) - assert(contactBundle.v2.hasKeyBundle()) - assertEquals(contactBundle.walletAddress, "0x66942eC8b0A6d0cff51AEA9C7fd00494556E705F") - } - - @Test - fun testParsingV1Bundle() { - val ints = arrayOf( // This is a serialized PublicKeyBundle (instead of a ContactBundle) - 10, 146, 1, 8, 236, 130, 192, 166, 148, 48, 18, 68, 10, 66, 10, 64, 70, 34, 101, 46, 39, - 87, 114, 210, 103, 135, 87, 49, 162, 200, 82, 177, 11, 4, 137, 31, 235, 91, 185, 46, 177, - 208, 228, 102, 44, 61, 40, 131, 109, 210, 93, 42, 44, 235, 177, 73, 72, 234, 18, 32, 230, - 61, 146, 58, 65, 78, 178, 163, 164, 241, 118, 167, 77, 240, 13, 100, 151, 70, 190, 15, - 26, 67, 10, 65, 4, 8, 71, 173, 223, 174, 185, 150, 4, 179, 111, 144, 35, 5, 210, 6, 60, - 21, 131, 135, 52, 37, 221, 72, 126, 21, 103, 208, 31, 182, 76, 187, 72, 66, 92, 193, 74, - 161, 45, 135, 204, 55, 10, 20, 119, 145, 136, 45, 194, 140, 164, 124, 47, 238, 17, 198, - 243, 102, 171, 67, 128, 164, 117, 7, 83 - ) - val data = - ints.foldIndexed(ByteArray(ints.size)) { i, a, v -> a.apply { set(i, v.toByte()) } } - val envelope = Envelope.newBuilder().apply { - this.message = data.toByteString() - }.build() - val contactBundle = ContactBundleBuilder.buildFromEnvelope(envelope = envelope) - assertEquals(contactBundle.walletAddress, "0x66942eC8b0A6d0cff51AEA9C7fd00494556E705F") - assertEquals(contactBundle.identityAddress, "0xD320f1454e33ab9393c0cc596E6321d80e4b481e") - assert(!contactBundle.v1.keyBundle.hasPreKey()) - } -} diff --git a/library/src/test/java/org/xmtp/android/library/PreparedMessageTest.kt b/library/src/test/java/org/xmtp/android/library/PreparedMessageTest.kt deleted file mode 100644 index e2cbd5d2c..000000000 --- a/library/src/test/java/org/xmtp/android/library/PreparedMessageTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.xmtp.android.library - -import com.google.protobuf.kotlin.toByteStringUtf8 -import org.junit.Assert.assertEquals -import org.junit.Test -import org.xmtp.android.library.messages.Envelope - -class PreparedMessageTest { - - @Test - fun testSerializing() { - val original = PreparedMessage( - listOf( - Envelope.newBuilder().apply { - contentTopic = "topic1" - timestampNs = 1234 - message = "abc123".toByteStringUtf8() - }.build(), - Envelope.newBuilder().apply { - contentTopic = "topic2" - timestampNs = 5678 - message = "def456".toByteStringUtf8() - }.build(), - ) - ) - val serialized = original.toSerializedData() - val unserialized = PreparedMessage.fromSerializedData(serialized) - assertEquals(original, unserialized) - } -} diff --git a/library/src/test/java/org/xmtp/android/library/PrivateKeyBundleTest.kt b/library/src/test/java/org/xmtp/android/library/PrivateKeyBundleTest.kt deleted file mode 100644 index 3c08b00ee..000000000 --- a/library/src/test/java/org/xmtp/android/library/PrivateKeyBundleTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -package org.xmtp.android.library - -import org.junit.Assert.assertEquals -import org.junit.Test -import org.xmtp.android.library.messages.PrivateKeyBuilder -import org.xmtp.android.library.messages.UnsignedPublicKey -import org.xmtp.android.library.messages.generate -import org.xmtp.android.library.messages.getPublicKeyBundle -import org.xmtp.android.library.messages.toPublicKeyBundle -import org.xmtp.android.library.messages.toV2 -import org.xmtp.proto.message.contents.PrivateKeyOuterClass - -class PrivateKeyBundleTest { - - @Test - fun testConversion() { - val wallet = PrivateKeyBuilder() - val v1 = - PrivateKeyOuterClass.PrivateKeyBundleV1.newBuilder().build().generate(wallet = wallet) - val v2 = v1.toV2() - val v2PreKeyPublic = UnsignedPublicKey.parseFrom(v2.preKeysList[0].publicKey.keyBytes) - assertEquals( - v1.preKeysList[0].publicKey.secp256K1Uncompressed.bytes, - v2PreKeyPublic.secp256K1Uncompressed.bytes - ) - } - - @Test - fun testKeyBundlesAreSigned() { - val wallet = PrivateKeyBuilder() - val v1 = - PrivateKeyOuterClass.PrivateKeyBundleV1.newBuilder().build().generate(wallet = wallet) - assert(v1.identityKey.publicKey.hasSignature()) - assert(v1.preKeysList[0].publicKey.hasSignature()) - assert(v1.toPublicKeyBundle().identityKey.hasSignature()) - assert(v1.toPublicKeyBundle().preKey.hasSignature()) - val v2 = v1.toV2() - assert(v2.identityKey.publicKey.hasSignature()) - assert(v2.preKeysList[0].publicKey.hasSignature()) - assert(v2.getPublicKeyBundle().identityKey.hasSignature()) - assert(v2.getPublicKeyBundle().preKey.hasSignature()) - } -} diff --git a/library/src/test/java/org/xmtp/android/library/TestHelpers.kt b/library/src/test/java/org/xmtp/android/library/TestHelpers.kt index 431cb9917..c28598658 100644 --- a/library/src/test/java/org/xmtp/android/library/TestHelpers.kt +++ b/library/src/test/java/org/xmtp/android/library/TestHelpers.kt @@ -1,11 +1,13 @@ package org.xmtp.android.library +import androidx.test.platform.app.InstrumentationRegistry import kotlinx.coroutines.runBlocking import org.xmtp.android.library.codecs.Fetcher import org.xmtp.android.library.messages.PrivateKey import org.xmtp.android.library.messages.PrivateKeyBuilder import java.io.File import java.net.URL +import java.security.SecureRandom class TestFetcher : Fetcher { override fun fetch(url: URL): ByteArray { @@ -16,21 +18,25 @@ class TestFetcher : Fetcher { data class Fixtures( val aliceAccount: PrivateKeyBuilder, val bobAccount: PrivateKeyBuilder, - val clientOptions: ClientOptions? = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, isSecure = false) - ), ) { - var aliceClient: Client = runBlocking { Client().create(account = aliceAccount, options = clientOptions) } + val key = SecureRandom().generateSeed(32) + val context = InstrumentationRegistry.getInstrumentation().targetContext + val clientOptions = ClientOptions( + ClientOptions.Api(XMTPEnvironment.LOCAL, isSecure = false), + dbEncryptionKey = key, + appContext = context, + ) + var aliceClient: Client = + runBlocking { Client().create(account = aliceAccount, options = clientOptions) } var alice: PrivateKey = aliceAccount.getPrivateKey() var bob: PrivateKey = bobAccount.getPrivateKey() - var bobClient: Client = runBlocking { Client().create(account = bobAccount, options = clientOptions) } + var bobClient: Client = + runBlocking { Client().create(account = bobAccount, options = clientOptions) } - constructor(clientOptions: ClientOptions?) : this( + constructor() : this( aliceAccount = PrivateKeyBuilder(), bobAccount = PrivateKeyBuilder(), - clientOptions = clientOptions ) } -fun fixtures(clientOptions: ClientOptions? = null): Fixtures = - Fixtures(clientOptions) +fun fixtures(): Fixtures = Fixtures()