Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibXMTP Client Creation #156

Merged
merged 40 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fcb9921
first pass at all the pieces needed for threading
nplasterer Jan 19, 2024
6326d7f
a few more places
nplasterer Jan 19, 2024
ed9ae8c
make signing key extend inboxOwner
nplasterer Jan 19, 2024
ff740e1
get it decoding messages
nplasterer Jan 19, 2024
750eb84
dump the latest v3 code
nplasterer Jan 23, 2024
15db4e8
write a test for creating a v3 client
nplasterer Jan 23, 2024
88a2c77
use created At
nplasterer Jan 23, 2024
53c5897
write test for creating libxmtp client and confirm it works
nplasterer Jan 23, 2024
8998d13
move these change to a different branch
nplasterer Jan 23, 2024
397982a
dont pass a conversation
nplasterer Jan 23, 2024
7bb1534
fix linter
nplasterer Jan 23, 2024
b35f686
point to local not dev
nplasterer Jan 23, 2024
aaecfc3
feature flag the client creating of libxmtp while in alpha
nplasterer Jan 23, 2024
9bbee43
change to local
nplasterer Jan 23, 2024
14b3870
fix up the test helper
nplasterer Jan 23, 2024
5ddf0f5
feat: fix up the example app
nplasterer Jan 23, 2024
305f483
fix up the 22 compat issue
nplasterer Jan 23, 2024
2cb89b7
setup local database
nplasterer Jan 24, 2024
4892ffe
have it create correctly
nplasterer Jan 24, 2024
ca663cf
add updates to the v3 bindings
nplasterer Jan 24, 2024
1e84e4c
store in a keystore
nplasterer Jan 25, 2024
4da7d38
move to preferences
nplasterer Jan 25, 2024
c05f7f8
fix lint
nplasterer Jan 25, 2024
ca7537f
dump the latest schema
nplasterer Jan 25, 2024
3fd9099
update to the latest client creation flow
nplasterer Jan 25, 2024
89d0e63
get the create working again
nplasterer Jan 26, 2024
845d360
use the keystore because its more secure
nplasterer Jan 26, 2024
8862d42
fix up linter compat again
nplasterer Jan 26, 2024
13b7cf9
flaky test
nplasterer Jan 26, 2024
ba3c247
Merge branch 'main' of https://github.com/xmtp/xmtp-android into np/g…
nplasterer Jan 26, 2024
6710b14
reproduce the keystore bug
nplasterer Jan 26, 2024
a947a45
get the keystore actually working correctly with a test
nplasterer Jan 26, 2024
185231f
make the logger more descriptive
nplasterer Jan 26, 2024
d663056
remove all the old v2 rust stuff
nplasterer Jan 26, 2024
5fb8b51
add a check on local
nplasterer Jan 26, 2024
3ed13f1
reproduce the signing key not being the same when building from bundle
nplasterer Jan 26, 2024
44666b4
get the tests passing with a account
nplasterer Jan 26, 2024
6cc56b1
limit the amount of changes
nplasterer Jan 26, 2024
c4febaf
remove some unnecessary changes
nplasterer Jan 26, 2024
c191404
fix the linter
nplasterer Jan 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.xmtp.android.example.account
import android.net.Uri
import com.walletconnect.wcmodal.client.Modal
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.web3j.crypto.Keys
import org.xmtp.android.example.connect.getPersonalSignBody
import org.xmtp.android.example.extension.requestMethod
Expand All @@ -14,21 +15,39 @@ import org.xmtp.proto.message.contents.SignatureOuterClass
data class WalletConnectV2Account(
val session: Modal.Model.ApprovedSession,
val chain: String,
private val sendSessionRequestDeepLink: (Uri) -> Unit
private val sendSessionRequestDeepLink: (Uri) -> Unit,
) :
SigningKey {
override val address: String
get() = Keys.toChecksumAddress(
session.namespaces.getValue(chain).accounts[0].substringAfterLast(
":"
)
)

override suspend fun sign(data: ByteArray): SignatureOuterClass.Signature? {
return sign(String(data))
return signLegacy(String(data))
}

override fun sign(text: String): ByteArray {
val (parentChain, chainId, account) = session.namespaces.getValue(chain).accounts[0].split(":")
val requestParams = session.namespaces.getValue(chain).methods.find { method ->
method == "personal_sign"
}?.let { method ->
Modal.Params.Request(
sessionTopic = session.topic,
method = method,
params = getPersonalSignBody(text, account),
chainId = "$parentChain:$chainId"
)
}

runCatching {
runBlocking {
requestMethod(requestParams!!, sendSessionRequestDeepLink).first().getOrThrow()
}
}.onSuccess {
return it
}.onFailure {}

return byteArrayOf()
}

override suspend fun sign(message: String): SignatureOuterClass.Signature? {
override suspend fun signLegacy(message: String): SignatureOuterClass.Signature? {
val (parentChain, chainId, account) = session.namespaces.getValue(chain).accounts[0].split(":")
val requestParams = session.namespaces.getValue(chain).methods.find { method ->
method == "personal_sign"
Expand All @@ -50,4 +69,12 @@ data class WalletConnectV2Account(

return null
}

override fun getAddress(): String {
return Keys.toChecksumAddress(
session.namespaces.getValue(chain).accounts[0].substringAfterLast(
":"
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ConnectWalletViewModel : ViewModel() {
val wallet = PrivateKeyBuilder()
val client = Client().create(wallet, ClientManager.CLIENT_OPTIONS)
_uiState.value = ConnectUiState.Success(
wallet.address,
wallet.getAddress(),
PrivateKeyBundleV1Builder.encodeData(client.privateKeyBundleV1)
)
} catch (e: XMTPException) {
Expand All @@ -110,7 +110,7 @@ class ConnectWalletViewModel : ViewModel() {
}
val client = Client().create(wallet, ClientManager.CLIENT_OPTIONS)
_uiState.value = ConnectUiState.Success(
wallet.address,
wallet.getAddress(),
PrivateKeyBundleV1Builder.encodeData(client.privateKeyBundleV1)
)
} catch (e: Exception) {
Expand Down
2 changes: 1 addition & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dokkaGfmPartial {

ktlint {
filter {
exclude { it.file.path.contains("xmtp_dh") }
exclude { it.file.path.contains("xmtp") }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.xmtp.android.library

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.fail
import org.junit.Ignore
import org.junit.Test
Expand Down Expand Up @@ -39,7 +40,7 @@ class ClientTest {
val v1Copy = PrivateKeyBundleV1Builder.fromEncodedData(encodedData)
val client = Client().buildFrom(v1Copy)
assertEquals(
wallet.address,
wallet.getAddress(),
client.address,
)
}
Expand Down Expand Up @@ -78,12 +79,29 @@ class ClientTest {
)
}

@Test
fun testCreatesAV3Client() {
val fakeWallet = PrivateKeyBuilder()
val client =
Client().create(account = fakeWallet, options = ClientOptions(enableLibXmtpV3 = true))
val v3Client = client.libXMTPClient
assertEquals(client.address.lowercase(), v3Client?.accountAddress()?.lowercase())
}

@Test
fun testDoesNotCreateAV3Client() {
val fakeWallet = PrivateKeyBuilder()
val client = Client().create(account = fakeWallet)
val v3Client = client.libXMTPClient
assertNull(v3Client)
}

@Test
fun testCanMessage() {
val fixtures = fixtures()
val notOnNetwork = PrivateKeyBuilder()
val canMessage = fixtures.aliceClient.canMessage(fixtures.bobClient.address)
val cannotMessage = fixtures.aliceClient.canMessage(notOnNetwork.address)
val cannotMessage = fixtures.aliceClient.canMessage(notOnNetwork.getAddress())
assert(canMessage)
assert(!cannotMessage)
}
Expand All @@ -97,8 +115,8 @@ class ClientTest {
val aliceClient = Client().create(aliceWallet, opts)
aliceClient.ensureUserContactPublished()

val canMessage = Client.canMessage(aliceWallet.address, opts)
val cannotMessage = Client.canMessage(notOnNetwork.address, opts)
val canMessage = Client.canMessage(aliceWallet.getAddress(), opts)
val cannotMessage = Client.canMessage(notOnNetwork.getAddress(), opts)

assert(canMessage)
assert(!cannotMessage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,39 +169,39 @@ class ConversationTest {
// Overwrite contact as legacy so we can get v1
fixtures.publishLegacyContact(client = bobClient)
fixtures.publishLegacyContact(client = aliceClient)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.address)
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.address)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.getAddress())
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.getAddress())

bobConversation.send(content = "hey alice")
bobConversation.send(content = "hey alice again")
val messages = aliceConversation.messages()
assertEquals(2, messages.size)
assertEquals("hey alice", messages[1].body)
assertEquals(bobWallet.address, messages[1].senderAddress)
assertEquals(bobWallet.getAddress(), messages[1].senderAddress)
}

@Test
fun testCanLoadV2Messages() {
val bobConversation = bobClient.conversations.newConversation(
aliceWallet.address,
aliceWallet.getAddress(),
InvitationV1ContextBuilder.buildFromConversation("hi"),
)

val aliceConversation = aliceClient.conversations.newConversation(
bobWallet.address,
bobWallet.getAddress(),
InvitationV1ContextBuilder.buildFromConversation("hi"),
)
bobConversation.send(content = "hey alice")
val messages = aliceConversation.messages()
assertEquals(1, messages.size)
assertEquals("hey alice", messages[0].body)
assertEquals(bobWallet.address, messages[0].senderAddress)
assertEquals(bobWallet.getAddress(), messages[0].senderAddress)
}

@Test
fun testVerifiesV2MessageSignature() {
val aliceConversation = aliceClient.conversations.newConversation(
bobWallet.address,
bobWallet.getAddress(),
context = InvitationV1ContextBuilder.buildFromConversation(conversationId = "hi"),
)

Expand Down Expand Up @@ -237,7 +237,7 @@ class ConversationTest {
)
aliceClient.publish(envelopes = listOf(tamperedEnvelope))
val bobConversation = bobClient.conversations.newConversation(
aliceWallet.address,
aliceWallet.getAddress(),
InvitationV1ContextBuilder.buildFromConversation("hi"),
)
assertThrows("Invalid signature", XMTPException::class.java) {
Expand All @@ -251,8 +251,8 @@ class ConversationTest {
fun testCanSendGzipCompressedV1Messages() {
fixtures.publishLegacyContact(client = bobClient)
fixtures.publishLegacyContact(client = aliceClient)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.address)
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.address)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.getAddress())
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.getAddress())
bobConversation.send(
text = MutableList(1000) { "A" }.toString(),
sendOptions = SendOptions(compression = EncodedContentCompression.GZIP),
Expand All @@ -266,8 +266,8 @@ class ConversationTest {
fun testCanSendDeflateCompressedV1Messages() {
fixtures.publishLegacyContact(client = bobClient)
fixtures.publishLegacyContact(client = aliceClient)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.address)
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.address)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.getAddress())
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.getAddress())
bobConversation.send(
content = MutableList(1000) { "A" }.toString(),
options = SendOptions(compression = EncodedContentCompression.DEFLATE),
Expand All @@ -280,11 +280,11 @@ class ConversationTest {
@Test
fun testCanSendGzipCompressedV2Messages() {
val bobConversation = bobClient.conversations.newConversation(
aliceWallet.address,
aliceWallet.getAddress(),
InvitationV1ContextBuilder.buildFromConversation(conversationId = "hi"),
)
val aliceConversation = aliceClient.conversations.newConversation(
bobWallet.address,
bobWallet.getAddress(),
InvitationV1ContextBuilder.buildFromConversation(conversationId = "hi"),
)
bobConversation.send(
Expand All @@ -294,17 +294,17 @@ class ConversationTest {
val messages = aliceConversation.messages()
assertEquals(1, messages.size)
assertEquals(MutableList(1000) { "A" }.toString(), messages[0].body)
assertEquals(bobWallet.address, messages[0].senderAddress)
assertEquals(bobWallet.getAddress(), messages[0].senderAddress)
}

@Test
fun testCanSendDeflateCompressedV2Messages() {
val bobConversation = bobClient.conversations.newConversation(
aliceWallet.address,
aliceWallet.getAddress(),
InvitationV1ContextBuilder.buildFromConversation(conversationId = "hi"),
)
val aliceConversation = aliceClient.conversations.newConversation(
bobWallet.address,
bobWallet.getAddress(),
InvitationV1ContextBuilder.buildFromConversation(conversationId = "hi"),
)
bobConversation.send(
Expand All @@ -314,7 +314,7 @@ class ConversationTest {
val messages = aliceConversation.messages()
assertEquals(1, messages.size)
assertEquals(MutableList(1000) { "A" }.toString(), messages[0].body)
assertEquals(bobWallet.address, messages[0].senderAddress)
assertEquals(bobWallet.getAddress(), messages[0].senderAddress)
}

@Test
Expand All @@ -324,8 +324,8 @@ class ConversationTest {
fakeContactClient.publishUserContact()
val fakeWallet = PrivateKeyBuilder()
val client = Client().create(account = fakeWallet)
val contact = client.getUserContact(peerAddress = fakeContactWallet.address)!!
assertEquals(contact.walletAddress, fakeContactWallet.address)
val contact = client.getUserContact(peerAddress = fakeContactWallet.getAddress())!!
assertEquals(contact.walletAddress, fakeContactWallet.getAddress())
val created = Date()
val invitationContext = Invitation.InvitationV1.Context.newBuilder().also {
it.conversationId = "https://example.com/1"
Expand All @@ -338,7 +338,7 @@ class ConversationTest {
val senderBundle = client.privateKeyBundleV1?.toV2()
assertEquals(
senderBundle?.identityKey?.publicKey?.recoverWalletSignerPublicKey()?.walletAddress,
fakeWallet.address,
fakeWallet.getAddress(),
)
val invitation = SealedInvitationBuilder.buildFromV1(
sender = client.privateKeyBundleV1!!.toV2(),
Expand All @@ -347,12 +347,12 @@ class ConversationTest {
invitation = invitationv1,
)
val inviteHeader = invitation.v1.header
assertEquals(inviteHeader.sender.walletAddress, fakeWallet.address)
assertEquals(inviteHeader.recipient.walletAddress, fakeContactWallet.address)
assertEquals(inviteHeader.sender.walletAddress, fakeWallet.getAddress())
assertEquals(inviteHeader.recipient.walletAddress, fakeContactWallet.getAddress())
val header = SealedInvitationHeaderV1.parseFrom(invitation.v1.headerBytes)
val conversation =
ConversationV2.create(client = client, invitation = invitationv1, header = header)
assertEquals(fakeContactWallet.address, conversation.peerAddress)
assertEquals(fakeContactWallet.getAddress(), conversation.peerAddress)

conversation.send(content = "hello world")

Expand Down Expand Up @@ -734,8 +734,8 @@ class ConversationTest {
fun testCanSendEncodedContentV1Message() {
fixtures.publishLegacyContact(client = bobClient)
fixtures.publishLegacyContact(client = aliceClient)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.address)
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.address)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.getAddress())
val aliceConversation = aliceClient.conversations.newConversation(bobWallet.getAddress())
val encodedContent = TextCodec().encode(content = "hi")
bobConversation.send(encodedContent = encodedContent)
val messages = aliceConversation.messages()
Expand All @@ -745,7 +745,7 @@ class ConversationTest {

@Test
fun testCanSendEncodedContentV2Message() {
val bobConversation = bobClient.conversations.newConversation(aliceWallet.address)
val bobConversation = bobClient.conversations.newConversation(aliceWallet.getAddress())
val encodedContent = TextCodec().encode(content = "hi")
bobConversation.send(encodedContent = encodedContent)
val messages = bobConversation.messages()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class ConversationsTest {
message = MessageBuilder.buildFromMessageV1(v1 = message).toByteArray()
)
val conversation = client.conversations.fromIntro(envelope = envelope)
assertEquals(conversation.peerAddress, newWallet.address)
assertEquals(conversation.peerAddress, newWallet.getAddress())
assertEquals(conversation.createdAt.time, created.time)
}

Expand Down Expand Up @@ -73,7 +73,7 @@ class ConversationsTest {
message = sealed.toByteArray()
)
val conversation = client.conversations.fromInvite(envelope = envelope)
assertEquals(conversation.peerAddress, newWallet.address)
assertEquals(conversation.peerAddress, newWallet.getAddress())
assertEquals(conversation.createdAt.time, created.time)
}

Expand Down
Loading