commit 0f3fb7bcd0d111c47e585b3d09ea92e86774acaf parent a95c75a0b636b9f56a6ae28e6d01bfe8e8612c51 Author: rhunk <101876869+rhunk@users.noreply.github.com> Date: Wed, 17 Jan 2024 19:02:54 +0100 feat(ff_preview): decrypt e2ee messages Diffstat:
3 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/EndToEndEncryption.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/EndToEndEncryption.kt @@ -19,6 +19,7 @@ import me.rhunk.snapenhance.common.data.ContentType import me.rhunk.snapenhance.common.data.MessageState import me.rhunk.snapenhance.common.data.MessagingRuleType import me.rhunk.snapenhance.common.data.RuleState +import me.rhunk.snapenhance.common.database.impl.ConversationMessage import me.rhunk.snapenhance.common.util.protobuf.ProtoEditor import me.rhunk.snapenhance.common.util.protobuf.ProtoReader import me.rhunk.snapenhance.common.util.protobuf.ProtoWriter @@ -50,7 +51,7 @@ class EndToEndEncryption : MessagingRuleFeature( MessagingRuleType.E2E_ENCRYPTION, loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC or FeatureLoadParams.INIT_SYNC or FeatureLoadParams.INIT_ASYNC ) { - private val isEnabled get() = context.config.experimental.e2eEncryption.globalState == true + val isEnabled get() = context.config.experimental.e2eEncryption.globalState == true private val e2eeInterface by lazy { context.bridgeClient.getE2eeInterface() } companion object { @@ -268,7 +269,19 @@ class EndToEndEncryption : MessagingRuleFeature( }.digest() } - fun tryDecryptMessage(senderId: String, clientMessageId: Long, conversationId: String, contentType: ContentType, messageBuffer: ByteArray): Pair<ContentType, ByteArray> { + fun decryptDatabaseMessage(conversationMessage: ConversationMessage): ProtoReader { + return tryDecryptMessage( + senderId = conversationMessage.senderId!!, + clientMessageId = conversationMessage.clientMessageId.toLong(), + conversationId = conversationMessage.clientConversationId!!, + contentType = ContentType.fromId(conversationMessage.contentType), + messageBuffer = ProtoReader(conversationMessage.messageContent!!).getByteArray(4, 4)!! + ).let { (_, buffer) -> + ProtoReader(buffer) + } + } + + private fun tryDecryptMessage(senderId: String, clientMessageId: Long, conversationId: String, contentType: ContentType, messageBuffer: ByteArray): Pair<ContentType, ByteArray> { if (contentType != ContentType.STATUS && decryptedMessageCache.containsKey(clientMessageId)) { return decryptedMessageCache[clientMessageId]!! } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/FriendFeedMessagePreview.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/FriendFeedMessagePreview.kt @@ -50,16 +50,8 @@ class FriendFeedMessagePreview : Feature("FriendFeedMessagePreview", loadParams val messageContainer = message.messageContent ?.let { ProtoReader(it) } - ?.followPath(4, 4)?.let { messageReader -> - takeIf { hasE2EE }?.let takeIf@{ - endToEndEncryption.tryDecryptMessage( - senderId = message.senderId ?: return@takeIf null, - clientMessageId = message.clientMessageId.toLong(), - conversationId = message.clientConversationId ?: return@takeIf null, - contentType = ContentType.fromId(message.contentType), - messageBuffer = messageReader.getBuffer() - ).second - }?.let { ProtoReader(it) } ?: messageReader + ?.followPath(4, 4)?.let { + if (hasE2EE) endToEndEncryption.decryptDatabaseMessage(message) else it } ?: return@mapNotNull null diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/impl/FriendFeedInfoMenu.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/impl/FriendFeedInfoMenu.kt @@ -29,6 +29,7 @@ import me.rhunk.snapenhance.common.scripting.ui.ScriptInterface import me.rhunk.snapenhance.common.ui.createComposeView import me.rhunk.snapenhance.common.util.protobuf.ProtoReader import me.rhunk.snapenhance.common.util.snap.BitmojiSelfie +import me.rhunk.snapenhance.core.features.impl.experiments.EndToEndEncryption import me.rhunk.snapenhance.core.features.impl.messaging.Messaging import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper @@ -159,6 +160,7 @@ class FriendFeedInfoMenu : AbstractMenu() { private fun showPreview(userId: String?, conversationId: String) { //query message val messageLogger = context.feature(MessageLogger::class) + val endToEndEncryption = context.feature(EndToEndEncryption::class) val messages: List<ConversationMessage> = context.database.getMessagesFromConversationId( conversationId, context.config.messaging.messagePreviewLength.get() @@ -174,11 +176,12 @@ class FriendFeedInfoMenu : AbstractMenu() { messages.forEach { message -> val sender = participants[message.senderId] val messageProtoReader = - messageLogger.takeIf { - it.isEnabled && message.contentType == ContentType.STATUS.id // only process deleted messages - }?.getMessageProto(conversationId, message.clientMessageId.toLong()) - ?: ProtoReader(message.messageContent ?: return@forEach).followPath(4, 4) - ?: return@forEach + ( + messageLogger.takeIf { it.isEnabled && message.contentType == ContentType.STATUS.id }?.getMessageProto(conversationId, message.clientMessageId.toLong()) // process deleted messages if message logger is enabled + ?: ProtoReader(message.messageContent!!).followPath(4, 4) // database message + )?.let { + if (endToEndEncryption.isEnabled) endToEndEncryption.decryptDatabaseMessage(message) else it // try to decrypt message if e2ee is enabled + } ?: return@forEach val contentType = ContentType.fromMessageContainer(messageProtoReader) ?: ContentType.fromId(message.contentType) var messageString = if (contentType == ContentType.CHAT) {