From 25664a0170b65257e5fd98cbade7a14d1da0172e Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Fri, 26 Jan 2024 10:38:02 -0600 Subject: [PATCH 01/31] Adding the way for adding should push and hmac --- .../org/xmtp/android/library/CodecTest.kt | 19 ++++---- .../java/org/xmtp/android/library/Crypto.kt | 47 +++++++++++-------- .../android/library/codecs/AttachmentCodec.kt | 2 + .../xmtp/android/library/codecs/Composite.kt | 2 + .../android/library/codecs/ContentCodec.kt | 1 + .../android/library/codecs/ReactionCodec.kt | 2 + .../library/codecs/ReadReceiptCodec.kt | 2 + .../library/codecs/RemoteAttachmentCodec.kt | 2 + .../xmtp/android/library/codecs/ReplyCodec.kt | 2 + .../xmtp/android/library/codecs/TextCodec.kt | 2 + .../android/library/messages/InvitationV1.kt | 12 ++--- 11 files changed, 60 insertions(+), 33 deletions(-) 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 4b04fe815..5859a46ab 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -19,8 +19,8 @@ data class NumberCodec( authorityId = "example.com", typeId = "number", versionMajor = 1, - versionMinor = 1 - ) + versionMinor = 1, + ), ) : ContentCodec { override fun encode(content: Double): EncodedContent { return EncodedContent.newBuilder().also { @@ -28,7 +28,7 @@ data class NumberCodec( authorityId = "example.com", typeId = "number", versionMajor = 1, - versionMinor = 1 + versionMinor = 1, ) it.content = mapOf(Pair("number", content)).toString().toByteStringUtf8() }.build() @@ -37,10 +37,13 @@ data class NumberCodec( override fun decode(content: EncodedContent): Double = content.content.toStringUtf8().filter { it.isDigit() || it == '.' }.toDouble() + override fun shouldPush(): Boolean = false + override fun fallback(content: Double): String? { return "Error: This app does not support numbers." } } + @RunWith(AndroidJUnit4::class) class CodecTest { @@ -53,7 +56,7 @@ class CodecTest { aliceClient.conversations.newConversation(fixtures.bob.walletAddress) aliceConversation.send( content = 3.14, - options = SendOptions(contentType = NumberCodec().contentType) + options = SendOptions(contentType = NumberCodec().contentType), ) val messages = aliceConversation.messages() assertEquals(messages.size, 1) @@ -75,7 +78,7 @@ class CodecTest { val source = DecodedComposite(encodedContent = textContent) aliceConversation.send( content = source, - options = SendOptions(contentType = CompositeCodec().contentType) + options = SendOptions(contentType = CompositeCodec().contentType), ) val messages = aliceConversation.messages() val decoded: DecodedComposite? = messages[0].content() @@ -95,12 +98,12 @@ class CodecTest { val source = DecodedComposite( parts = listOf( DecodedComposite(encodedContent = textContent), - DecodedComposite(parts = listOf(DecodedComposite(encodedContent = numberContent))) - ) + DecodedComposite(parts = listOf(DecodedComposite(encodedContent = numberContent))), + ), ) aliceConversation.send( content = source, - options = SendOptions(contentType = CompositeCodec().contentType) + options = SendOptions(contentType = CompositeCodec().contentType), ) val messages = aliceConversation.messages() val decoded: DecodedComposite? = messages[0].content() diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index b91af0fa9..681f2d33e 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -77,26 +77,35 @@ class Crypto { null } } - } - fun calculateMac(secret: ByteArray, message: ByteArray): ByteArray { - val sha256HMAC: Mac = Mac.getInstance("HmacSHA256") - val secretKey = SecretKeySpec(secret, "HmacSHA256") - sha256HMAC.init(secretKey) - return sha256HMAC.doFinal(message) - } + fun calculateMac(secret: ByteArray, message: ByteArray): ByteArray { + val sha256HMAC: Mac = Mac.getInstance("HmacSHA256") + val secretKey = SecretKeySpec(secret, "HmacSHA256") + sha256HMAC.init(secretKey) + return sha256HMAC.doFinal(message) + } - fun deriveKey( - secret: ByteArray, - salt: ByteArray, - info: ByteArray, - ): ByteArray { - val derivationParameters = HKDFParameters(secret, salt, info) - val digest = SHA256Digest() - val hkdfGenerator = HKDFBytesGenerator(digest) - hkdfGenerator.init(derivationParameters) - val hkdf = ByteArray(32) - hkdfGenerator.generateBytes(hkdf, 0, hkdf.size) - return hkdf + fun deriveKey( + secret: ByteArray, + salt: ByteArray, + info: ByteArray, + ): ByteArray { + val derivationParameters = HKDFParameters(secret, salt, info) + val digest = SHA256Digest() + val hkdfGenerator = HKDFBytesGenerator(digest) + hkdfGenerator.init(derivationParameters) + val hkdf = ByteArray(32) + hkdfGenerator.generateBytes(hkdf, 0, hkdf.size) + return hkdf + } + + fun generateHmacSignature( + secret: ByteArray, + info: ByteArray, + message: ByteArray, + ): ByteArray { + val hkdfKey = deriveKey(secret, message, info) + return calculateMac(secret, hkdfKey) + } } } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt index 21c9e872c..f2273f14b 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt @@ -36,4 +36,6 @@ data class AttachmentCodec(override var contentType: ContentTypeId = ContentType override fun fallback(content: Attachment): String? { return "Can’t display \"${content.filename}”. This app doesn’t support attachments." } + + override fun shouldPush(): Boolean = true } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt b/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt index 4fa7c8c9f..ebe84d5e0 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt @@ -52,6 +52,8 @@ class CompositeCodec : ContentCodec { return null } + override fun shouldPush(): Boolean = false + private fun toComposite(decodedComposite: DecodedComposite): Composite { return Composite.newBuilder().also { val content = decodedComposite.encodedContent diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt index 1282e3655..732d96b44 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt @@ -67,6 +67,7 @@ interface ContentCodec { fun encode(content: T): EncodedContent fun decode(content: EncodedContent): T fun fallback(content: T): String? + fun shouldPush(): Boolean } val id: String diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt index f15f366d4..fbb917b7f 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt @@ -95,6 +95,8 @@ data class ReactionCodec(override var contentType: ContentTypeId = ContentTypeRe else -> null } } + + override fun shouldPush(): Boolean = true } private class ReactionSerializer : JsonSerializer { diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt index 6e51e77ae..c07b66d40 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt @@ -28,4 +28,6 @@ data class ReadReceiptCodec(override var contentType: ContentTypeId = ContentTyp override fun fallback(content: ReadReceipt): String? { return null } + + override fun shouldPush(): Boolean = false } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt index 2fdebe0a2..29ebfce1b 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt @@ -171,4 +171,6 @@ data class RemoteAttachmentCodec(override var contentType: ContentTypeId = Conte override fun fallback(content: RemoteAttachment): String? { return "Can’t display \"${content.filename}”. This app doesn’t support attachments." } + + override fun shouldPush(): Boolean = true } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt index f61c20400..61fe61c0a 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt @@ -49,6 +49,8 @@ data class ReplyCodec(override var contentType: ContentTypeId = ContentTypeReply return "Replied with “${content.content}” to an earlier message" } + override fun shouldPush(): Boolean = true + private fun , T> encodeReply( codec: Codec, content: Any, diff --git a/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt index 378d6f060..86b15c02d 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt @@ -36,4 +36,6 @@ data class TextCodec(override var contentType: ContentTypeId = ContentTypeText) override fun fallback(content: String): String? { return null } + + override fun shouldPush(): Boolean = true } diff --git a/library/src/main/java/org/xmtp/android/library/messages/InvitationV1.kt b/library/src/main/java/org/xmtp/android/library/messages/InvitationV1.kt index 347847ed7..f0cd5e57c 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/InvitationV1.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/InvitationV1.kt @@ -52,7 +52,7 @@ fun InvitationV1.createRandom(context: Context? = null): InvitationV1 { return InvitationV1Builder.buildFromTopic( topic = topic, context = inviteContext, - aes256GcmHkdfSha256 = aes256GcmHkdfSha256 + aes256GcmHkdfSha256 = aes256GcmHkdfSha256, ) } @@ -68,7 +68,7 @@ fun InvitationV1.createDeterministic( val secret = sender.sharedSecret( peer = recipient, myPreKey = sender.preKeysList[0].publicKey, - isRecipient = myAddress < theirAddress + isRecipient = myAddress < theirAddress, ) val addresses = arrayOf(myAddress, theirAddress) @@ -80,12 +80,12 @@ fun InvitationV1.createDeterministic( addresses.joinToString(separator = ",") } - val topicId = Crypto().calculateMac(secret = secret, message = msg.toByteArray()).toHex() + val topicId = Crypto.calculateMac(secret = secret, message = msg.toByteArray()).toHex() val topic = Topic.directMessageV2(topicId) - val keyMaterial = Crypto().deriveKey( + val keyMaterial = Crypto.deriveKey( secret = secret, salt = "__XMTP__INVITATION__SALT__XMTP__".toByteArray(), - info = listOf("0").plus(addresses).joinToString(separator = "|").toByteArray() + info = listOf("0").plus(addresses).joinToString(separator = "|").toByteArray(), ) val aes256GcmHkdfSha256 = Invitation.InvitationV1.Aes256gcmHkdfsha256.newBuilder().apply { this.keyMaterial = keyMaterial.toByteString() @@ -94,7 +94,7 @@ fun InvitationV1.createDeterministic( return InvitationV1Builder.buildFromTopic( topic = topic, context = inviteContext, - aes256GcmHkdfSha256 = aes256GcmHkdfSha256 + aes256GcmHkdfSha256 = aes256GcmHkdfSha256, ) } From bda8a7a1593b7f2834036902ff56dbae1df7a312 Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Wed, 31 Jan 2024 02:11:10 -0600 Subject: [PATCH 02/31] Adding new approach for codecs and crypto --- .../org/xmtp/android/library/CodecTest.kt | 2 +- .../xmtp/android/library/ConversationTest.kt | 8 +++- .../org/xmtp/android/library/MessageTest.kt | 3 +- .../org/xmtp/android/library/Conversation.kt | 6 ++- .../xmtp/android/library/ConversationV2.kt | 40 ++++++++++++++----- .../android/library/codecs/AttachmentCodec.kt | 2 +- .../xmtp/android/library/codecs/Composite.kt | 2 +- .../android/library/codecs/ContentCodec.kt | 2 +- .../android/library/codecs/ReactionCodec.kt | 8 +++- .../library/codecs/ReadReceiptCodec.kt | 4 +- .../library/codecs/RemoteAttachmentCodec.kt | 21 ++++++---- .../xmtp/android/library/codecs/ReplyCodec.kt | 6 +-- .../xmtp/android/library/codecs/TextCodec.kt | 2 +- .../android/library/messages/MessageV2.kt | 24 ++++++++--- .../android/library/RemoteAttachmentTest.kt | 6 +-- 15 files changed, 95 insertions(+), 41 deletions(-) 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 5859a46ab..fd629daeb 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -37,7 +37,7 @@ data class NumberCodec( override fun decode(content: EncodedContent): Double = content.content.toStringUtf8().filter { it.isDigit() || it == '.' }.toDouble() - override fun shouldPush(): Boolean = false + override fun shouldPush(content: Double): Boolean = false override fun fallback(content: Double): String? { return "Error: This app does not support numbers." diff --git a/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt index 7dde5004c..60b387bd2 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt @@ -229,7 +229,12 @@ class ConversationTest { additionalData = headerBytes, ) val tamperedMessage = - MessageV2Builder.buildFromCipherText(headerBytes = headerBytes, ciphertext = ciphertext) + MessageV2Builder.buildFromCipherText( + headerBytes = headerBytes, + ciphertext = ciphertext, + senderHmac = null, + shouldPush = true, + ) val tamperedEnvelope = EnvelopeBuilder.buildFromString( topic = aliceConversation.topic, timestamp = Date(), @@ -585,6 +590,7 @@ class ConversationTest { encodedContent, topic = conversation.topic, keyMaterial = conversation.keyMaterial!!, + shouldPush = true, ), ).toByteArray(), ), diff --git a/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt b/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt index 171377d17..15a7b458b 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt @@ -91,7 +91,8 @@ class MessageTest { client = client, encodedContent, topic = invitationv1.topic, - keyMaterial = invitationv1.aes256GcmHkdfSha256.keyMaterial.toByteArray() + keyMaterial = invitationv1.aes256GcmHkdfSha256.keyMaterial.toByteArray(), + shouldPush = true, ) val decoded = MessageV2Builder.buildDecode( id = "", diff --git a/library/src/main/java/org/xmtp/android/library/Conversation.kt b/library/src/main/java/org/xmtp/android/library/Conversation.kt index 51219b3ac..1a24be3eb 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversation.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversation.kt @@ -162,7 +162,11 @@ sealed class Conversation { } is V2 -> { - conversationV2.prepareMessage(encodedContent = encodedContent, options = options) + conversationV2.prepareMessage( + encodedContent = encodedContent, + options = options, + false, + ) } is Group -> throw XMTPException("Groups do not support prepared messages") // We return a encoded content not a preparedmessage which requires a envelope diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index 6d20253c6..2967833b1 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -84,7 +84,7 @@ data class ConversationV2( val result = runBlocking { client.apiClient.envelopes( topic = topic, - pagination = pagination + pagination = pagination, ) } @@ -133,7 +133,7 @@ data class ConversationV2( topic, message.v2, keyMaterial, - client + client, ) } @@ -155,7 +155,7 @@ data class ConversationV2( topic = topic, message.v2, keyMaterial = keyMaterial, - client = client + client = client, ) } @@ -184,7 +184,12 @@ data class ConversationV2( } fun send(encodedContent: EncodedContent, options: SendOptions?): String { - val preparedMessage = prepareMessage(encodedContent = encodedContent, options = options) + val codec = Client.codecRegistry.find(options?.contentType) + val preparedMessage = prepareMessage( + encodedContent = encodedContent, + options = options, + shouldPush = shouldPush(codec, encodedContent.content), + ) return send(preparedMessage) } @@ -202,16 +207,26 @@ data class ConversationV2( client = client, encodedContent = encodedContent, topic = topic, - keyMaterial = keyMaterial + keyMaterial = keyMaterial, + shouldPush = shouldPush(codec, content), ) val envelope = EnvelopeBuilder.buildFromString( topic = topic, timestamp = Date(), - message = MessageBuilder.buildFromMessageV2(v2 = message).toByteArray() + message = MessageBuilder.buildFromMessageV2(v2 = message).toByteArray(), ) return envelope.toByteArray() } + fun , T> shouldPush(codec: Codec, content: Any?): Boolean { + val contentType = content as? T + if (contentType != null) { + return codec.shouldPush(content = content) + } else { + throw XMTPException("Codec invalid content") + } + } + fun prepareMessage(content: T, options: SendOptions?): PreparedMessage { val codec = Client.codecRegistry.find(options?.contentType) @@ -235,15 +250,20 @@ data class ConversationV2( if (compression != null) { encoded = encoded.compress(compression) } - return prepareMessage(encoded, options = options) + return prepareMessage(encoded, options = options, shouldPush = shouldPush(codec, content)) } - fun prepareMessage(encodedContent: EncodedContent, options: SendOptions?): PreparedMessage { + fun prepareMessage( + encodedContent: EncodedContent, + options: SendOptions?, + shouldPush: Boolean, + ): PreparedMessage { val message = MessageV2Builder.buildEncode( client = client, encodedContent = encodedContent, topic = topic, - keyMaterial = keyMaterial + keyMaterial = keyMaterial, + shouldPush = shouldPush, ) val newTopic = if (options?.ephemeral == true) ephemeralTopic else topic @@ -251,7 +271,7 @@ data class ConversationV2( val envelope = EnvelopeBuilder.buildFromString( topic = newTopic, timestamp = Date(), - message = MessageBuilder.buildFromMessageV2(v2 = message).toByteArray() + message = MessageBuilder.buildFromMessageV2(v2 = message).toByteArray(), ) return PreparedMessage(listOf(envelope)) } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt index f2273f14b..80d39d2b8 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/AttachmentCodec.kt @@ -37,5 +37,5 @@ data class AttachmentCodec(override var contentType: ContentTypeId = ContentType return "Can’t display \"${content.filename}”. This app doesn’t support attachments." } - override fun shouldPush(): Boolean = true + override fun shouldPush(content: Attachment): Boolean = true } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt b/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt index ebe84d5e0..da233e5bc 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/Composite.kt @@ -52,7 +52,7 @@ class CompositeCodec : ContentCodec { return null } - override fun shouldPush(): Boolean = false + override fun shouldPush(content: DecodedComposite): Boolean = false private fun toComposite(decodedComposite: DecodedComposite): Composite { return Composite.newBuilder().also { diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt index 732d96b44..22e4190d7 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ContentCodec.kt @@ -67,7 +67,7 @@ interface ContentCodec { fun encode(content: T): EncodedContent fun decode(content: EncodedContent): T fun fallback(content: T): String? - fun shouldPush(): Boolean + fun shouldPush(content: T): Boolean } val id: String diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt index fbb917b7f..cb786e765 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt @@ -14,7 +14,7 @@ val ContentTypeReaction = ContentTypeIdBuilder.builderFromAuthorityId( "xmtp.org", "reaction", versionMajor = 1, - versionMinor = 0 + versionMinor = 0, ) data class Reaction( @@ -96,7 +96,11 @@ data class ReactionCodec(override var contentType: ContentTypeId = ContentTypeRe } } - override fun shouldPush(): Boolean = true + override fun shouldPush(content: Reaction): Boolean = when (content.action) { + ReactionAction.Added -> true + ReactionAction.Removed -> false + ReactionAction.Unknown -> false + } } private class ReactionSerializer : JsonSerializer { diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt index c07b66d40..ec5c76cd2 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ReadReceiptCodec.kt @@ -6,7 +6,7 @@ val ContentTypeReadReceipt = ContentTypeIdBuilder.builderFromAuthorityId( "xmtp.org", "readReceipt", versionMajor = 1, - versionMinor = 0 + versionMinor = 0, ) object ReadReceipt @@ -29,5 +29,5 @@ data class ReadReceiptCodec(override var contentType: ContentTypeId = ContentTyp return null } - override fun shouldPush(): Boolean = false + override fun shouldPush(content: ReadReceipt): Boolean = false } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt index 29ebfce1b..5e781d1b2 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/RemoteAttachmentCodec.kt @@ -80,8 +80,10 @@ data class RemoteAttachment( fun encodeEncrypted(content: T, codec: ContentCodec): EncryptedEncodedContent { val secret = SecureRandom().generateSeed(32) val encodedContent = codec.encode(content).toByteArray() - val ciphertext = Crypto.encrypt(secret, encodedContent) ?: throw XMTPException("ciphertext not created") - val contentDigest = Hash.sha256(ciphertext.aes256GcmHkdfSha256.payload.toByteArray()).toHex() + val ciphertext = Crypto.encrypt(secret, encodedContent) + ?: throw XMTPException("ciphertext not created") + val contentDigest = + Hash.sha256(ciphertext.aes256GcmHkdfSha256.payload.toByteArray()).toHex() return EncryptedEncodedContent( contentDigest = contentDigest, secret = secret.toByteString(), @@ -114,7 +116,7 @@ val ContentTypeRemoteAttachment = ContentTypeIdBuilder.builderFromAuthorityId( "xmtp.org", "remoteStaticAttachment", versionMajor = 1, - versionMinor = 0 + versionMinor = 0, ) interface Fetcher { @@ -127,7 +129,8 @@ class HTTPFetcher : Fetcher { } } -data class RemoteAttachmentCodec(override var contentType: ContentTypeId = ContentTypeRemoteAttachment) : ContentCodec { +data class RemoteAttachmentCodec(override var contentType: ContentTypeId = ContentTypeRemoteAttachment) : + ContentCodec { override fun encode(content: RemoteAttachment): EncodedContent { return EncodedContent.newBuilder().also { it.type = ContentTypeRemoteAttachment @@ -140,19 +143,21 @@ data class RemoteAttachmentCodec(override var contentType: ContentTypeId = Conte "scheme" to content.scheme, "contentLength" to content.contentLength.toString(), "filename" to content.filename, - ) + ), ) it.content = content.url.toString().toByteStringUtf8() }.build() } override fun decode(content: EncodedContent): RemoteAttachment { - val contentDigest = content.parametersMap["contentDigest"] ?: throw XMTPException("missing content digest") + val contentDigest = + content.parametersMap["contentDigest"] ?: throw XMTPException("missing content digest") val secret = content.parametersMap["secret"] ?: throw XMTPException("missing secret") val salt = content.parametersMap["salt"] ?: throw XMTPException("missing salt") val nonce = content.parametersMap["nonce"] ?: throw XMTPException("missing nonce") val scheme = content.parametersMap["scheme"] ?: throw XMTPException("missing scheme") - val contentLength = content.parametersMap["contentLength"] ?: throw XMTPException("missing contentLength") + val contentLength = + content.parametersMap["contentLength"] ?: throw XMTPException("missing contentLength") val filename = content.parametersMap["filename"] ?: throw XMTPException("missing filename") val encodedContent = content.content ?: throw XMTPException("missing content") @@ -172,5 +177,5 @@ data class RemoteAttachmentCodec(override var contentType: ContentTypeId = Conte return "Can’t display \"${content.filename}”. This app doesn’t support attachments." } - override fun shouldPush(): Boolean = true + override fun shouldPush(content: RemoteAttachment): Boolean = true } diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt index 61fe61c0a..e60780123 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ReplyCodec.kt @@ -7,7 +7,7 @@ val ContentTypeReply = ContentTypeIdBuilder.builderFromAuthorityId( "xmtp.org", "reply", versionMajor = 1, - versionMinor = 0 + versionMinor = 0, ) data class Reply( @@ -41,7 +41,7 @@ data class ReplyCodec(override var contentType: ContentTypeId = ContentTypeReply return Reply( reference = reference, content = replyContent, - contentType = replyCodec.contentType + contentType = replyCodec.contentType, ) } @@ -49,7 +49,7 @@ data class ReplyCodec(override var contentType: ContentTypeId = ContentTypeReply return "Replied with “${content.content}” to an earlier message" } - override fun shouldPush(): Boolean = true + override fun shouldPush(content: Reply): Boolean = true private fun , T> encodeReply( codec: Codec, diff --git a/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt index 86b15c02d..66a7ea9cc 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/TextCodec.kt @@ -37,5 +37,5 @@ data class TextCodec(override var contentType: ContentTypeId = ContentTypeText) return null } - override fun shouldPush(): Boolean = true + override fun shouldPush(content: String): Boolean = true } diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 37b819ed7..b785c05de 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -1,6 +1,7 @@ package org.xmtp.android.library.messages import com.google.protobuf.kotlin.toByteString +import com.google.protobuf.kotlin.toByteStringUtf8 import org.web3j.crypto.ECDSASignature import org.web3j.crypto.Hash import org.web3j.crypto.Sign @@ -18,7 +19,12 @@ typealias MessageV2 = org.xmtp.proto.message.contents.MessageOuterClass.MessageV class MessageV2Builder { companion object { - fun buildFromCipherText(headerBytes: ByteArray, ciphertext: CipherText?): MessageV2 { + fun buildFromCipherText( + headerBytes: ByteArray, + ciphertext: CipherText?, + senderHmac: ByteArray?, + shouldPush: Boolean, + ): MessageV2 { return MessageV2.newBuilder().also { it.headerBytes = headerBytes.toByteString() it.ciphertext = ciphertext @@ -41,7 +47,7 @@ class MessageV2Builder { topic = decryptedMessage.topic, encodedContent = decryptedMessage.encodedContent, senderAddress = decryptedMessage.senderAddress, - sent = decryptedMessage.sentAt + sent = decryptedMessage.sentAt, ) } catch (e: Exception) { throw XMTPException("Error decoding message", e) @@ -69,7 +75,7 @@ class MessageV2Builder { if (!senderPreKey.signature.verify( senderIdentityKey, - signed.sender.preKey.keyBytes.toByteArray() + signed.sender.preKey.keyBytes.toByteArray(), ) ) { throw XMTPException("pre-key not signed by identity key") @@ -109,7 +115,7 @@ class MessageV2Builder { encodedContent = encodedMessage, senderAddress = signed.sender.walletAddress, sentAt = Date(header.createdNs / 1_000_000), - topic = topic + topic = topic, ) } @@ -118,6 +124,7 @@ class MessageV2Builder { encodedContent: EncodedContent, topic: String, keyMaterial: ByteArray, + shouldPush: Boolean, ): MessageV2 { val payload = encodedContent.toByteArray() val date = Date() @@ -130,7 +137,14 @@ class MessageV2Builder { val signedContent = SignedContentBuilder.builderFromPayload(payload, bundle, signature) val signedBytes = signedContent.toByteArray() val ciphertext = Crypto.encrypt(keyMaterial, signedBytes, additionalData = headerBytes) - return buildFromCipherText(headerBytes, ciphertext) + + val thirtyDayPeriodsSinceEpoch = + (System.currentTimeMillis() / 60 / 60 / 24 / 30).toInt() + val info = "$thirtyDayPeriodsSinceEpoch-${client.address}" + val infoEncoded = info.toByteStringUtf8().toByteArray() + val senderHmac = Crypto.generateHmacSignature(keyMaterial, infoEncoded, headerBytes) + + return buildFromCipherText(headerBytes, ciphertext, senderHmac, shouldPush) } } } diff --git a/library/src/test/java/org/xmtp/android/library/RemoteAttachmentTest.kt b/library/src/test/java/org/xmtp/android/library/RemoteAttachmentTest.kt index b459834b2..44093f67c 100644 --- a/library/src/test/java/org/xmtp/android/library/RemoteAttachmentTest.kt +++ b/library/src/test/java/org/xmtp/android/library/RemoteAttachmentTest.kt @@ -60,7 +60,7 @@ class RemoteAttachmentTest { val remoteAttachment = RemoteAttachment.from( url = URL("https://abcdefg"), - encryptedEncodedContent = encodedEncryptedContent + encryptedEncodedContent = encodedEncryptedContent, ) remoteAttachment.contentLength = attachment.data.size() @@ -113,7 +113,7 @@ class RemoteAttachmentTest { Assert.assertThrows(XMTPException::class.java) { RemoteAttachment.from( url = URL("http://abcdefg"), - encryptedEncodedContent = encodedEncryptedContent + encryptedEncodedContent = encodedEncryptedContent, ) } } @@ -139,7 +139,7 @@ class RemoteAttachmentTest { val remoteAttachment = RemoteAttachment.from( url = URL("https://abcdefg"), - encryptedEncodedContent = encodedEncryptedContent + encryptedEncodedContent = encodedEncryptedContent, ) remoteAttachment.contentLength = attachment.data.size() From 8286a3faa9f2a58e440636d8ea0f2de3a133dd86 Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Wed, 31 Jan 2024 16:10:14 -0600 Subject: [PATCH 03/31] Solving test for conversation using new flag --- .../src/main/java/org/xmtp/android/library/ConversationV2.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index 2967833b1..1064cf37b 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -1,6 +1,7 @@ package org.xmtp.android.library import android.util.Log +import com.google.protobuf.ByteString import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.mapNotNull @@ -188,7 +189,7 @@ data class ConversationV2( val preparedMessage = prepareMessage( encodedContent = encodedContent, options = options, - shouldPush = shouldPush(codec, encodedContent.content), + shouldPush = shouldPush(codec, encodedContent.content.toStringUtf8()), ) return send(preparedMessage) } From 40018576bbaa796b30a38f17353a4e15ef03b3f7 Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Wed, 31 Jan 2024 16:10:43 -0600 Subject: [PATCH 04/31] Update ConversationV2.kt --- library/src/main/java/org/xmtp/android/library/ConversationV2.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index 1064cf37b..885153d3d 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -1,7 +1,6 @@ package org.xmtp.android.library import android.util.Log -import com.google.protobuf.ByteString import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.mapNotNull From fd117ab33a7300992ad30cb1a16eb763b7d868ac Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 31 Jan 2024 20:10:12 -0800 Subject: [PATCH 05/31] do kotlin way of extending proto class --- .../xmtp/android/library/ConversationTest.kt | 4 ++-- .../org/xmtp/android/library/MessageTest.kt | 2 +- .../org/xmtp/android/library/ConversationV2.kt | 4 ++-- .../xmtp/android/library/messages/MessageV2.kt | 17 +++++++++++------ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt index 60b387bd2..26625e179 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt @@ -238,7 +238,7 @@ class ConversationTest { val tamperedEnvelope = EnvelopeBuilder.buildFromString( topic = aliceConversation.topic, timestamp = Date(), - message = MessageBuilder.buildFromMessageV2(v2 = tamperedMessage).toByteArray(), + message = MessageBuilder.buildFromMessageV2(v2 = tamperedMessage.messageV2).toByteArray(), ) aliceClient.publish(envelopes = listOf(tamperedEnvelope)) val bobConversation = bobClient.conversations.newConversation( @@ -591,7 +591,7 @@ class ConversationTest { topic = conversation.topic, keyMaterial = conversation.keyMaterial!!, shouldPush = true, - ), + ).messageV2, ).toByteArray(), ), ) diff --git a/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt b/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt index 15a7b458b..10a1e92fd 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt @@ -97,7 +97,7 @@ class MessageTest { val decoded = MessageV2Builder.buildDecode( id = "", client = client, - message = message1, + message = message1.messageV2, keyMaterial = invitationv1.aes256GcmHkdfSha256.keyMaterial.toByteArray(), topic = invitationv1.topic ) diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index 885153d3d..c19e17a7f 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -213,7 +213,7 @@ data class ConversationV2( val envelope = EnvelopeBuilder.buildFromString( topic = topic, timestamp = Date(), - message = MessageBuilder.buildFromMessageV2(v2 = message).toByteArray(), + message = MessageBuilder.buildFromMessageV2(v2 = message.messageV2).toByteArray(), ) return envelope.toByteArray() } @@ -271,7 +271,7 @@ data class ConversationV2( val envelope = EnvelopeBuilder.buildFromString( topic = newTopic, timestamp = Date(), - message = MessageBuilder.buildFromMessageV2(v2 = message).toByteArray(), + message = MessageBuilder.buildFromMessageV2(v2 = message.messageV2).toByteArray(), ) return PreparedMessage(listOf(envelope)) } diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index b785c05de..7149c7677 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -17,18 +17,22 @@ import java.util.Date typealias MessageV2 = org.xmtp.proto.message.contents.MessageOuterClass.MessageV2 -class MessageV2Builder { +class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolean = false) { + lateinit var messageV2: MessageV2 + companion object { fun buildFromCipherText( headerBytes: ByteArray, ciphertext: CipherText?, senderHmac: ByteArray?, shouldPush: Boolean, - ): MessageV2 { - return MessageV2.newBuilder().also { + ): MessageV2Builder { + val messageBuilder = MessageV2Builder(senderHmac = senderHmac, shouldPush = shouldPush) + messageBuilder.messageV2 = MessageV2.newBuilder().also { it.headerBytes = headerBytes.toByteString() it.ciphertext = ciphertext }.build() + return messageBuilder } fun buildDecode( @@ -125,7 +129,7 @@ class MessageV2Builder { topic: String, keyMaterial: ByteArray, shouldPush: Boolean, - ): MessageV2 { + ): MessageV2Builder { val payload = encodedContent.toByteArray() val date = Date() val header = MessageHeaderV2Builder.buildFromTopic(topic, date) @@ -142,9 +146,10 @@ class MessageV2Builder { (System.currentTimeMillis() / 60 / 60 / 24 / 30).toInt() val info = "$thirtyDayPeriodsSinceEpoch-${client.address}" val infoEncoded = info.toByteStringUtf8().toByteArray() - val senderHmac = Crypto.generateHmacSignature(keyMaterial, infoEncoded, headerBytes) + val senderHmacGenerated = + Crypto.generateHmacSignature(keyMaterial, infoEncoded, headerBytes) - return buildFromCipherText(headerBytes, ciphertext, senderHmac, shouldPush) + return buildFromCipherText(headerBytes, ciphertext, senderHmacGenerated, shouldPush) } } } From 92a5712232422ba32fdf7a3de1382aba61372f6e Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Thu, 8 Feb 2024 02:12:30 -0600 Subject: [PATCH 06/31] Adding the proper way to manage the codec changes --- .../org/xmtp/android/library/CodecTest.kt | 28 ++++++++++ .../xmtp/android/library/ConversationTest.kt | 3 +- .../org/xmtp/android/library/MessageTest.kt | 34 ++++++------ .../org/xmtp/android/library/ReactionTest.kt | 52 ++++++++++++++++++- .../org/xmtp/android/library/Conversation.kt | 6 +-- .../xmtp/android/library/ConversationV2.kt | 24 ++------- .../android/library/codecs/ReactionCodec.kt | 3 +- .../android/library/messages/MessageV2.kt | 22 ++++++-- 8 files changed, 121 insertions(+), 51 deletions(-) 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 fd629daeb..b523318bb 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -12,6 +12,7 @@ import org.xmtp.android.library.codecs.ContentTypeIdBuilder import org.xmtp.android.library.codecs.DecodedComposite import org.xmtp.android.library.codecs.EncodedContent import org.xmtp.android.library.codecs.TextCodec +import org.xmtp.android.library.messages.MessageV2Builder import org.xmtp.android.library.messages.walletAddress data class NumberCodec( @@ -112,4 +113,31 @@ class CodecTest { assertEquals("sup", part1.content()) assertEquals(3.14, part2.content()) } + + @Test + fun testCanGetPushInfoBeforeDecoded() { + val codec = NumberCodec() + Client.register(codec = codec) + val fixtures = fixtures() + val aliceClient = fixtures.aliceClient!! + val aliceConversation = + aliceClient.conversations.newConversation(fixtures.bob.walletAddress) + aliceConversation.send( + content = 3.14, + options = SendOptions(contentType = codec.contentType), + ) + val messages = aliceConversation.messages() + assert(messages.isNotEmpty()) + + val message = MessageV2Builder.buildEncode( + client = aliceClient, + encodedContent = messages[0].encodedContent, + topic = aliceConversation.topic, + keyMaterial = aliceConversation.keyMaterial!!, + codec = codec, + ) + + assertEquals(false, message.shouldPush) + assertEquals(true, message.senderHmac?.isNotEmpty()) + } } diff --git a/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt b/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt index 26625e179..0b0e87155 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ConversationTest.kt @@ -590,7 +590,7 @@ class ConversationTest { encodedContent, topic = conversation.topic, keyMaterial = conversation.keyMaterial!!, - shouldPush = true, + codec = encoder, ).messageV2, ).toByteArray(), ), @@ -854,7 +854,6 @@ class ConversationTest { val directMessageV1 = Topic.directMessageV1(invalidId, "sd").description val directMessageV2 = Topic.directMessageV2(invalidId).description val preferenceList = Topic.preferenceList(invalidId).description - val conversations = bobClient.conversations // check if validation of topics no accept all types with invalid topic assertFalse(Topic.isValidTopic(privateStore)) diff --git a/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt b/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt index 10a1e92fd..d89455406 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/MessageTest.kt @@ -53,7 +53,7 @@ class MessageTest { sender = alice, recipient = bob.toPublicKeyBundle(), message = content, - timestamp = Date() + timestamp = Date(), ) assertEquals(aliceWallet.getPrivateKey().walletAddress, message1.senderAddress) assertEquals(bobWallet.getPrivateKey().walletAddress, message1.recipientAddress) @@ -77,13 +77,13 @@ class MessageTest { InvitationV1.newBuilder().build().createDeterministic( sender = alice.toV2(), recipient = bob.toV2().getPublicKeyBundle(), - context = invitationContext + context = invitationContext, ) val sealedInvitation = SealedInvitationBuilder.buildFromV1( sender = alice.toV2(), recipient = bob.toV2().getPublicKeyBundle(), created = Date(), - invitation = invitationv1 + invitation = invitationv1, ) val encoder = TextCodec() val encodedContent = encoder.encode(content = "Yo!") @@ -92,14 +92,14 @@ class MessageTest { encodedContent, topic = invitationv1.topic, keyMaterial = invitationv1.aes256GcmHkdfSha256.keyMaterial.toByteArray(), - shouldPush = true, + codec = encoder, ) val decoded = MessageV2Builder.buildDecode( id = "", client = client, message = message1.messageV2, keyMaterial = invitationv1.aes256GcmHkdfSha256.keyMaterial.toByteArray(), - topic = invitationv1.topic + topic = invitationv1.topic, ) val result: String? = decoded.content() assertEquals(result, "Yo!") @@ -119,7 +119,7 @@ class MessageTest { Numeric.hexStringToByteArray("d752fb09ee0390fe5902a1bd7b2f530da7e5b3a2bd91bad9df8fa284ab63327b86a59620fd3e2d2cf9183f46bd0fe75bda3caca893420c38416b1f") val additionalData = Numeric.hexStringToByteArray( - "0aac020a940108d995eeadcc3012460a440a408f20c9fc03909edeb21538b0a568c423f8829e95c0270779ca704f72a45f02416f6071f6faaf421cac3bacc6bb432fc4b5f92bc4391349953c7c98f12253cdd710011a430a4104b7eb7b56059a4f08bf3dd8f1b329e21d486e39822f17db15bad0d7f689f6c8081ae2800b9014fc9ef355a39e10503fddfdfa0b07ccc1946c2275b10e660d5ded12920108e995eeadcc3012440a420a40da669aa014468ffe34d5b962443d8b1e353b1e39f252bbcffa5c6c70adf9f7d2484de944213f345bac869e8c1942657b9c59f6fc12d139171b22789bc76ffb971a430a4104901d3a7f728bde1f871bcf46d44dcf34eead4c532135913583268d35bd93ca0a1571a8cb6546ab333f2d77c3bb9839be7e8f27795ea4d6e979b6670dec20636d12aa020a920108bad3eaadcc3012440a420a4016d83a6e44ee8b9764f18fbb390f2a4049d92ff904ebd75c76a71d58a7f943744f8bed7d3696f9fb41ce450c5ab9f4a7f9a83e3d10f401bbe85e3992c5156d491a430a41047cebe3a23e573672363665d13220d368d37776e10232de9bd382d5af36392956dbd806f8b78bec5cdc111763e4ef4aff7dee65a8a15fee8d338c387320c5b23912920108bad3eaadcc3012440a420a404a751f28001f34a4136529a99e738279856da6b32a1ee9dba20849d9cd84b6165166a6abeae1139ed8df8be3b4594d9701309075f2b8d5d4de1f713fb62ae37e1a430a41049c45e552ac9f69c083bd358acac31a2e3cf7d9aa9298fef11b43252730949a39c68272302a61b548b13452e19272c119b5189a5d7b5c3283a37d5d9db5ed0c6818b286deaecc30" + "0aac020a940108d995eeadcc3012460a440a408f20c9fc03909edeb21538b0a568c423f8829e95c0270779ca704f72a45f02416f6071f6faaf421cac3bacc6bb432fc4b5f92bc4391349953c7c98f12253cdd710011a430a4104b7eb7b56059a4f08bf3dd8f1b329e21d486e39822f17db15bad0d7f689f6c8081ae2800b9014fc9ef355a39e10503fddfdfa0b07ccc1946c2275b10e660d5ded12920108e995eeadcc3012440a420a40da669aa014468ffe34d5b962443d8b1e353b1e39f252bbcffa5c6c70adf9f7d2484de944213f345bac869e8c1942657b9c59f6fc12d139171b22789bc76ffb971a430a4104901d3a7f728bde1f871bcf46d44dcf34eead4c532135913583268d35bd93ca0a1571a8cb6546ab333f2d77c3bb9839be7e8f27795ea4d6e979b6670dec20636d12aa020a920108bad3eaadcc3012440a420a4016d83a6e44ee8b9764f18fbb390f2a4049d92ff904ebd75c76a71d58a7f943744f8bed7d3696f9fb41ce450c5ab9f4a7f9a83e3d10f401bbe85e3992c5156d491a430a41047cebe3a23e573672363665d13220d368d37776e10232de9bd382d5af36392956dbd806f8b78bec5cdc111763e4ef4aff7dee65a8a15fee8d338c387320c5b23912920108bad3eaadcc3012440a420a404a751f28001f34a4136529a99e738279856da6b32a1ee9dba20849d9cd84b6165166a6abeae1139ed8df8be3b4594d9701309075f2b8d5d4de1f713fb62ae37e1a430a41049c45e552ac9f69c083bd358acac31a2e3cf7d9aa9298fef11b43252730949a39c68272302a61b548b13452e19272c119b5189a5d7b5c3283a37d5d9db5ed0c6818b286deaecc30", ) val ciphertext = CipherText.newBuilder().apply { aes256GcmHkdfSha256 = aes256GcmHkdfSha256.toBuilder().also { @@ -198,7 +198,7 @@ class MessageTest { val convo = client.conversations.list()[0] convo.send( text = "hello deflate from kotlin again", - SendOptions(compression = EncodedContentCompression.DEFLATE) + SendOptions(compression = EncodedContentCompression.DEFLATE), ) val message = convo.messages().lastOrNull()!! assertEquals("hello deflate from kotlin again", message.content()) @@ -240,7 +240,7 @@ class MessageTest { val convo = ConversationV1( client = client, peerAddress = "0xf4BF19Ed562651837bc11ff975472ABd239D35B5", - sentAt = Date() + sentAt = Date(), ) convo.send(text = "hello from kotlin") val messages = convo.messages() @@ -255,7 +255,7 @@ class MessageTest { val client = Client().create(account = wallet) val convo = client.conversations.newConversation( "0xf4BF19Ed562651837bc11ff975472ABd239D35B5", - InvitationV1ContextBuilder.buildFromConversation("https://example.com/4") + InvitationV1ContextBuilder.buildFromConversation("https://example.com/4"), ) convo.send(content = "hello from kotlin") @@ -280,7 +280,7 @@ class MessageTest { fun testGetsV2ID() { val envelopeMessageData = Numeric.hexStringToByteArray( - "12bf040a470880dedf9dafc0ff9e17123b2f786d74702f302f6d2d32536b644e355161305a6d694649357433524662667749532d4f4c76356a7573716e6465656e544c764e672f70726f746f12f3030af0030a20439174a205643a50af33c7670341338526dbb9c1cf0560687ff8a742e957282d120c090ba2b385b40639867493ce1abd037648c947f72e5c62e8691d7748e78f9a346ff401c97a628ebecf627d722829ff9cfb7d7c3e0b9e26b5801f2b5a39fd58757cc5771427bfefad6243f52cfc84b384fa042873ebeb90948aa80ca34f26ff883d64720c9228ed6bcd1a5c46953a12ae8732fd70260651455674e2e2c23bc8d64ed35562fef4cdfc55d38e72ad9cf2d597e68f48b6909967b0f5d0b4f33c0af3efce55c739fbc93888d20b833df15811823970a356b26622936564d830434d3ecde9a013f7433142e366f1df5589131e440251be54d5d6deef9aaaa9facac26eb54fb7b74eb48c5a2a9a2e2956633b123cc5b91dec03e4dba30683be03bd7510f16103d3f81712dccf2be003f2f77f9e1f162bc47f6c1c38a1068abd3403952bef31d75e8024e7a62d9a8cbd48f1872a0156abb559d01de689b4370a28454658957061c46f47fc5594808d15753876d4b5408b3a3410d0555c016e427dfceae9c05a4a21fd7ce4cfbb11b2a696170443cf310e0083b0a48e357fc2f00c688c0b56821c8a14c2bb44ddfa31d680dfc85efe4811e86c6aa3adfc373ad5731ddab83960774d98d60075b8fd70228da5d748bfb7a5334bd07e1cc4a9fbf3d5de50860d0684bb27786b5b4e00d415" + "12bf040a470880dedf9dafc0ff9e17123b2f786d74702f302f6d2d32536b644e355161305a6d694649357433524662667749532d4f4c76356a7573716e6465656e544c764e672f70726f746f12f3030af0030a20439174a205643a50af33c7670341338526dbb9c1cf0560687ff8a742e957282d120c090ba2b385b40639867493ce1abd037648c947f72e5c62e8691d7748e78f9a346ff401c97a628ebecf627d722829ff9cfb7d7c3e0b9e26b5801f2b5a39fd58757cc5771427bfefad6243f52cfc84b384fa042873ebeb90948aa80ca34f26ff883d64720c9228ed6bcd1a5c46953a12ae8732fd70260651455674e2e2c23bc8d64ed35562fef4cdfc55d38e72ad9cf2d597e68f48b6909967b0f5d0b4f33c0af3efce55c739fbc93888d20b833df15811823970a356b26622936564d830434d3ecde9a013f7433142e366f1df5589131e440251be54d5d6deef9aaaa9facac26eb54fb7b74eb48c5a2a9a2e2956633b123cc5b91dec03e4dba30683be03bd7510f16103d3f81712dccf2be003f2f77f9e1f162bc47f6c1c38a1068abd3403952bef31d75e8024e7a62d9a8cbd48f1872a0156abb559d01de689b4370a28454658957061c46f47fc5594808d15753876d4b5408b3a3410d0555c016e427dfceae9c05a4a21fd7ce4cfbb11b2a696170443cf310e0083b0a48e357fc2f00c688c0b56821c8a14c2bb44ddfa31d680dfc85efe4811e86c6aa3adfc373ad5731ddab83960774d98d60075b8fd70228da5d748bfb7a5334bd07e1cc4a9fbf3d5de50860d0684bb27786b5b4e00d415", ) val envelope = MessageApiOuterClass.Envelope.newBuilder().also { it.contentTopic = "/xmtp/0/m-2SkdN5Qa0ZmiFI5t3RFbfwIS-OLv5jusqndeenTLvNg/proto" @@ -289,7 +289,7 @@ class MessageTest { }.build() val ints = arrayOf( 80, 84, 15, 126, 14, 105, 216, 8, 61, 147, 153, 232, 103, 69, 219, 13, - 99, 118, 68, 56, 160, 94, 58, 22, 140, 247, 221, 172, 14, 188, 52, 88 + 99, 118, 68, 56, 160, 94, 58, 22, 140, 247, 221, 172, 14, 188, 52, 88, ) val bytes = ints.foldIndexed(ByteArray(ints.size)) { i, a, v -> a.apply { set(i, v.toByte()) } } @@ -311,7 +311,7 @@ class MessageTest { val client = Client().buildFrom(bundle = keyBundle.v1) val conversationJSON = (""" {"version":"v2","topic":"/xmtp/0/m-2SkdN5Qa0ZmiFI5t3RFbfwIS-OLv5jusqndeenTLvNg/proto","keyMaterial":"ATA1L0O2aTxHmskmlGKCudqfGqwA1H+bad3W/GpGOr8=","peerAddress":"0x436D906d1339fC4E951769b1699051f020373D04","createdAt":"2023-01-26T22:58:45.068Z","context":{"conversationId":"pat/messageid","metadata":{}}} """).toByteArray( - UTF_8 + UTF_8, ) val decodedConversation = client.importConversation(conversationJSON) val conversation = ConversationV2( @@ -320,12 +320,12 @@ class MessageTest { context = Context.newBuilder().build(), peerAddress = decodedConversation.peerAddress, client = client, - header = Invitation.SealedInvitationHeaderV1.newBuilder().build() + header = Invitation.SealedInvitationHeaderV1.newBuilder().build(), ) val decodedMessage = conversation.decodeEnvelope(envelope) assertEquals( decodedMessage.id, - "e42a7dd44d0e1214824eab093cb89cfe6f666298d0af2d54fe0c914c8b72eff3" + "e42a7dd44d0e1214824eab093cb89cfe6f666298d0af2d54fe0c914c8b72eff3", ) } @@ -366,12 +366,12 @@ class MessageTest { val aliceSharedSecret = alicePrivateBundle.sharedSecret( peer = bobPublicBundle, myPreKey = alicePublicBundle.preKey, - isRecipient = true + isRecipient = true, ) val bobSharedSecret = bobPrivateBundle.sharedSecret( peer = alicePublicBundle, myPreKey = bobPublicBundle.preKey, - isRecipient = false + isRecipient = false, ) assert(aliceSharedSecret.contentEquals(bobSharedSecret)) } @@ -390,7 +390,7 @@ class MessageTest { val secret = meBundle.sharedSecret( peer = youBundlePublic, myPreKey = meBundle.preKeysList[0].publicKey, - isRecipient = true + isRecipient = true, ) assert(secretData.contentEquals(secret)) } 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 2a13f06ec..0333f1c8c 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ReactionTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ReactionTest.kt @@ -11,6 +11,7 @@ import org.xmtp.android.library.codecs.Reaction import org.xmtp.android.library.codecs.ReactionAction import org.xmtp.android.library.codecs.ReactionCodec import org.xmtp.android.library.codecs.ReactionSchema +import org.xmtp.android.library.messages.MessageV2Builder import org.xmtp.android.library.messages.walletAddress @RunWith(AndroidJUnit4::class) @@ -42,7 +43,7 @@ class ReactionTest { "action" to "added", "reference" to "abc123", "schema" to "shortcode", - ) + ), ) it.content = "smile".toByteStringUtf8() }.build() @@ -77,7 +78,7 @@ class ReactionTest { reference = messageToReact.id, action = ReactionAction.Added, content = "U+1F603", - schema = ReactionSchema.Unicode + schema = ReactionSchema.Unicode, ) aliceConversation.send( @@ -94,4 +95,51 @@ class ReactionTest { assertEquals(ReactionSchema.Unicode, content?.schema) } } + + @Test + fun testShouldPushMustBeTrue() { + Client.register(codec = ReactionCodec()) + + val fixtures = fixtures() + val aliceClient = fixtures.aliceClient + val aliceConversation = + aliceClient.conversations.newConversation(fixtures.bob.walletAddress) + + aliceConversation.send(text = "hey alice 2 bob") + + val messageToReact = aliceConversation.messages()[0] + + val attachment = Reaction( + reference = messageToReact.id, + action = ReactionAction.Added, + content = "U+1F603", + schema = ReactionSchema.Unicode, + ) + + aliceConversation.send( + content = attachment, + options = SendOptions(contentType = ContentTypeReaction), + ) + val messages = aliceConversation.messages() + assertEquals(messages.size, 2) + + val message = MessageV2Builder.buildEncode( + client = aliceClient, + encodedContent = messages[0].encodedContent, + topic = aliceConversation.topic, + keyMaterial = aliceConversation.keyMaterial!!, + codec = ReactionCodec(), + ) + + if (messages.size == 2) { + val content: Reaction? = messages.first().content() + assertEquals("U+1F603", content?.content) + assertEquals(messageToReact.id, content?.reference) + assertEquals(ReactionAction.Added, content?.action) + assertEquals(ReactionSchema.Unicode, content?.schema) + } + + assertEquals(true, message.shouldPush) + assertEquals(true, message.senderHmac?.isNotEmpty()) + } } diff --git a/library/src/main/java/org/xmtp/android/library/Conversation.kt b/library/src/main/java/org/xmtp/android/library/Conversation.kt index 1a24be3eb..51219b3ac 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversation.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversation.kt @@ -162,11 +162,7 @@ sealed class Conversation { } is V2 -> { - conversationV2.prepareMessage( - encodedContent = encodedContent, - options = options, - false, - ) + conversationV2.prepareMessage(encodedContent = encodedContent, options = options) } is Group -> throw XMTPException("Groups do not support prepared messages") // We return a encoded content not a preparedmessage which requires a envelope diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index c19e17a7f..a0c46fbfe 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -184,12 +184,7 @@ data class ConversationV2( } fun send(encodedContent: EncodedContent, options: SendOptions?): String { - val codec = Client.codecRegistry.find(options?.contentType) - val preparedMessage = prepareMessage( - encodedContent = encodedContent, - options = options, - shouldPush = shouldPush(codec, encodedContent.content.toStringUtf8()), - ) + val preparedMessage = prepareMessage(encodedContent = encodedContent, options = options) return send(preparedMessage) } @@ -208,7 +203,7 @@ data class ConversationV2( encodedContent = encodedContent, topic = topic, keyMaterial = keyMaterial, - shouldPush = shouldPush(codec, content), + codec = codec, ) val envelope = EnvelopeBuilder.buildFromString( topic = topic, @@ -218,15 +213,6 @@ data class ConversationV2( return envelope.toByteArray() } - fun , T> shouldPush(codec: Codec, content: Any?): Boolean { - val contentType = content as? T - if (contentType != null) { - return codec.shouldPush(content = content) - } else { - throw XMTPException("Codec invalid content") - } - } - fun prepareMessage(content: T, options: SendOptions?): PreparedMessage { val codec = Client.codecRegistry.find(options?.contentType) @@ -250,20 +236,20 @@ data class ConversationV2( if (compression != null) { encoded = encoded.compress(compression) } - return prepareMessage(encoded, options = options, shouldPush = shouldPush(codec, content)) + return prepareMessage(encoded, options = options) } fun prepareMessage( encodedContent: EncodedContent, options: SendOptions?, - shouldPush: Boolean, ): PreparedMessage { + val codec = Client.codecRegistry.find(options?.contentType) val message = MessageV2Builder.buildEncode( client = client, encodedContent = encodedContent, topic = topic, keyMaterial = keyMaterial, - shouldPush = shouldPush, + codec = codec, ) val newTopic = if (options?.ephemeral == true) ephemeralTopic else topic diff --git a/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt index cb786e765..cb0093a63 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/ReactionCodec.kt @@ -98,8 +98,7 @@ data class ReactionCodec(override var contentType: ContentTypeId = ContentTypeRe override fun shouldPush(content: Reaction): Boolean = when (content.action) { ReactionAction.Added -> true - ReactionAction.Removed -> false - ReactionAction.Unknown -> false + else -> false } } diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 7149c7677..b140b89cc 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -11,6 +11,7 @@ import org.xmtp.android.library.Crypto import org.xmtp.android.library.DecodedMessage import org.xmtp.android.library.KeyUtil import org.xmtp.android.library.XMTPException +import org.xmtp.android.library.codecs.ContentCodec import org.xmtp.android.library.codecs.EncodedContent import java.math.BigInteger import java.util.Date @@ -123,12 +124,20 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea ) } - fun buildEncode( + private fun , T> shouldPush(codec: Codec, content: T?): Boolean { + if (content != null) { + return codec.shouldPush(content = content) + } else { + throw XMTPException("Codec invalid content") + } + } + + fun , T> buildEncode( client: Client, encodedContent: EncodedContent, topic: String, keyMaterial: ByteArray, - shouldPush: Boolean, + codec: Codec, ): MessageV2Builder { val payload = encodedContent.toByteArray() val date = Date() @@ -143,13 +152,18 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea val ciphertext = Crypto.encrypt(keyMaterial, signedBytes, additionalData = headerBytes) val thirtyDayPeriodsSinceEpoch = - (System.currentTimeMillis() / 60 / 60 / 24 / 30).toInt() + (Date().time / 1000 / 60 / 60 / 24 / 30).toInt() val info = "$thirtyDayPeriodsSinceEpoch-${client.address}" val infoEncoded = info.toByteStringUtf8().toByteArray() val senderHmacGenerated = Crypto.generateHmacSignature(keyMaterial, infoEncoded, headerBytes) - return buildFromCipherText(headerBytes, ciphertext, senderHmacGenerated, shouldPush) + return buildFromCipherText( + headerBytes, + ciphertext, + senderHmacGenerated, + shouldPush(codec = codec, content = codec.decode(encodedContent)), + ) } } } From 97ea0c00c183e347077d59226fde1f99c9e6a63b Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Thu, 8 Feb 2024 02:16:57 -0600 Subject: [PATCH 07/31] Update GroupMembershipChangeCodec.kt --- .../xmtp/android/library/codecs/GroupMembershipChangeCodec.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/org/xmtp/android/library/codecs/GroupMembershipChangeCodec.kt b/library/src/main/java/org/xmtp/android/library/codecs/GroupMembershipChangeCodec.kt index 9d7e855fd..eb153c146 100644 --- a/library/src/main/java/org/xmtp/android/library/codecs/GroupMembershipChangeCodec.kt +++ b/library/src/main/java/org/xmtp/android/library/codecs/GroupMembershipChangeCodec.kt @@ -11,7 +11,7 @@ val ContentTypeGroupMembershipChange = ContentTypeIdBuilder.builderFromAuthority "xmtp.org", "group_membership_change", versionMajor = 1, - versionMinor = 0 + versionMinor = 0, ) data class GroupMembershipChangeCodec(override var contentType: ContentTypeId = ContentTypeGroupMembershipChange) : @@ -31,4 +31,6 @@ data class GroupMembershipChangeCodec(override var contentType: ContentTypeId = override fun fallback(content: GroupMembershipChanges): String? { return null } + + override fun shouldPush(content: GroupMembershipChanges): Boolean = false } From 696e22911bcda7f98fe79c86e2bcd781a9a53852 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 10 Feb 2024 12:59:35 -0800 Subject: [PATCH 08/31] Update library/src/main/java/org/xmtp/android/library/Crypto.kt Co-authored-by: Brendan McMillion --- library/src/main/java/org/xmtp/android/library/Crypto.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index 681f2d33e..5fa512903 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -90,7 +90,7 @@ class Crypto { salt: ByteArray, info: ByteArray, ): ByteArray { - val derivationParameters = HKDFParameters(secret, salt, info) + val derivationParameters = HKDFParameters(secret, ByteArray(0), info) val digest = SHA256Digest() val hkdfGenerator = HKDFBytesGenerator(digest) hkdfGenerator.init(derivationParameters) From 241992abe58043fc7daab00961859822d74869c6 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 10 Feb 2024 12:59:40 -0800 Subject: [PATCH 09/31] Update library/src/main/java/org/xmtp/android/library/Crypto.kt Co-authored-by: Brendan McMillion --- library/src/main/java/org/xmtp/android/library/Crypto.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index 5fa512903..7db53cdb6 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -87,7 +87,6 @@ class Crypto { fun deriveKey( secret: ByteArray, - salt: ByteArray, info: ByteArray, ): ByteArray { val derivationParameters = HKDFParameters(secret, ByteArray(0), info) From 33d50f338619eb2474b639d6a8523da0932d48d6 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 10 Feb 2024 12:59:45 -0800 Subject: [PATCH 10/31] Update library/src/main/java/org/xmtp/android/library/Crypto.kt Co-authored-by: Brendan McMillion --- library/src/main/java/org/xmtp/android/library/Crypto.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index 7db53cdb6..734102ed8 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -103,8 +103,8 @@ class Crypto { info: ByteArray, message: ByteArray, ): ByteArray { - val hkdfKey = deriveKey(secret, message, info) - return calculateMac(secret, hkdfKey) + val hkdfKey = deriveKey(secret, info) + return calculateMac(hkdfKey, message) } } } From fd46f810102b3aae1d9776a7cc1d59d78b7e03cd Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 10 Feb 2024 13:51:14 -0800 Subject: [PATCH 11/31] add method to get the hmac keys --- .../org/xmtp/android/library/Conversations.kt | 45 +++++++++++++++++++ .../android/library/messages/MessageV2.kt | 2 + 2 files changed, 47 insertions(+) diff --git a/library/src/main/java/org/xmtp/android/library/Conversations.kt b/library/src/main/java/org/xmtp/android/library/Conversations.kt index cec8da0de..fb479b981 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversations.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversations.kt @@ -1,6 +1,7 @@ package org.xmtp.android.library import android.util.Log +import com.google.protobuf.kotlin.toByteStringUtf8 import io.grpc.StatusException import kotlinx.coroutines.CancellationException import kotlinx.coroutines.channels.awaitClose @@ -16,6 +17,7 @@ import org.xmtp.android.library.libxmtp.Message import org.xmtp.android.library.messages.DecryptedMessage import org.xmtp.android.library.messages.Envelope import org.xmtp.android.library.messages.EnvelopeBuilder +import org.xmtp.android.library.messages.HmacKeyValue import org.xmtp.android.library.messages.InvitationV1 import org.xmtp.android.library.messages.MessageV1Builder import org.xmtp.android.library.messages.Pagination @@ -298,6 +300,49 @@ data class Conversations( return conversation } + fun getHmacKeys( + topics: List, + ): Map> { + val thirtyDayPeriodsSinceEpoch = (Date().time / 1000 / 60 / 60 / 24 / 30).toInt() + + val requests = topics.map { topic -> + makeQueryRequest(topic = topic) + } + // The maximum number of requests permitted in a single batch call. + val maxQueryRequestsPerBatch = 50 + val hmacKeys = mutableMapOf>() + val batches = requests.chunked(maxQueryRequestsPerBatch) + for (batch in batches) { + runBlocking { + client.batchQuery(batch).responsesOrBuilderList.flatMap { res -> + res.envelopesList.mapNotNull { envelope -> + val conversation = conversationsByTopic[envelope.contentTopic] + if (conversation == null || conversation.keyMaterial != null) { + Log.d(TAG, "discarding unknown conversation $envelope") + return@mapNotNull null + } + val values = + (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).map { value -> + val info = "$value-${client.address}" + val hmacKey = + Crypto.calculateMac( + conversation.keyMaterial!!, + info.toByteStringUtf8().toByteArray() + ) + HmacKeyValue( + thirtyDayPeriodsSinceEpoch = value, + hmacKey = hmacKey + ) + } + hmacKeys[conversation.topic] = values + + } + } + } + } + return hmacKeys + } + private fun listIntroductionPeers(pagination: Pagination? = null): Map { val envelopes = runBlocking { diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index b140b89cc..4c80dcf11 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -167,3 +167,5 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea } } } + +data class HmacKeyValue(val thirtyDayPeriodsSinceEpoch: Int, val hmacKey: ByteArray) From deec4b0d6f302c5873e5d9855086a09a38c55927 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Sat, 10 Feb 2024 13:59:06 -0800 Subject: [PATCH 12/31] fix up the crypto --- .../src/main/java/org/xmtp/android/library/Crypto.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index 734102ed8..8227d9149 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -87,9 +87,10 @@ class Crypto { fun deriveKey( secret: ByteArray, + salt: ByteArray, info: ByteArray, ): ByteArray { - val derivationParameters = HKDFParameters(secret, ByteArray(0), info) + val derivationParameters = HKDFParameters(secret, salt, info) val digest = SHA256Digest() val hkdfGenerator = HKDFBytesGenerator(digest) hkdfGenerator.init(derivationParameters) @@ -103,8 +104,13 @@ class Crypto { info: ByteArray, message: ByteArray, ): ByteArray { - val hkdfKey = deriveKey(secret, info) - return calculateMac(hkdfKey, message) + val derivationParameters = HKDFParameters(secret, ByteArray(0), info) + val digest = SHA256Digest() + val hkdfGenerator = HKDFBytesGenerator(digest) + hkdfGenerator.init(derivationParameters) + val hkdf = ByteArray(32) + hkdfGenerator.generateBytes(hkdf, 0, hkdf.size) + return calculateMac(hkdf, message) } } } From c985c6af72827b91ffc42ca729e9100f845da814 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 12 Feb 2024 19:00:14 -0800 Subject: [PATCH 13/31] add the get keys code for hmacs --- .../org/xmtp/android/library/CodecTest.kt | 1 + .../org/xmtp/android/library/Conversations.kt | 68 +++++++++---------- .../android/library/messages/MessageV2.kt | 4 +- 3 files changed, 35 insertions(+), 38 deletions(-) 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 b523318bb..43e52cf05 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -139,5 +139,6 @@ class CodecTest { assertEquals(false, message.shouldPush) assertEquals(true, message.senderHmac?.isNotEmpty()) + val keys = aliceClient.conversations.getHmacKeys() } } diff --git a/library/src/main/java/org/xmtp/android/library/Conversations.kt b/library/src/main/java/org/xmtp/android/library/Conversations.kt index fb479b981..675bc0854 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversations.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversations.kt @@ -1,6 +1,7 @@ package org.xmtp.android.library import android.util.Log +import com.google.protobuf.kotlin.toByteString import com.google.protobuf.kotlin.toByteStringUtf8 import io.grpc.StatusException import kotlinx.coroutines.CancellationException @@ -17,7 +18,6 @@ import org.xmtp.android.library.libxmtp.Message import org.xmtp.android.library.messages.DecryptedMessage import org.xmtp.android.library.messages.Envelope import org.xmtp.android.library.messages.EnvelopeBuilder -import org.xmtp.android.library.messages.HmacKeyValue import org.xmtp.android.library.messages.InvitationV1 import org.xmtp.android.library.messages.MessageV1Builder import org.xmtp.android.library.messages.Pagination @@ -35,6 +35,9 @@ import org.xmtp.android.library.messages.senderAddress import org.xmtp.android.library.messages.sentAt import org.xmtp.android.library.messages.toSignedPublicKeyBundle import org.xmtp.android.library.messages.walletAddress +import org.xmtp.proto.keystore.api.v1.Keystore +import org.xmtp.proto.keystore.api.v1.Keystore.GetConversationHmacKeysResponse.HmacKeyData +import org.xmtp.proto.keystore.api.v1.Keystore.GetConversationHmacKeysResponse.HmacKeys import org.xmtp.proto.keystore.api.v1.Keystore.TopicMap.TopicData import org.xmtp.proto.message.contents.Contact import org.xmtp.proto.message.contents.Invitation @@ -49,6 +52,7 @@ import java.util.Date import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.DurationUnit + data class Conversations( var client: Client, var conversationsByTopic: MutableMap = mutableMapOf(), @@ -301,46 +305,40 @@ data class Conversations( } fun getHmacKeys( - topics: List, - ): Map> { + request: Keystore.GetConversationHmacKeysRequest? = null, + ): Keystore.GetConversationHmacKeysResponse { val thirtyDayPeriodsSinceEpoch = (Date().time / 1000 / 60 / 60 / 24 / 30).toInt() + val hmacKeys = Keystore.GetConversationHmacKeysResponse.newBuilder() + + var topics = conversationsByTopic - val requests = topics.map { topic -> - makeQueryRequest(topic = topic) + if (!request?.topicsList.isNullOrEmpty()) { + topics = topics.filter { + request!!.topicsList.contains(it.key) + }.toMutableMap() } - // The maximum number of requests permitted in a single batch call. - val maxQueryRequestsPerBatch = 50 - val hmacKeys = mutableMapOf>() - val batches = requests.chunked(maxQueryRequestsPerBatch) - for (batch in batches) { - runBlocking { - client.batchQuery(batch).responsesOrBuilderList.flatMap { res -> - res.envelopesList.mapNotNull { envelope -> - val conversation = conversationsByTopic[envelope.contentTopic] - if (conversation == null || conversation.keyMaterial != null) { - Log.d(TAG, "discarding unknown conversation $envelope") - return@mapNotNull null - } - val values = - (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).map { value -> - val info = "$value-${client.address}" - val hmacKey = - Crypto.calculateMac( - conversation.keyMaterial!!, - info.toByteStringUtf8().toByteArray() - ) - HmacKeyValue( - thirtyDayPeriodsSinceEpoch = value, - hmacKey = hmacKey - ) - } - hmacKeys[conversation.topic] = values - } - } + topics.forEach { + val conversation = it.value + + (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).map { value -> + val info = "$value-${client.address}" + val hmacKey = + Crypto.calculateMac( + conversation.keyMaterial!!, + info.toByteStringUtf8().toByteArray() + ) + + hmacKeys.putHmacKeys( + conversation.topic, HmacKeys.newBuilder().addValues( + HmacKeyData.newBuilder().setHmacKey(hmacKey.toByteString()) + .setThirtyDayPeriodsSinceEpoch(value).build() + ).build() + ) } } - return hmacKeys + + return hmacKeys.build() } private fun listIntroductionPeers(pagination: Pagination? = null): Map { diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 4c80dcf11..8e1b7e37d 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -166,6 +166,4 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea ) } } -} - -data class HmacKeyValue(val thirtyDayPeriodsSinceEpoch: Int, val hmacKey: ByteArray) +} \ No newline at end of file From 2127f775f01f4a1758e55ce0a4b0cb404cdee6cd Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 12 Feb 2024 19:03:23 -0800 Subject: [PATCH 14/31] remove unneeded crypto code --- .../main/java/org/xmtp/android/library/Crypto.kt | 14 -------------- .../org/xmtp/android/library/messages/MessageV2.kt | 5 ++++- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index 8227d9149..db590def2 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -98,19 +98,5 @@ class Crypto { hkdfGenerator.generateBytes(hkdf, 0, hkdf.size) return hkdf } - - fun generateHmacSignature( - secret: ByteArray, - info: ByteArray, - message: ByteArray, - ): ByteArray { - val derivationParameters = HKDFParameters(secret, ByteArray(0), info) - val digest = SHA256Digest() - val hkdfGenerator = HKDFBytesGenerator(digest) - hkdfGenerator.init(derivationParameters) - val hkdf = ByteArray(32) - hkdfGenerator.generateBytes(hkdf, 0, hkdf.size) - return calculateMac(hkdf, message) - } } } diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 8e1b7e37d..913adc8d8 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -156,7 +156,10 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea val info = "$thirtyDayPeriodsSinceEpoch-${client.address}" val infoEncoded = info.toByteStringUtf8().toByteArray() val senderHmacGenerated = - Crypto.generateHmacSignature(keyMaterial, infoEncoded, headerBytes) + Crypto.calculateMac( + Crypto.deriveKey(keyMaterial, ByteArray(0), infoEncoded), + headerBytes + ) return buildFromCipherText( headerBytes, From ca3416c733ba4bdf1cb44ec5eddddea272039f1a Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 12 Feb 2024 20:38:29 -0800 Subject: [PATCH 15/31] write a test for it --- .../org/xmtp/android/library/CodecTest.kt | 83 +++++++++++++++++++ .../java/org/xmtp/android/library/Crypto.kt | 16 ++++ 2 files changed, 99 insertions(+) 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 43e52cf05..29f6960bb 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -3,8 +3,11 @@ package org.xmtp.android.library import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.protobuf.kotlin.toByteStringUtf8 import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith +import org.xmtp.android.library.Crypto.Companion.calculateMac +import org.xmtp.android.library.Crypto.Companion.verifyHmacSignature import org.xmtp.android.library.codecs.CompositeCodec import org.xmtp.android.library.codecs.ContentCodec import org.xmtp.android.library.codecs.ContentTypeId @@ -12,8 +15,19 @@ import org.xmtp.android.library.codecs.ContentTypeIdBuilder import org.xmtp.android.library.codecs.DecodedComposite import org.xmtp.android.library.codecs.EncodedContent import org.xmtp.android.library.codecs.TextCodec +import org.xmtp.android.library.messages.InvitationV1 import org.xmtp.android.library.messages.MessageV2Builder +import org.xmtp.android.library.messages.PrivateKeyBuilder +import org.xmtp.android.library.messages.PrivateKeyBundleV1 +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.getPublicKeyBundle +import org.xmtp.android.library.messages.toV2 import org.xmtp.android.library.messages.walletAddress +import java.security.Key +import java.time.Instant +import java.util.Date data class NumberCodec( override var contentType: ContentTypeId = ContentTypeIdBuilder.builderFromAuthorityId( @@ -141,4 +155,73 @@ class CodecTest { assertEquals(true, message.senderHmac?.isNotEmpty()) val keys = aliceClient.conversations.getHmacKeys() } + + @Test + fun testReturnsAllHMACKeys() { + val baseTime = Instant.now() + val timestamps = List(5) { i -> baseTime.plusSeconds(i.toLong()) } + val fixtures = fixtures() + + val invites = timestamps.map { createdAt -> + val fakeWallet = FakeWallet.generate() + val recipient = PrivateKeyBundleV1.newBuilder().build().generate(wallet = fakeWallet) + InvitationV1.newBuilder().build().createDeterministic( + sender = fixtures.aliceClient.privateKeyBundleV1.toV2(), + recipient = recipient.toV2().getPublicKeyBundle() + ) + } + + val thirtyDayPeriodsSinceEpoch = Instant.now().epochSecond / 60 / 60 / 24 / 30 + + val periods = listOf( + thirtyDayPeriodsSinceEpoch - 1, + thirtyDayPeriodsSinceEpoch, + thirtyDayPeriodsSinceEpoch + 1 + ) + + val hmacKeys = fixtures.aliceClient.conversations.getHmacKeys() + + val topics = hmacKeys.hmacKeysMap.keys + invites.forEach { invite -> + assertTrue(topics.contains(invite.topic)) + } + + val topicHmacs = mutableMapOf() + val headerBytes = ByteArray(10) + + invites.map { invite -> + val topic = invite.topic + val payload = TextCodec().encode(content = "Hello, world!") + + val message = MessageV2Builder.buildEncode( + client = fixtures.aliceClient, + encodedContent = payload, + topic = topic, + keyMaterial = headerBytes, + codec = TextCodec() + ) + + val conversation = fixtures.aliceClient.fetchConversation(topic) + val keyMaterial = conversation?.keyMaterial + val info = "$thirtyDayPeriodsSinceEpoch-${fixtures.aliceClient.address}" + val hmac = Crypto.calculateMac( + Crypto.deriveKey(keyMaterial!!, ByteArray(0), info.toByteArray()), + headerBytes + ) + + topicHmacs[topic] = hmac + } + + hmacKeys.hmacKeysMap.forEach { (topic, hmacData) -> + hmacData.valuesList.forEachIndexed { idx, hmacKeyThirtyDayPeriod -> + val valid = verifyHmacSignature( + hmacKeyThirtyDayPeriod.hmacKey.toByteArray(), + topicHmacs[topic]!!, + headerBytes + ) + assertTrue(valid == (idx == 1)) + } + } + + } } diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index db590def2..7738d7232 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -8,6 +8,7 @@ import org.bouncycastle.crypto.generators.HKDFBytesGenerator import org.bouncycastle.crypto.params.HKDFParameters import org.xmtp.proto.message.contents.CiphertextOuterClass import java.security.GeneralSecurityException +import java.security.Key import java.security.SecureRandom import javax.crypto.Cipher import javax.crypto.Mac @@ -98,5 +99,20 @@ class Crypto { hkdfGenerator.generateBytes(hkdf, 0, hkdf.size) return hkdf } + + fun verifyHmacSignature( + key: ByteArray, + signature: ByteArray, + message: ByteArray + ): Boolean { + return try { + val mac = Mac.getInstance("HmacSHA256") + mac.init(SecretKeySpec(key, "HmacSHA256")) + val computedSignature = mac.doFinal(message) + java.util.Arrays.equals(signature, computedSignature) + } catch (e: Exception) { + false + } + } } } From dd29da473a15767fb12e10bcb1b973c4ca72a0e3 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 19 Feb 2024 21:07:05 -0800 Subject: [PATCH 16/31] get the test to pass --- .../org/xmtp/android/library/CodecTest.kt | 58 +++++++------------ .../org/xmtp/android/library/Conversations.kt | 31 +++++----- .../java/org/xmtp/android/library/Crypto.kt | 1 - .../android/library/messages/MessageV2.kt | 2 +- 4 files changed, 39 insertions(+), 53 deletions(-) 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 29f6960bb..b33f66c0e 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -6,7 +6,6 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith -import org.xmtp.android.library.Crypto.Companion.calculateMac import org.xmtp.android.library.Crypto.Companion.verifyHmacSignature import org.xmtp.android.library.codecs.CompositeCodec import org.xmtp.android.library.codecs.ContentCodec @@ -15,19 +14,11 @@ import org.xmtp.android.library.codecs.ContentTypeIdBuilder import org.xmtp.android.library.codecs.DecodedComposite import org.xmtp.android.library.codecs.EncodedContent import org.xmtp.android.library.codecs.TextCodec -import org.xmtp.android.library.messages.InvitationV1 +import org.xmtp.android.library.messages.InvitationV1ContextBuilder import org.xmtp.android.library.messages.MessageV2Builder import org.xmtp.android.library.messages.PrivateKeyBuilder -import org.xmtp.android.library.messages.PrivateKeyBundleV1 -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.getPublicKeyBundle -import org.xmtp.android.library.messages.toV2 import org.xmtp.android.library.messages.walletAddress -import java.security.Key import java.time.Instant -import java.util.Date data class NumberCodec( override var contentType: ContentTypeId = ContentTypeIdBuilder.builderFromAuthorityId( @@ -158,52 +149,48 @@ class CodecTest { @Test fun testReturnsAllHMACKeys() { - val baseTime = Instant.now() - val timestamps = List(5) { i -> baseTime.plusSeconds(i.toLong()) } - val fixtures = fixtures() - - val invites = timestamps.map { createdAt -> - val fakeWallet = FakeWallet.generate() - val recipient = PrivateKeyBundleV1.newBuilder().build().generate(wallet = fakeWallet) - InvitationV1.newBuilder().build().createDeterministic( - sender = fixtures.aliceClient.privateKeyBundleV1.toV2(), - recipient = recipient.toV2().getPublicKeyBundle() + val alix = PrivateKeyBuilder() + val clientOptions = + ClientOptions(api = ClientOptions.Api(env = XMTPEnvironment.LOCAL, isSecure = false)) + val alixClient = Client().create(alix, clientOptions) + val conversations = mutableListOf() + repeat(5) { + val account = PrivateKeyBuilder() + val client = Client().create(account, clientOptions) + conversations.add( + alixClient.conversations.newConversation( + client.address, + context = InvitationV1ContextBuilder.buildFromConversation(conversationId = "hi") + ) ) } val thirtyDayPeriodsSinceEpoch = Instant.now().epochSecond / 60 / 60 / 24 / 30 - val periods = listOf( - thirtyDayPeriodsSinceEpoch - 1, - thirtyDayPeriodsSinceEpoch, - thirtyDayPeriodsSinceEpoch + 1 - ) - - val hmacKeys = fixtures.aliceClient.conversations.getHmacKeys() + val hmacKeys = alixClient.conversations.getHmacKeys() val topics = hmacKeys.hmacKeysMap.keys - invites.forEach { invite -> - assertTrue(topics.contains(invite.topic)) + conversations.forEach { convo -> + assertTrue(topics.contains(convo.topic)) } val topicHmacs = mutableMapOf() val headerBytes = ByteArray(10) - invites.map { invite -> - val topic = invite.topic + conversations.map { conversation -> + val topic = conversation.topic val payload = TextCodec().encode(content = "Hello, world!") val message = MessageV2Builder.buildEncode( - client = fixtures.aliceClient, + client = alixClient, encodedContent = payload, topic = topic, keyMaterial = headerBytes, codec = TextCodec() ) - val conversation = fixtures.aliceClient.fetchConversation(topic) - val keyMaterial = conversation?.keyMaterial - val info = "$thirtyDayPeriodsSinceEpoch-${fixtures.aliceClient.address}" + val keyMaterial = conversation.keyMaterial + val info = "$thirtyDayPeriodsSinceEpoch-${alixClient.address}" val hmac = Crypto.calculateMac( Crypto.deriveKey(keyMaterial!!, ByteArray(0), info.toByteArray()), headerBytes @@ -222,6 +209,5 @@ class CodecTest { assertTrue(valid == (idx == 1)) } } - } } diff --git a/library/src/main/java/org/xmtp/android/library/Conversations.kt b/library/src/main/java/org/xmtp/android/library/Conversations.kt index 675bc0854..3dc2abaa3 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversations.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversations.kt @@ -52,7 +52,6 @@ import java.util.Date import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.DurationUnit - data class Conversations( var client: Client, var conversationsByTopic: MutableMap = mutableMapOf(), @@ -320,21 +319,23 @@ data class Conversations( topics.forEach { val conversation = it.value - - (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).map { value -> - val info = "$value-${client.address}" - val hmacKey = - Crypto.calculateMac( - conversation.keyMaterial!!, - info.toByteStringUtf8().toByteArray() + if (conversation.keyMaterial != null) { + (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).map { value -> + val info = "$value-${client.address}" + val hmacKey = + Crypto.calculateMac( + conversation.keyMaterial!!, + info.toByteStringUtf8().toByteArray() + ) + + hmacKeys.putHmacKeys( + conversation.topic, + HmacKeys.newBuilder().addValues( + HmacKeyData.newBuilder().setHmacKey(hmacKey.toByteString()) + .setThirtyDayPeriodsSinceEpoch(value).build() + ).build() ) - - hmacKeys.putHmacKeys( - conversation.topic, HmacKeys.newBuilder().addValues( - HmacKeyData.newBuilder().setHmacKey(hmacKey.toByteString()) - .setThirtyDayPeriodsSinceEpoch(value).build() - ).build() - ) + } } } diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index 7738d7232..217645826 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -8,7 +8,6 @@ import org.bouncycastle.crypto.generators.HKDFBytesGenerator import org.bouncycastle.crypto.params.HKDFParameters import org.xmtp.proto.message.contents.CiphertextOuterClass import java.security.GeneralSecurityException -import java.security.Key import java.security.SecureRandom import javax.crypto.Cipher import javax.crypto.Mac diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 913adc8d8..08afc0f06 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -169,4 +169,4 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea ) } } -} \ No newline at end of file +} From 866b5a37b3f649867037ef5c6819429db3fb653d Mon Sep 17 00:00:00 2001 From: Ezequiel Leanes Date: Tue, 20 Feb 2024 02:08:34 -0300 Subject: [PATCH 17/31] feat: integrate `shouldPush' for React Native (#184) * Add shouldPush property to SendOptions * Add shouldPush property to DecryptedMessage class * Add shouldPush parameter to ConversationV2 and MessageV2Builder --- .../src/main/java/org/xmtp/android/library/ConversationV2.kt | 1 + library/src/main/java/org/xmtp/android/library/SendOptions.kt | 3 ++- .../org/xmtp/android/library/messages/DecryptedMessage.kt | 3 ++- .../main/java/org/xmtp/android/library/messages/MessageV2.kt | 4 +++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index a0c46fbfe..8242c7641 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -250,6 +250,7 @@ data class ConversationV2( topic = topic, keyMaterial = keyMaterial, codec = codec, + shouldPush = options?.shouldPush ) val newTopic = if (options?.ephemeral == true) ephemeralTopic else topic diff --git a/library/src/main/java/org/xmtp/android/library/SendOptions.kt b/library/src/main/java/org/xmtp/android/library/SendOptions.kt index 313c4ae35..fb66f5dc1 100644 --- a/library/src/main/java/org/xmtp/android/library/SendOptions.kt +++ b/library/src/main/java/org/xmtp/android/library/SendOptions.kt @@ -5,5 +5,6 @@ import org.xmtp.proto.message.contents.Content data class SendOptions( var compression: EncodedContentCompression? = null, var contentType: Content.ContentTypeId? = null, - var ephemeral: Boolean = false + var ephemeral: Boolean = false, + var shouldPush: Boolean? = null ) diff --git a/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt b/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt index c2b2d4ef5..a2a661c75 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt @@ -8,5 +8,6 @@ data class DecryptedMessage( var encodedContent: EncodedContent, var senderAddress: String, var sentAt: Date, - var topic: String = "" + var topic: String = "", + var shouldPush: Boolean? ) diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 08afc0f06..401e5a7de 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -138,6 +138,7 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea topic: String, keyMaterial: ByteArray, codec: Codec, + shouldPush: Boolean? = null ): MessageV2Builder { val payload = encodedContent.toByteArray() val date = Date() @@ -160,12 +161,13 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea Crypto.deriveKey(keyMaterial, ByteArray(0), infoEncoded), headerBytes ) + val calculatedShouldPush = shouldPush ?: shouldPush(codec = codec, content = codec.decode(encodedContent)) return buildFromCipherText( headerBytes, ciphertext, senderHmacGenerated, - shouldPush(codec = codec, content = codec.decode(encodedContent)), + calculatedShouldPush, ) } } From 0279d00692447b62153a2f37433415c2bcfd2ecd Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Mon, 19 Feb 2024 10:45:06 -0600 Subject: [PATCH 18/31] Update GroupMembershipChangeTest.kt --- .../library/GroupMembershipChangeTest.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt index 96f53d7b0..cdf30cc55 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt @@ -1,5 +1,7 @@ package org.xmtp.android.library +import android.content.Context +import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import org.junit.Assert.assertEquals @@ -25,18 +27,17 @@ class GroupMembershipChangeTest { lateinit var caro: PrivateKey lateinit var caroClient: Client lateinit var fixtures: Fixtures + val context = ApplicationProvider.getApplicationContext() @Before fun setUp() { - val context = InstrumentationRegistry.getInstrumentation().targetContext - fixtures = - fixtures( - clientOptions = ClientOptions( - ClientOptions.Api(XMTPEnvironment.LOCAL, false), - enableAlphaMls = true, - appContext = context - ) + fixtures = fixtures( + clientOptions = ClientOptions( + ClientOptions.Api(XMTPEnvironment.LOCAL, false), + enableAlphaMls = true, + appContext = context, ) + ) alixWallet = fixtures.aliceAccount alix = fixtures.alice boWallet = fixtures.bobAccount From 578e4b97dd0c3e5810b07980820a4a026739b42c Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Tue, 20 Feb 2024 09:33:57 -0600 Subject: [PATCH 19/31] Removing issues and failing tests --- .../androidTest/java/org/xmtp/android/library/ClientTest.kt | 3 +++ .../src/androidTest/java/org/xmtp/android/library/CodecTest.kt | 2 ++ .../java/org/xmtp/android/library/GroupMembershipChangeTest.kt | 2 ++ .../src/androidTest/java/org/xmtp/android/library/GroupTest.kt | 2 ++ .../src/main/java/org/xmtp/android/library/ConversationV1.kt | 1 + .../main/java/org/xmtp/android/library/messages/MessageV2.kt | 1 + 6 files changed, 11 insertions(+) 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 98c287ed6..467793842 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt @@ -63,6 +63,7 @@ class ClientTest { ) } + @Ignore @Test fun testCanBeCreatedWithV1Bundle() { val fakeWallet = PrivateKeyBuilder() @@ -80,6 +81,7 @@ class ClientTest { ) } + @Ignore @Test fun testV3CanBeCreatedWithBundle() { val context = InstrumentationRegistry.getInstrumentation().targetContext @@ -109,6 +111,7 @@ class ClientTest { ) } + @Ignore @Test fun testCreatesAV3Client() { val context = InstrumentationRegistry.getInstrumentation().targetContext 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 b33f66c0e..0f4260859 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.protobuf.kotlin.toByteStringUtf8 import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.Crypto.Companion.verifyHmacSignature @@ -147,6 +148,7 @@ class CodecTest { val keys = aliceClient.conversations.getHmacKeys() } + @Ignore @Test fun testReturnsAllHMACKeys() { val alix = PrivateKeyBuilder() diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt index cdf30cc55..6a7fddd40 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt @@ -6,6 +6,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import org.junit.Assert.assertEquals import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.messages.PrivateKey @@ -14,6 +15,7 @@ import org.xmtp.android.library.messages.walletAddress import uniffi.xmtpv3.org.xmtp.android.library.codecs.GroupMembershipChangeCodec import uniffi.xmtpv3.org.xmtp.android.library.codecs.GroupMembershipChanges +@Ignore @RunWith(AndroidJUnit4::class) class GroupMembershipChangeTest { lateinit var fakeApiClient: FakeApiClient 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 1758f694b..6d2f0b9a6 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Assert.assertThrows import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.codecs.ContentTypeReaction @@ -19,6 +20,7 @@ import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.walletAddress import uniffi.xmtpv3.GroupPermissions +@Ignore @RunWith(AndroidJUnit4::class) class GroupTest { private lateinit var fakeApiClient: FakeApiClient diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV1.kt b/library/src/main/java/org/xmtp/android/library/ConversationV1.kt index f23c73f73..f1fb7b4d2 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV1.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV1.kt @@ -127,6 +127,7 @@ data class ConversationV1( encodedContent = encodedMessage, senderAddress = header.sender.walletAddress, sentAt = message.v1.sentAt, + shouldPush = false, ) } catch (e: Exception) { throw XMTPException("Error decrypting message", e) diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 401e5a7de..4a54bf48c 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -121,6 +121,7 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea senderAddress = signed.sender.walletAddress, sentAt = Date(header.createdNs / 1_000_000), topic = topic, + shouldPush = false, ) } From c5d97df3a71559d95cc5dfe28bf163e44a9a4658 Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Tue, 20 Feb 2024 09:40:20 -0600 Subject: [PATCH 20/31] Update GroupMembershipChangeTest.kt --- .../java/org/xmtp/android/library/GroupMembershipChangeTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt index 6a7fddd40..382bb3919 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt @@ -3,7 +3,6 @@ package org.xmtp.android.library import android.content.Context import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Ignore From 50a413ca66aec554bb50e5419d70c53c026b9c7f Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Tue, 20 Feb 2024 10:06:31 -0600 Subject: [PATCH 21/31] Updating shouldPush flag and removing issues in instrumental testing --- .../androidTest/java/org/xmtp/android/library/ClientTest.kt | 6 +++--- .../androidTest/java/org/xmtp/android/library/CodecTest.kt | 2 +- .../org/xmtp/android/library/GroupMembershipChangeTest.kt | 2 +- .../androidTest/java/org/xmtp/android/library/GroupTest.kt | 2 +- .../main/java/org/xmtp/android/library/ConversationV1.kt | 1 - .../main/java/org/xmtp/android/library/ConversationV2.kt | 2 +- .../src/main/java/org/xmtp/android/library/SendOptions.kt | 2 +- .../org/xmtp/android/library/messages/DecryptedMessage.kt | 2 +- .../java/org/xmtp/android/library/messages/MessageV2.kt | 2 +- 9 files changed, 10 insertions(+), 11 deletions(-) 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 467793842..e71f82f68 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt @@ -63,7 +63,7 @@ class ClientTest { ) } - @Ignore + @Ignore("CI Issues") @Test fun testCanBeCreatedWithV1Bundle() { val fakeWallet = PrivateKeyBuilder() @@ -81,7 +81,7 @@ class ClientTest { ) } - @Ignore + @Ignore("CI Issues") @Test fun testV3CanBeCreatedWithBundle() { val context = InstrumentationRegistry.getInstrumentation().targetContext @@ -111,7 +111,7 @@ class ClientTest { ) } - @Ignore + @Ignore("CI Issues") @Test fun testCreatesAV3Client() { val context = InstrumentationRegistry.getInstrumentation().targetContext 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 0f4260859..4c40f69a3 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -148,7 +148,7 @@ class CodecTest { val keys = aliceClient.conversations.getHmacKeys() } - @Ignore + @Ignore("CI Issues") @Test fun testReturnsAllHMACKeys() { val alix = PrivateKeyBuilder() diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt index 382bb3919..44d1b89e5 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt @@ -14,7 +14,7 @@ import org.xmtp.android.library.messages.walletAddress import uniffi.xmtpv3.org.xmtp.android.library.codecs.GroupMembershipChangeCodec import uniffi.xmtpv3.org.xmtp.android.library.codecs.GroupMembershipChanges -@Ignore +@Ignore("CI Issues") @RunWith(AndroidJUnit4::class) class GroupMembershipChangeTest { lateinit var fakeApiClient: FakeApiClient 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 6d2f0b9a6..3f555fbbf 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt @@ -20,7 +20,7 @@ import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.walletAddress import uniffi.xmtpv3.GroupPermissions -@Ignore +@Ignore("CI Issues") @RunWith(AndroidJUnit4::class) class GroupTest { private lateinit var fakeApiClient: FakeApiClient diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV1.kt b/library/src/main/java/org/xmtp/android/library/ConversationV1.kt index f1fb7b4d2..f23c73f73 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV1.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV1.kt @@ -127,7 +127,6 @@ data class ConversationV1( encodedContent = encodedMessage, senderAddress = header.sender.walletAddress, sentAt = message.v1.sentAt, - shouldPush = false, ) } catch (e: Exception) { throw XMTPException("Error decrypting message", e) diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index 8242c7641..f362db0c6 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -250,7 +250,7 @@ data class ConversationV2( topic = topic, keyMaterial = keyMaterial, codec = codec, - shouldPush = options?.shouldPush + shouldPush = options?.__shouldPush ) val newTopic = if (options?.ephemeral == true) ephemeralTopic else topic diff --git a/library/src/main/java/org/xmtp/android/library/SendOptions.kt b/library/src/main/java/org/xmtp/android/library/SendOptions.kt index fb66f5dc1..748954d58 100644 --- a/library/src/main/java/org/xmtp/android/library/SendOptions.kt +++ b/library/src/main/java/org/xmtp/android/library/SendOptions.kt @@ -6,5 +6,5 @@ data class SendOptions( var compression: EncodedContentCompression? = null, var contentType: Content.ContentTypeId? = null, var ephemeral: Boolean = false, - var shouldPush: Boolean? = null + var __shouldPush: Boolean? = null ) diff --git a/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt b/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt index a2a661c75..d90890b03 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt @@ -9,5 +9,5 @@ data class DecryptedMessage( var senderAddress: String, var sentAt: Date, var topic: String = "", - var shouldPush: Boolean? + var shouldPush: Boolean? = null, ) diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 4a54bf48c..4a6e0c487 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -121,7 +121,7 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea senderAddress = signed.sender.walletAddress, sentAt = Date(header.createdNs / 1_000_000), topic = topic, - shouldPush = false, + shouldPush = message.shouldPush, ) } From 2f67cefabfb3bd87690c0698ad32b2f0bfe5426e Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Tue, 20 Feb 2024 10:17:41 -0600 Subject: [PATCH 22/31] Ignoring failing tests --- .../java/org/xmtp/android/library/ClientTest.kt | 6 +++--- .../java/org/xmtp/android/library/CodecTest.kt | 2 +- .../android/library/GroupMembershipChangeTest.kt | 4 +++- .../java/org/xmtp/android/library/GroupTest.kt | 14 +++++++++++++- 4 files changed, 20 insertions(+), 6 deletions(-) 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 e71f82f68..3c11818bf 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt @@ -63,8 +63,8 @@ class ClientTest { ) } - @Ignore("CI Issues") @Test + @Ignore("CI Issues") fun testCanBeCreatedWithV1Bundle() { val fakeWallet = PrivateKeyBuilder() val client = Client().create(account = fakeWallet) @@ -81,8 +81,8 @@ class ClientTest { ) } - @Ignore("CI Issues") @Test + @Ignore("CI Issues") fun testV3CanBeCreatedWithBundle() { val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() @@ -111,8 +111,8 @@ class ClientTest { ) } - @Ignore("CI Issues") @Test + @Ignore("CI Issues") fun testCreatesAV3Client() { val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() 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 4c40f69a3..54a48d18d 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -148,8 +148,8 @@ class CodecTest { val keys = aliceClient.conversations.getHmacKeys() } - @Ignore("CI Issues") @Test + @Ignore("CI Issues") fun testReturnsAllHMACKeys() { val alix = PrivateKeyBuilder() val clientOptions = diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt index 44d1b89e5..7064f2650 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt @@ -14,7 +14,6 @@ import org.xmtp.android.library.messages.walletAddress import uniffi.xmtpv3.org.xmtp.android.library.codecs.GroupMembershipChangeCodec import uniffi.xmtpv3.org.xmtp.android.library.codecs.GroupMembershipChanges -@Ignore("CI Issues") @RunWith(AndroidJUnit4::class) class GroupMembershipChangeTest { lateinit var fakeApiClient: FakeApiClient @@ -53,6 +52,7 @@ class GroupMembershipChangeTest { } @Test + @Ignore("CI Issues") fun testCanAddMembers() { Client.register(codec = GroupMembershipChangeCodec()) @@ -73,6 +73,7 @@ class GroupMembershipChangeTest { } @Test + @Ignore("CI Issues") fun testCanRemoveMembers() { Client.register(codec = GroupMembershipChangeCodec()) @@ -99,6 +100,7 @@ class GroupMembershipChangeTest { } @Test + @Ignore("CI Issues") fun testIfNotRegisteredReturnsFallback() { val group = alixClient.conversations.newGroup( listOf( 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 3f555fbbf..268cfc14a 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt @@ -20,7 +20,6 @@ import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.walletAddress import uniffi.xmtpv3.GroupPermissions -@Ignore("CI Issues") @RunWith(AndroidJUnit4::class) class GroupTest { private lateinit var fakeApiClient: FakeApiClient @@ -137,6 +136,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanListGroupMembers() { val group = boClient.conversations.newGroup( listOf( @@ -163,6 +163,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanAddGroupMembers() { val group = boClient.conversations.newGroup(listOf(alix.walletAddress)) group.addMembers(listOf(caro.walletAddress)) @@ -177,6 +178,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanRemoveGroupMembers() { val group = boClient.conversations.newGroup( listOf( @@ -195,6 +197,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanRemoveGroupMembersWhenNotCreator() { boClient.conversations.newGroup( listOf( @@ -215,6 +218,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testIsActiveReturnsCorrectly() { val group = boClient.conversations.newGroup( listOf( @@ -234,6 +238,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanListGroups() { boClient.conversations.newGroup(listOf(alix.walletAddress)) boClient.conversations.newGroup(listOf(caro.walletAddress)) @@ -242,6 +247,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanListGroupsAndConversations() { boClient.conversations.newGroup(listOf(alix.walletAddress)) boClient.conversations.newGroup(listOf(caro.walletAddress)) @@ -251,6 +257,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCannotSendMessageToGroupMemberNotOnV3() { val fakeApiClient = FakeApiClient() val chuxAccount = PrivateKeyBuilder() @@ -263,6 +270,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCannotStartGroupWithSelf() { assertThrows("Recipient is sender", XMTPException::class.java) { boClient.conversations.newGroup(listOf(bo.walletAddress)) @@ -270,6 +278,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCannotStartEmptyGroupChat() { assertThrows("Cannot start an empty group chat.", XMTPException::class.java) { boClient.conversations.newGroup(listOf()) @@ -303,6 +312,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanSendContentTypesToGroup() { Client.register(codec = ReactionCodec()) @@ -331,6 +341,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanStreamGroupMessages() = kotlinx.coroutines.test.runTest { val group = boClient.conversations.newGroup(listOf(alix.walletAddress.lowercase())) alixClient.conversations.syncGroups() @@ -419,6 +430,7 @@ class GroupTest { } @Test + @Ignore("CI Issues") fun testCanStreamGroupsAndConversations() = kotlinx.coroutines.test.runTest { boClient.conversations.streamAll().test { val group = From 2763b7e88da89926e15c8093da1641c080729e98 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 21 Feb 2024 00:21:05 -0800 Subject: [PATCH 23/31] remove all the ignored tests --- .../androidTest/java/org/xmtp/android/library/ClientTest.kt | 6 ------ .../androidTest/java/org/xmtp/android/library/CodecTest.kt | 4 +--- .../org/xmtp/android/library/GroupMembershipChangeTest.kt | 4 ---- .../androidTest/java/org/xmtp/android/library/GroupTest.kt | 1 - .../src/main/java/org/xmtp/android/library/Conversations.kt | 2 +- 5 files changed, 2 insertions(+), 15 deletions(-) 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 3c11818bf..c540f38d3 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt @@ -64,7 +64,6 @@ class ClientTest { } @Test - @Ignore("CI Issues") fun testCanBeCreatedWithV1Bundle() { val fakeWallet = PrivateKeyBuilder() val client = Client().create(account = fakeWallet) @@ -82,7 +81,6 @@ class ClientTest { } @Test - @Ignore("CI Issues") fun testV3CanBeCreatedWithBundle() { val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() @@ -112,7 +110,6 @@ class ClientTest { } @Test - @Ignore("CI Issues") fun testCreatesAV3Client() { val context = InstrumentationRegistry.getInstrumentation().targetContext val fakeWallet = PrivateKeyBuilder() @@ -205,7 +202,6 @@ class ClientTest { } @Test - @Ignore("CI Issues") fun testPublicCanMessage() { val aliceWallet = PrivateKeyBuilder() val notOnNetwork = PrivateKeyBuilder() @@ -221,7 +217,6 @@ class ClientTest { } @Test - @Ignore("CI Issues") fun testPreEnableIdentityCallback() { val fakeWallet = PrivateKeyBuilder() val expectation = CompletableFuture() @@ -244,7 +239,6 @@ class ClientTest { } @Test - @Ignore("CI Issues") fun testPreCreateIdentityCallback() { val fakeWallet = PrivateKeyBuilder() val expectation = CompletableFuture() 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 54a48d18d..88ffc998c 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -145,11 +145,9 @@ class CodecTest { assertEquals(false, message.shouldPush) assertEquals(true, message.senderHmac?.isNotEmpty()) - val keys = aliceClient.conversations.getHmacKeys() } @Test - @Ignore("CI Issues") fun testReturnsAllHMACKeys() { val alix = PrivateKeyBuilder() val clientOptions = @@ -179,7 +177,7 @@ class CodecTest { val topicHmacs = mutableMapOf() val headerBytes = ByteArray(10) - conversations.map { conversation -> + conversations.forEach { conversation -> val topic = conversation.topic val payload = TextCodec().encode(content = "Hello, world!") diff --git a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt index 7064f2650..8cb1e9de1 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupMembershipChangeTest.kt @@ -5,7 +5,6 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.messages.PrivateKey @@ -52,7 +51,6 @@ class GroupMembershipChangeTest { } @Test - @Ignore("CI Issues") fun testCanAddMembers() { Client.register(codec = GroupMembershipChangeCodec()) @@ -73,7 +71,6 @@ class GroupMembershipChangeTest { } @Test - @Ignore("CI Issues") fun testCanRemoveMembers() { Client.register(codec = GroupMembershipChangeCodec()) @@ -100,7 +97,6 @@ class GroupMembershipChangeTest { } @Test - @Ignore("CI Issues") fun testIfNotRegisteredReturnsFallback() { val group = alixClient.conversations.newGroup( listOf( 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 268cfc14a..d619f0e38 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt @@ -257,7 +257,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCannotSendMessageToGroupMemberNotOnV3() { val fakeApiClient = FakeApiClient() val chuxAccount = PrivateKeyBuilder() diff --git a/library/src/main/java/org/xmtp/android/library/Conversations.kt b/library/src/main/java/org/xmtp/android/library/Conversations.kt index 3dc2abaa3..ccca2104b 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversations.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversations.kt @@ -320,7 +320,7 @@ data class Conversations( topics.forEach { val conversation = it.value if (conversation.keyMaterial != null) { - (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).map { value -> + (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).forEach { value -> val info = "$value-${client.address}" val hmacKey = Crypto.calculateMac( From e113e3b6cb13ebdd7b284614c0342b0a93fc8311 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Tue, 20 Feb 2024 20:24:42 -0300 Subject: [PATCH 24/31] feat: add shouldPush property to MessageV2Builder --- .../src/main/java/org/xmtp/android/library/messages/MessageV2.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 4a6e0c487..3a44ea7e6 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -32,6 +32,7 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea messageBuilder.messageV2 = MessageV2.newBuilder().also { it.headerBytes = headerBytes.toByteString() it.ciphertext = ciphertext + it.shouldPush = shouldPush }.build() return messageBuilder } From df578cf58307a4a7beae3f528543d9684e4f64bd Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 21 Feb 2024 00:28:18 -0800 Subject: [PATCH 25/31] fix up the lint issue --- .../src/androidTest/java/org/xmtp/android/library/ClientTest.kt | 1 - .../src/androidTest/java/org/xmtp/android/library/CodecTest.kt | 1 - 2 files changed, 2 deletions(-) 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 c540f38d3..1f0086f8f 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt @@ -5,7 +5,6 @@ import androidx.test.platform.app.InstrumentationRegistry import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Assert.fail -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.messages.PrivateKeyBuilder 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 88ffc998c..2f152faef 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -4,7 +4,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.protobuf.kotlin.toByteStringUtf8 import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.Crypto.Companion.verifyHmacSignature From f37d913f0ca542bc8a16c7a647a2136b3dee8fbe Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Tue, 27 Feb 2024 21:48:16 -0300 Subject: [PATCH 26/31] fix: deriveKey function and improvements --- .../java/org/xmtp/android/library/Crypto.kt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/library/src/main/java/org/xmtp/android/library/Crypto.kt b/library/src/main/java/org/xmtp/android/library/Crypto.kt index 217645826..2160baa91 100644 --- a/library/src/main/java/org/xmtp/android/library/Crypto.kt +++ b/library/src/main/java/org/xmtp/android/library/Crypto.kt @@ -3,9 +3,6 @@ package org.xmtp.android.library import android.util.Log import com.google.crypto.tink.subtle.Hkdf import com.google.protobuf.kotlin.toByteString -import org.bouncycastle.crypto.digests.SHA256Digest -import org.bouncycastle.crypto.generators.HKDFBytesGenerator -import org.bouncycastle.crypto.params.HKDFParameters import org.xmtp.proto.message.contents.CiphertextOuterClass import java.security.GeneralSecurityException import java.security.SecureRandom @@ -90,13 +87,12 @@ class Crypto { salt: ByteArray, info: ByteArray, ): ByteArray { - val derivationParameters = HKDFParameters(secret, salt, info) - val digest = SHA256Digest() - val hkdfGenerator = HKDFBytesGenerator(digest) - hkdfGenerator.init(derivationParameters) - val hkdf = ByteArray(32) - hkdfGenerator.generateBytes(hkdf, 0, hkdf.size) - return hkdf + val keySpec = SecretKeySpec(secret, "HmacSHA256") + val hmac = Mac.getInstance("HmacSHA256") + hmac.init(keySpec) + val derivedKey = hmac.doFinal(salt + info) + + return derivedKey.copyOfRange(0, 32) } fun verifyHmacSignature( @@ -108,7 +104,7 @@ class Crypto { val mac = Mac.getInstance("HmacSHA256") mac.init(SecretKeySpec(key, "HmacSHA256")) val computedSignature = mac.doFinal(message) - java.util.Arrays.equals(signature, computedSignature) + computedSignature.contentEquals(signature) } catch (e: Exception) { false } From 7f9394ca896708a46fbd1188d263bd35054838a1 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Tue, 27 Feb 2024 21:48:54 -0300 Subject: [PATCH 27/31] fix: getHmacKeys method --- .../org/xmtp/android/library/Conversations.kt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/library/src/main/java/org/xmtp/android/library/Conversations.kt b/library/src/main/java/org/xmtp/android/library/Conversations.kt index ccca2104b..535efe0fd 100644 --- a/library/src/main/java/org/xmtp/android/library/Conversations.kt +++ b/library/src/main/java/org/xmtp/android/library/Conversations.kt @@ -307,7 +307,7 @@ data class Conversations( request: Keystore.GetConversationHmacKeysRequest? = null, ): Keystore.GetConversationHmacKeysResponse { val thirtyDayPeriodsSinceEpoch = (Date().time / 1000 / 60 / 60 / 24 / 30).toInt() - val hmacKeys = Keystore.GetConversationHmacKeysResponse.newBuilder() + val hmacKeysResponse = Keystore.GetConversationHmacKeysResponse.newBuilder() var topics = conversationsByTopic @@ -319,6 +319,7 @@ data class Conversations( topics.forEach { val conversation = it.value + val hmacKeys = HmacKeys.newBuilder() if (conversation.keyMaterial != null) { (thirtyDayPeriodsSinceEpoch - 1..thirtyDayPeriodsSinceEpoch + 1).forEach { value -> val info = "$value-${client.address}" @@ -327,19 +328,15 @@ data class Conversations( conversation.keyMaterial!!, info.toByteStringUtf8().toByteArray() ) - - hmacKeys.putHmacKeys( - conversation.topic, - HmacKeys.newBuilder().addValues( - HmacKeyData.newBuilder().setHmacKey(hmacKey.toByteString()) - .setThirtyDayPeriodsSinceEpoch(value).build() - ).build() - ) + val hmacKeyData = HmacKeyData.newBuilder() + hmacKeyData.hmacKey = hmacKey.toByteString() + hmacKeyData.thirtyDayPeriodsSinceEpoch = value + hmacKeys.addValues(hmacKeyData) } + hmacKeysResponse.putHmacKeys(conversation.topic, hmacKeys.build()) } } - - return hmacKeys.build() + return hmacKeysResponse.build() } private fun listIntroductionPeers(pagination: Pagination? = null): Map { From b04fc1ed3b23e8f720d2a1474fb7bb69a53f8695 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Tue, 27 Feb 2024 21:49:22 -0300 Subject: [PATCH 28/31] fix: CodecText.kt --- .../androidTest/java/org/xmtp/android/library/CodecTest.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 2f152faef..3d7464344 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/CodecTest.kt @@ -190,10 +190,8 @@ class CodecTest { val keyMaterial = conversation.keyMaterial val info = "$thirtyDayPeriodsSinceEpoch-${alixClient.address}" - val hmac = Crypto.calculateMac( - Crypto.deriveKey(keyMaterial!!, ByteArray(0), info.toByteArray()), - headerBytes - ) + val key = Crypto.deriveKey(keyMaterial!!, ByteArray(0), info.toByteArray()) + val hmac = Crypto.calculateMac(key, headerBytes) topicHmacs[topic] = hmac } From 6f14b68706f3fefb5cca9f698b70f62c6757c5cb Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Tue, 27 Feb 2024 21:52:07 -0300 Subject: [PATCH 29/31] Revert "feat: integrate `shouldPush' for React Native (#184)" This reverts commit 887f1f4dce979c57cf4d86d2fd035273fd70d78d. --- .../src/main/java/org/xmtp/android/library/ConversationV2.kt | 1 - library/src/main/java/org/xmtp/android/library/SendOptions.kt | 3 +-- .../org/xmtp/android/library/messages/DecryptedMessage.kt | 3 +-- .../main/java/org/xmtp/android/library/messages/MessageV2.kt | 4 +--- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt index f362db0c6..a0c46fbfe 100644 --- a/library/src/main/java/org/xmtp/android/library/ConversationV2.kt +++ b/library/src/main/java/org/xmtp/android/library/ConversationV2.kt @@ -250,7 +250,6 @@ data class ConversationV2( topic = topic, keyMaterial = keyMaterial, codec = codec, - shouldPush = options?.__shouldPush ) val newTopic = if (options?.ephemeral == true) ephemeralTopic else topic diff --git a/library/src/main/java/org/xmtp/android/library/SendOptions.kt b/library/src/main/java/org/xmtp/android/library/SendOptions.kt index 748954d58..313c4ae35 100644 --- a/library/src/main/java/org/xmtp/android/library/SendOptions.kt +++ b/library/src/main/java/org/xmtp/android/library/SendOptions.kt @@ -5,6 +5,5 @@ import org.xmtp.proto.message.contents.Content data class SendOptions( var compression: EncodedContentCompression? = null, var contentType: Content.ContentTypeId? = null, - var ephemeral: Boolean = false, - var __shouldPush: Boolean? = null + var ephemeral: Boolean = false ) diff --git a/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt b/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt index d90890b03..c2b2d4ef5 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/DecryptedMessage.kt @@ -8,6 +8,5 @@ data class DecryptedMessage( var encodedContent: EncodedContent, var senderAddress: String, var sentAt: Date, - var topic: String = "", - var shouldPush: Boolean? = null, + var topic: String = "" ) diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 3a44ea7e6..8874aed15 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -140,7 +140,6 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea topic: String, keyMaterial: ByteArray, codec: Codec, - shouldPush: Boolean? = null ): MessageV2Builder { val payload = encodedContent.toByteArray() val date = Date() @@ -163,13 +162,12 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea Crypto.deriveKey(keyMaterial, ByteArray(0), infoEncoded), headerBytes ) - val calculatedShouldPush = shouldPush ?: shouldPush(codec = codec, content = codec.decode(encodedContent)) return buildFromCipherText( headerBytes, ciphertext, senderHmacGenerated, - calculatedShouldPush, + shouldPush(codec = codec, content = codec.decode(encodedContent)), ) } } From 5050c3043b2338b311bc3128658e4a292119172f Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Tue, 27 Feb 2024 22:05:38 -0300 Subject: [PATCH 30/31] Revert "Removing issues and failing tests" This reverts commit e6cecc70a4e4508ae2bbe65f4152b720576e6fb2. --- .../src/main/java/org/xmtp/android/library/messages/MessageV2.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt index 8874aed15..e6f9302e7 100644 --- a/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt +++ b/library/src/main/java/org/xmtp/android/library/messages/MessageV2.kt @@ -122,7 +122,6 @@ class MessageV2Builder(val senderHmac: ByteArray? = null, val shouldPush: Boolea senderAddress = signed.sender.walletAddress, sentAt = Date(header.createdNs / 1_000_000), topic = topic, - shouldPush = message.shouldPush, ) } From 5bb1b5ac7f0ca3ed537fa78c909080b8823ed7f1 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Fri, 1 Mar 2024 13:05:17 -0300 Subject: [PATCH 31/31] Remove @Ignore annotations from GroupTest --- .../java/org/xmtp/android/library/GroupTest.kt | 13 ------------- 1 file changed, 13 deletions(-) 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 d619f0e38..1758f694b 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/GroupTest.kt @@ -7,7 +7,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Assert.assertThrows import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.xmtp.android.library.codecs.ContentTypeReaction @@ -136,7 +135,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanListGroupMembers() { val group = boClient.conversations.newGroup( listOf( @@ -163,7 +161,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanAddGroupMembers() { val group = boClient.conversations.newGroup(listOf(alix.walletAddress)) group.addMembers(listOf(caro.walletAddress)) @@ -178,7 +175,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanRemoveGroupMembers() { val group = boClient.conversations.newGroup( listOf( @@ -197,7 +193,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanRemoveGroupMembersWhenNotCreator() { boClient.conversations.newGroup( listOf( @@ -218,7 +213,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testIsActiveReturnsCorrectly() { val group = boClient.conversations.newGroup( listOf( @@ -238,7 +232,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanListGroups() { boClient.conversations.newGroup(listOf(alix.walletAddress)) boClient.conversations.newGroup(listOf(caro.walletAddress)) @@ -247,7 +240,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanListGroupsAndConversations() { boClient.conversations.newGroup(listOf(alix.walletAddress)) boClient.conversations.newGroup(listOf(caro.walletAddress)) @@ -269,7 +261,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCannotStartGroupWithSelf() { assertThrows("Recipient is sender", XMTPException::class.java) { boClient.conversations.newGroup(listOf(bo.walletAddress)) @@ -277,7 +268,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCannotStartEmptyGroupChat() { assertThrows("Cannot start an empty group chat.", XMTPException::class.java) { boClient.conversations.newGroup(listOf()) @@ -311,7 +301,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanSendContentTypesToGroup() { Client.register(codec = ReactionCodec()) @@ -340,7 +329,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanStreamGroupMessages() = kotlinx.coroutines.test.runTest { val group = boClient.conversations.newGroup(listOf(alix.walletAddress.lowercase())) alixClient.conversations.syncGroups() @@ -429,7 +417,6 @@ class GroupTest { } @Test - @Ignore("CI Issues") fun testCanStreamGroupsAndConversations() = kotlinx.coroutines.test.runTest { boClient.conversations.streamAll().test { val group =