Skip to content

Commit

Permalink
Create a pure v3 client (#298)
Browse files Browse the repository at this point in the history
* create a pure v3 client

* remove the nonce

* update the code to allow v3 only client and write a test

* fix up the tests

* Update library/src/main/java/org/xmtp/android/library/Client.kt

Co-authored-by: Cameron Voell <[email protected]>

* add very detailed tests

* unify the error logic

* fix up the example app

* fix linter

* skip a flaky test

* fix up test

* reorder check on apiClient

* update the test to be way more explicit

---------

Co-authored-by: Cameron Voell <[email protected]>
  • Loading branch information
nplasterer and cameronvoell authored Sep 18, 2024
1 parent 12a55d8 commit 8e37581
Show file tree
Hide file tree
Showing 14 changed files with 456 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class MainViewModel : ViewModel() {
MainListItem.Footer(
id = "footer",
ClientManager.client.address,
ClientManager.client.apiClient.environment.name
ClientManager.client.environment.name
)
)
_uiState.value = UiState.Success(listItems)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
Client.register(codec = GroupUpdatedCodec())
_uiState.value = ConnectUiState.Success(
wallet.address,
PrivateKeyBundleV1Builder.encodeData(client.privateKeyBundleV1)
PrivateKeyBundleV1Builder.encodeData(client.v1keys)
)
} catch (e: XMTPException) {
_uiState.value = ConnectUiState.Error(e.message.orEmpty())
Expand All @@ -115,7 +115,7 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
Client.register(codec = GroupUpdatedCodec())
_uiState.value = ConnectUiState.Success(
wallet.address,
PrivateKeyBundleV1Builder.encodeData(client.privateKeyBundleV1)
PrivateKeyBundleV1Builder.encodeData(client.v1keys)
)
} catch (e: Exception) {
_uiState.value = ConnectUiState.Error(e.message.orEmpty())
Expand Down
49 changes: 37 additions & 12 deletions library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class ClientTest {
fun testHasPrivateKeyBundleV1() {
val fakeWallet = PrivateKeyBuilder()
val client = runBlocking { Client().create(account = fakeWallet) }
assertEquals(1, client.privateKeyBundleV1.preKeysList?.size)
val preKey = client.privateKeyBundleV1.preKeysList?.get(0)
assertEquals(1, client.v1keys.preKeysList?.size)
val preKey = client.v1keys.preKeysList?.get(0)
assert(preKey?.publicKey?.hasSignature() ?: false)
}

Expand All @@ -56,12 +56,12 @@ class ClientTest {
val clientFromV1Bundle = runBlocking { Client().buildFromBundle(bundle) }
assertEquals(client.address, clientFromV1Bundle.address)
assertEquals(
client.privateKeyBundleV1.identityKey,
clientFromV1Bundle.privateKeyBundleV1.identityKey,
client.v1keys.identityKey,
clientFromV1Bundle.v1keys.identityKey,
)
assertEquals(
client.privateKeyBundleV1.preKeysList,
clientFromV1Bundle.privateKeyBundleV1.preKeysList,
client.v1keys.preKeysList,
clientFromV1Bundle.v1keys.preKeysList,
)
}

Expand All @@ -73,12 +73,12 @@ class ClientTest {
val clientFromV1Bundle = runBlocking { Client().buildFromV1Bundle(bundleV1) }
assertEquals(client.address, clientFromV1Bundle.address)
assertEquals(
client.privateKeyBundleV1.identityKey,
clientFromV1Bundle.privateKeyBundleV1.identityKey,
client.v1keys.identityKey,
clientFromV1Bundle.v1keys.identityKey,
)
assertEquals(
client.privateKeyBundleV1.preKeysList,
clientFromV1Bundle.privateKeyBundleV1.preKeysList,
client.v1keys.preKeysList,
clientFromV1Bundle.v1keys.preKeysList,
)
}

Expand Down Expand Up @@ -107,8 +107,8 @@ class ClientTest {
}
assertEquals(client.address, clientFromV1Bundle.address)
assertEquals(
client.privateKeyBundleV1.identityKey,
clientFromV1Bundle.privateKeyBundleV1.identityKey,
client.v1keys.identityKey,
clientFromV1Bundle.v1keys.identityKey,
)

runBlocking {
Expand Down Expand Up @@ -146,6 +146,31 @@ class ClientTest {
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().createOrBuild(
account = fakeWallet,
options = options
)
}
runBlocking {
client.canMessageV3(listOf(client.address))[client.address]?.let { assert(it) }
}
assert(client.installationId.isNotEmpty())
assertEquals(inboxId, client.inboxId)
}

@Test
fun testCanDeleteDatabase() {
val key = SecureRandom().generateSeed(32)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,31 +844,31 @@ class ConversationTest {

assertTrue("Bob should be allowed from conversation 2", isBobAllowed2)
}
}

@Test
@Ignore("TODO: Fix Flaky Test")
fun testCanHaveImplicitConsentOnMessageSend() {
runBlocking {
val bobConversation = bobClient.conversations.newConversation(alice.walletAddress, null)
Thread.sleep(1000)
val isAllowed = bobConversation.consentState() == ConsentState.ALLOWED
@Test
@Ignore("TODO: Fix Flaky Test")
fun testCanHaveImplicitConsentOnMessageSend() {
runBlocking {
val bobConversation = bobClient.conversations.newConversation(alice.walletAddress, null)
Thread.sleep(1000)
val isAllowed = bobConversation.consentState() == ConsentState.ALLOWED

// Conversations you start should start as allowed
assertTrue("Bob convo should be allowed", isAllowed)
// Conversations you start should start as allowed
assertTrue("Bob convo should be allowed", isAllowed)

val aliceConversation = aliceClient.conversations.list()[0]
val isUnknown = aliceConversation.consentState() == ConsentState.UNKNOWN
val aliceConversation = aliceClient.conversations.list()[0]
val isUnknown = aliceConversation.consentState() == ConsentState.UNKNOWN

// Conversations you receive should start as unknown
assertTrue("Alice convo should be unknown", isUnknown)
// Conversations you receive should start as unknown
assertTrue("Alice convo should be unknown", isUnknown)

aliceConversation.send(content = "hey bob")
aliceClient.contacts.refreshConsentList()
val isNowAllowed = aliceConversation.consentState() == ConsentState.ALLOWED
aliceConversation.send(content = "hey bob")
aliceClient.contacts.refreshConsentList()
val isNowAllowed = aliceConversation.consentState() == ConsentState.ALLOWED

// Conversations you send a message to get marked as allowed
assertTrue("Should now be allowed", isNowAllowed)
}
// Conversations you send a message to get marked as allowed
assertTrue("Should now be allowed", isNowAllowed)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class ConversationsTest {
val newWallet = PrivateKeyBuilder()
val newClient = runBlocking { Client().create(account = newWallet) }
val message = MessageV1Builder.buildEncode(
sender = newClient.privateKeyBundleV1,
sender = newClient.v1keys,
recipient = fixtures.aliceClient.v1keys.toPublicKeyBundle(),
message = TextCodec().encode(content = "hello").toByteArray(),
timestamp = created
Expand Down Expand Up @@ -160,6 +160,7 @@ class ConversationsTest {
}

@Test
@Ignore("TODO: Fix Flaky Test")
fun testStreamTimeOutsAllMessages() {
val boConversation =
runBlocking { boClient.conversations.newConversation(alixClient.address) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ class LocalInstrumentedTest {
private fun publishLegacyContact(client: Client) {
val contactBundle = Contact.ContactBundle.newBuilder().also {
it.v1 = it.v1.toBuilder().apply {
keyBundle = client.privateKeyBundleV1.toPublicKeyBundle()
keyBundle = client.v1keys.toPublicKeyBundle()
}.build()
}.build()
val envelope = Envelope.newBuilder().also {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,30 @@ class FakeWallet : SigningKey {
}

data class Fixtures(
val aliceAccount: PrivateKeyBuilder,
val bobAccount: PrivateKeyBuilder,
val caroAccount: PrivateKeyBuilder,
val clientOptions: ClientOptions? = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, isSecure = false)
),
) {
val aliceAccount = PrivateKeyBuilder()
val bobAccount = PrivateKeyBuilder()
val caroAccount = PrivateKeyBuilder()

var alice: PrivateKey = aliceAccount.getPrivateKey()
var aliceClient: Client = runBlocking { Client().create(account = aliceAccount, options = clientOptions) }
var aliceClient: Client =
runBlocking { Client().create(account = aliceAccount, options = clientOptions) }

var bob: PrivateKey = bobAccount.getPrivateKey()
var bobClient: Client = runBlocking { Client().create(account = bobAccount, options = clientOptions) }
var caro: PrivateKey = caroAccount.getPrivateKey()
var caroClient: Client = runBlocking { Client().create(account = caroAccount, options = clientOptions) }
var bobClient: Client =
runBlocking { Client().create(account = bobAccount, options = clientOptions) }

constructor(clientOptions: ClientOptions?) : this(
aliceAccount = PrivateKeyBuilder(),
bobAccount = PrivateKeyBuilder(),
caroAccount = PrivateKeyBuilder(),
clientOptions = 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.privateKeyBundleV1.toPublicKeyBundle()
it.keyBundle = client.v1keys.toPublicKeyBundle()
}.build()
}.build()
val envelope = Envelope.newBuilder().apply {
Expand Down
Loading

0 comments on commit 8e37581

Please sign in to comment.