mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-13 05:37:48 +02:00
pref: database and e2ee
- fix ff preview for e2e messages
This commit is contained in:
@ -27,6 +27,7 @@ import me.rhunk.snapenhance.core.features.Feature
|
|||||||
import me.rhunk.snapenhance.core.logger.CoreLogger
|
import me.rhunk.snapenhance.core.logger.CoreLogger
|
||||||
import me.rhunk.snapenhance.core.manager.impl.ActionManager
|
import me.rhunk.snapenhance.core.manager.impl.ActionManager
|
||||||
import me.rhunk.snapenhance.core.manager.impl.FeatureManager
|
import me.rhunk.snapenhance.core.manager.impl.FeatureManager
|
||||||
|
import me.rhunk.snapenhance.core.messaging.CoreMessagingBridge
|
||||||
import me.rhunk.snapenhance.core.messaging.MessageSender
|
import me.rhunk.snapenhance.core.messaging.MessageSender
|
||||||
import me.rhunk.snapenhance.core.scripting.CoreScriptRuntime
|
import me.rhunk.snapenhance.core.scripting.CoreScriptRuntime
|
||||||
import me.rhunk.snapenhance.core.util.media.HttpServer
|
import me.rhunk.snapenhance.core.util.media.HttpServer
|
||||||
@ -61,6 +62,7 @@ class ModContext {
|
|||||||
val eventDispatcher = EventDispatcher(this)
|
val eventDispatcher = EventDispatcher(this)
|
||||||
val native = NativeLib()
|
val native = NativeLib()
|
||||||
val scriptRuntime by lazy { CoreScriptRuntime(androidContext, log) }
|
val scriptRuntime by lazy { CoreScriptRuntime(androidContext, log) }
|
||||||
|
val messagingBridge = CoreMessagingBridge(this)
|
||||||
|
|
||||||
val isDeveloper by lazy { config.scripting.developerMode.get() }
|
val isDeveloper by lazy { config.scripting.developerMode.get() }
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ import me.rhunk.snapenhance.core.bridge.loadFromBridge
|
|||||||
import me.rhunk.snapenhance.core.data.SnapClassCache
|
import me.rhunk.snapenhance.core.data.SnapClassCache
|
||||||
import me.rhunk.snapenhance.core.event.events.impl.SnapWidgetBroadcastReceiveEvent
|
import me.rhunk.snapenhance.core.event.events.impl.SnapWidgetBroadcastReceiveEvent
|
||||||
import me.rhunk.snapenhance.core.event.events.impl.UnaryCallEvent
|
import me.rhunk.snapenhance.core.event.events.impl.UnaryCallEvent
|
||||||
import me.rhunk.snapenhance.core.messaging.CoreMessagingBridge
|
|
||||||
import me.rhunk.snapenhance.core.util.LSPatchUpdater
|
import me.rhunk.snapenhance.core.util.LSPatchUpdater
|
||||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
import me.rhunk.snapenhance.core.util.hook.hook
|
import me.rhunk.snapenhance.core.util.hook.hook
|
||||||
@ -117,7 +116,7 @@ class SnapEnhance {
|
|||||||
logCritical(null, throwable)
|
logCritical(null, throwable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bridgeClient.registerMessagingBridge(CoreMessagingBridge(this))
|
bridgeClient.registerMessagingBridge(messagingBridge)
|
||||||
|
|
||||||
reloadConfig()
|
reloadConfig()
|
||||||
actionManager.init()
|
actionManager.init()
|
||||||
|
@ -26,6 +26,10 @@ class DatabaseAccess(private val context: ModContext) : Manager {
|
|||||||
context.androidContext.getDatabasePath("main.db")
|
context.androidContext.getDatabasePath("main.db")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val dmOtherParticipantCache by lazy {
|
||||||
|
getAllDMOtherParticipants().toMutableMap()
|
||||||
|
}
|
||||||
|
|
||||||
private fun openMain(): SQLiteDatabase {
|
private fun openMain(): SQLiteDatabase {
|
||||||
return SQLiteDatabase.openDatabase(
|
return SQLiteDatabase.openDatabase(
|
||||||
mainDatabase.absolutePath,
|
mainDatabase.absolutePath,
|
||||||
@ -95,7 +99,7 @@ class DatabaseAccess(private val context: ModContext) : Manager {
|
|||||||
val myUserId by lazy {
|
val myUserId by lazy {
|
||||||
safeDatabaseOperation(openArroyo()) { arroyoDatabase: SQLiteDatabase ->
|
safeDatabaseOperation(openArroyo()) { arroyoDatabase: SQLiteDatabase ->
|
||||||
arroyoDatabase.rawQuery(buildString {
|
arroyoDatabase.rawQuery(buildString {
|
||||||
append("SELECT * FROM required_values WHERE key = 'USERID'")
|
append("SELECT value FROM required_values WHERE key = 'USERID'")
|
||||||
}, null).use { query ->
|
}, null).use { query ->
|
||||||
if (!query.moveToFirst()) {
|
if (!query.moveToFirst()) {
|
||||||
return@safeDatabaseOperation null
|
return@safeDatabaseOperation null
|
||||||
@ -163,7 +167,7 @@ class DatabaseAccess(private val context: ModContext) : Manager {
|
|||||||
fun getConversationType(conversationId: String): Int? {
|
fun getConversationType(conversationId: String): Int? {
|
||||||
return safeDatabaseOperation(openArroyo()) { database ->
|
return safeDatabaseOperation(openArroyo()) { database ->
|
||||||
database.rawQuery(
|
database.rawQuery(
|
||||||
"SELECT * FROM user_conversation WHERE client_conversation_id = ?",
|
"SELECT conversation_type FROM user_conversation WHERE client_conversation_id = ?",
|
||||||
arrayOf(conversationId)
|
arrayOf(conversationId)
|
||||||
).use { query ->
|
).use { query ->
|
||||||
if (!query.moveToFirst()) {
|
if (!query.moveToFirst()) {
|
||||||
@ -186,10 +190,30 @@ class DatabaseAccess(private val context: ModContext) : Manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getAllDMOtherParticipants(): Map<String, String?> {
|
||||||
|
return safeDatabaseOperation(openArroyo()) { arroyoDatabase: SQLiteDatabase ->
|
||||||
|
arroyoDatabase.rawQuery(
|
||||||
|
"SELECT client_conversation_id, user_id FROM user_conversation WHERE conversation_type = 0",
|
||||||
|
null
|
||||||
|
).use { query ->
|
||||||
|
val participants = mutableMapOf<String, String>()
|
||||||
|
if (!query.moveToFirst()) {
|
||||||
|
return@safeDatabaseOperation null
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
participants[query.getString(query.getColumnIndex("client_conversation_id"))] =
|
||||||
|
query.getString(query.getColumnIndex("user_id"))
|
||||||
|
} while (query.moveToNext())
|
||||||
|
participants
|
||||||
|
}
|
||||||
|
} ?: emptyMap()
|
||||||
|
}
|
||||||
|
|
||||||
fun getDMOtherParticipant(conversationId: String): String? {
|
fun getDMOtherParticipant(conversationId: String): String? {
|
||||||
|
if (dmOtherParticipantCache.containsKey(conversationId)) return dmOtherParticipantCache[conversationId]
|
||||||
return safeDatabaseOperation(openArroyo()) { cursor ->
|
return safeDatabaseOperation(openArroyo()) { cursor ->
|
||||||
cursor.rawQuery(
|
cursor.rawQuery(
|
||||||
"SELECT * FROM user_conversation WHERE client_conversation_id = ? AND conversation_type = 0",
|
"SELECT user_id FROM user_conversation WHERE client_conversation_id = ? AND conversation_type = 0",
|
||||||
arrayOf(conversationId)
|
arrayOf(conversationId)
|
||||||
).use { query ->
|
).use { query ->
|
||||||
val participants = mutableListOf<String>()
|
val participants = mutableListOf<String>()
|
||||||
@ -201,7 +225,7 @@ class DatabaseAccess(private val context: ModContext) : Manager {
|
|||||||
} while (query.moveToNext())
|
} while (query.moveToNext())
|
||||||
participants.firstOrNull { it != myUserId }
|
participants.firstOrNull { it != myUserId }
|
||||||
}
|
}
|
||||||
}
|
}.also { dmOtherParticipantCache[conversationId] = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -214,7 +238,7 @@ class DatabaseAccess(private val context: ModContext) : Manager {
|
|||||||
fun getConversationParticipants(conversationId: String): List<String>? {
|
fun getConversationParticipants(conversationId: String): List<String>? {
|
||||||
return safeDatabaseOperation(openArroyo()) { arroyoDatabase: SQLiteDatabase ->
|
return safeDatabaseOperation(openArroyo()) { arroyoDatabase: SQLiteDatabase ->
|
||||||
arroyoDatabase.rawQuery(
|
arroyoDatabase.rawQuery(
|
||||||
"SELECT * FROM user_conversation WHERE client_conversation_id = ?",
|
"SELECT user_id FROM user_conversation WHERE client_conversation_id = ?",
|
||||||
arrayOf(conversationId)
|
arrayOf(conversationId)
|
||||||
).use {
|
).use {
|
||||||
if (!it.moveToFirst()) {
|
if (!it.moveToFirst()) {
|
||||||
|
@ -12,6 +12,7 @@ import android.view.ViewGroup.MarginLayoutParams
|
|||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import me.rhunk.snapenhance.common.data.ContentType
|
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.MessagingRuleType
|
||||||
import me.rhunk.snapenhance.common.data.RuleState
|
import me.rhunk.snapenhance.common.data.RuleState
|
||||||
import me.rhunk.snapenhance.common.util.protobuf.ProtoEditor
|
import me.rhunk.snapenhance.common.util.protobuf.ProtoEditor
|
||||||
@ -268,25 +269,26 @@ class EndToEndEncryption : MessagingRuleFeature(
|
|||||||
}.digest()
|
}.digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun messageHook(conversationId: String, messageId: Long, senderId: String, messageContent: MessageContent) {
|
fun tryDecryptMessage(senderId: String, clientMessageId: Long, conversationId: String, contentType: ContentType, messageBuffer: ByteArray): Pair<ContentType, ByteArray> {
|
||||||
if (messageContent.contentType != ContentType.STATUS && decryptedMessageCache.containsKey(messageId)) {
|
if (contentType != ContentType.STATUS && decryptedMessageCache.containsKey(clientMessageId)) {
|
||||||
val (contentType, buffer) = decryptedMessageCache[messageId]!!
|
return decryptedMessageCache[clientMessageId]!!
|
||||||
messageContent.contentType = contentType
|
|
||||||
messageContent.content = buffer
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val reader = ProtoReader(messageContent.content)
|
val reader = ProtoReader(messageBuffer)
|
||||||
messageContent.contentType = fixContentType(messageContent.contentType!!, reader)
|
var outputBuffer = messageBuffer
|
||||||
|
var outputContentType = fixContentType(contentType, reader) ?: contentType
|
||||||
|
val conversationParticipants by lazy {
|
||||||
|
getE2EParticipants(conversationId)
|
||||||
|
}
|
||||||
|
|
||||||
fun setMessageContent(buffer: ByteArray) {
|
fun setMessageContent(buffer: ByteArray) {
|
||||||
messageContent.content = buffer
|
outputBuffer = buffer
|
||||||
messageContent.contentType = fixContentType(messageContent.contentType, ProtoReader(buffer))
|
outputContentType = fixContentType(outputContentType, ProtoReader(buffer)) ?: outputContentType
|
||||||
decryptedMessageCache[messageId] = messageContent.contentType!! to buffer
|
decryptedMessageCache[clientMessageId] = outputContentType to buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replaceMessageText(text: String) {
|
fun replaceMessageText(text: String) {
|
||||||
messageContent.content = ProtoWriter().apply {
|
outputBuffer = ProtoWriter().apply {
|
||||||
from(2) {
|
from(2) {
|
||||||
addString(1, text)
|
addString(1, text)
|
||||||
}
|
}
|
||||||
@ -297,9 +299,6 @@ class EndToEndEncryption : MessagingRuleFeature(
|
|||||||
reader.followPath(2, 1) {
|
reader.followPath(2, 1) {
|
||||||
val messageTypeId = getVarInt(1)?.toInt() ?: return@followPath
|
val messageTypeId = getVarInt(1)?.toInt() ?: return@followPath
|
||||||
val isMe = context.database.myUserId == senderId
|
val isMe = context.database.myUserId == senderId
|
||||||
val conversationParticipants by lazy {
|
|
||||||
getE2EParticipants(conversationId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageTypeId == ENCRYPTED_MESSAGE_ID) {
|
if (messageTypeId == ENCRYPTED_MESSAGE_ID) {
|
||||||
runCatching {
|
runCatching {
|
||||||
@ -314,7 +313,7 @@ class EndToEndEncryption : MessagingRuleFeature(
|
|||||||
setMessageContent(
|
setMessageContent(
|
||||||
e2eeInterface.decryptMessage(participantId, ciphertext, iv)
|
e2eeInterface.decryptMessage(participantId, ciphertext, iv)
|
||||||
)
|
)
|
||||||
encryptedMessages.add(messageId)
|
encryptedMessages.add(clientMessageId)
|
||||||
return@eachBuffer
|
return@eachBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,14 +322,14 @@ class EndToEndEncryption : MessagingRuleFeature(
|
|||||||
setMessageContent(
|
setMessageContent(
|
||||||
e2eeInterface.decryptMessage(senderId, ciphertext, iv)
|
e2eeInterface.decryptMessage(senderId, ciphertext, iv)
|
||||||
)
|
)
|
||||||
encryptedMessages.add(messageId)
|
encryptedMessages.add(clientMessageId)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
context.log.error("Failed to decrypt message id: $messageId", it)
|
context.log.error("Failed to decrypt message id: $clientMessageId", it)
|
||||||
messageContent.contentType = ContentType.CHAT
|
outputContentType = ContentType.CHAT
|
||||||
messageContent.content = ProtoWriter().apply {
|
outputBuffer = ProtoWriter().apply {
|
||||||
from(2) {
|
from(2) {
|
||||||
addString(1, "Failed to decrypt message, id=$messageId. Check logcat for more details.")
|
addString(1, "Failed to decrypt message, id=$clientMessageId. Check logcat for more details.")
|
||||||
}
|
}
|
||||||
}.toByteArray()
|
}.toByteArray()
|
||||||
}
|
}
|
||||||
@ -354,15 +353,23 @@ class EndToEndEncryption : MessagingRuleFeature(
|
|||||||
|
|
||||||
when (messageTypeId) {
|
when (messageTypeId) {
|
||||||
REQUEST_PK_MESSAGE_ID -> {
|
REQUEST_PK_MESSAGE_ID -> {
|
||||||
pkRequests[messageId] = payload
|
pkRequests[clientMessageId] = payload
|
||||||
replaceMessageText("You just received a public key request. Click below to accept it.")
|
replaceMessageText("You just received a public key request. Click below to accept it.")
|
||||||
}
|
}
|
||||||
RESPONSE_SK_MESSAGE_ID -> {
|
RESPONSE_SK_MESSAGE_ID -> {
|
||||||
secretResponses[messageId] = payload
|
secretResponses[clientMessageId] = payload
|
||||||
replaceMessageText("Your friend just accepted your public key. Click below to accept the secret.")
|
replaceMessageText("Your friend just accepted your public key. Click below to accept the secret.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return outputContentType to outputBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun messageHook(conversationId: String, messageId: Long, senderId: String, messageContent: MessageContent) {
|
||||||
|
val (contentType, buffer) = tryDecryptMessage(senderId, messageId, conversationId, messageContent.contentType ?: ContentType.CHAT, messageContent.content)
|
||||||
|
messageContent.contentType = contentType
|
||||||
|
messageContent.content = buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun asyncInit() {
|
override fun asyncInit() {
|
||||||
@ -474,6 +481,7 @@ class EndToEndEncryption : MessagingRuleFeature(
|
|||||||
|
|
||||||
context.event.subscribe(BuildMessageEvent::class, priority = 0) { event ->
|
context.event.subscribe(BuildMessageEvent::class, priority = 0) { event ->
|
||||||
val message = event.message
|
val message = event.message
|
||||||
|
if (message.messageState != MessageState.COMMITTED) return@subscribe
|
||||||
val conversationId = message.messageDescriptor.conversationId.toString()
|
val conversationId = message.messageDescriptor.conversationId.toString()
|
||||||
messageHook(
|
messageHook(
|
||||||
conversationId = conversationId,
|
conversationId = conversationId,
|
||||||
|
@ -15,8 +15,10 @@ import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
|
|||||||
import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent
|
import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent
|
||||||
import me.rhunk.snapenhance.core.features.Feature
|
import me.rhunk.snapenhance.core.features.Feature
|
||||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||||
|
import me.rhunk.snapenhance.core.features.impl.experiments.EndToEndEncryption
|
||||||
import me.rhunk.snapenhance.core.ui.addForegroundDrawable
|
import me.rhunk.snapenhance.core.ui.addForegroundDrawable
|
||||||
import me.rhunk.snapenhance.core.ui.removeForegroundDrawable
|
import me.rhunk.snapenhance.core.ui.removeForegroundDrawable
|
||||||
|
import me.rhunk.snapenhance.core.util.EvictingMap
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@SuppressLint("DiscouragedApi")
|
@SuppressLint("DiscouragedApi")
|
||||||
@ -27,12 +29,17 @@ class FriendFeedMessagePreview : Feature("FriendFeedMessagePreview", loadParams
|
|||||||
).getColor(0, 0)
|
).getColor(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val friendNameCache = EvictingMap<String, String>(100)
|
||||||
|
|
||||||
private fun getDimens(name: String) = context.resources.getDimensionPixelSize(context.resources.getIdentifier(name, "dimen", Constants.SNAPCHAT_PACKAGE_NAME))
|
private fun getDimens(name: String) = context.resources.getDimensionPixelSize(context.resources.getIdentifier(name, "dimen", Constants.SNAPCHAT_PACKAGE_NAME))
|
||||||
|
|
||||||
override fun onActivityCreate() {
|
override fun onActivityCreate() {
|
||||||
val setting = context.config.userInterface.friendFeedMessagePreview
|
val setting = context.config.userInterface.friendFeedMessagePreview
|
||||||
if (setting.globalState != true) return
|
if (setting.globalState != true) return
|
||||||
|
|
||||||
|
val hasE2EE = context.config.experimental.e2eEncryption.globalState == true
|
||||||
|
val endToEndEncryption by lazy { context.feature(EndToEndEncryption::class) }
|
||||||
|
|
||||||
val ffItemId = context.resources.getIdentifier("ff_item", "id", Constants.SNAPCHAT_PACKAGE_NAME)
|
val ffItemId = context.resources.getIdentifier("ff_item", "id", Constants.SNAPCHAT_PACKAGE_NAME)
|
||||||
|
|
||||||
val secondaryTextSize = getDimens("ff_feed_cell_secondary_text_size").toFloat()
|
val secondaryTextSize = getDimens("ff_feed_cell_secondary_text_size").toFloat()
|
||||||
@ -58,17 +65,29 @@ class FriendFeedMessagePreview : Feature("FriendFeedMessagePreview", loadParams
|
|||||||
frameLayout.removeForegroundDrawable("ffItem")
|
frameLayout.removeForegroundDrawable("ffItem")
|
||||||
|
|
||||||
val stringMessages = context.database.getMessagesFromConversationId(conversationId, setting.amount.get().absoluteValue)?.mapNotNull { message ->
|
val stringMessages = context.database.getMessagesFromConversationId(conversationId, setting.amount.get().absoluteValue)?.mapNotNull { message ->
|
||||||
val messageContainer = message.messageContent
|
val messageContainer =
|
||||||
?.let { ProtoReader(it) }
|
message.messageContent
|
||||||
?.followPath(4, 4)
|
?.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
|
||||||
|
}
|
||||||
?: return@mapNotNull null
|
?: return@mapNotNull null
|
||||||
|
|
||||||
val messageString = messageContainer.getString(2, 1)
|
val messageString = messageContainer.getString(2, 1)
|
||||||
?: ContentType.fromMessageContainer(messageContainer)?.name
|
?: ContentType.fromMessageContainer(messageContainer)?.name
|
||||||
?: return@mapNotNull null
|
?: return@mapNotNull null
|
||||||
|
|
||||||
val friendName = context.database.getFriendInfo(message.senderId ?: return@mapNotNull null)?.let { it.displayName?: it.mutableUsername } ?: "Unknown"
|
val friendName = friendNameCache.getOrPut(message.senderId ?: return@mapNotNull null) {
|
||||||
|
context.database.getFriendInfo(message.senderId ?: return@mapNotNull null)?.let { it.displayName?: it.mutableUsername } ?: "Unknown"
|
||||||
|
}
|
||||||
"$friendName: $messageString"
|
"$friendName: $messageString"
|
||||||
}?.reversed() ?: return@friendFeedItem
|
}?.reversed() ?: return@friendFeedItem
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class CoreMessagingBridge(
|
|||||||
val callback = CallbackBuilder(
|
val callback = CallbackBuilder(
|
||||||
context.mappings.getMappedClass("callbacks", "FetchMessageCallback")
|
context.mappings.getMappedClass("callbacks", "FetchMessageCallback")
|
||||||
).override("onFetchMessageComplete") { param ->
|
).override("onFetchMessageComplete") { param ->
|
||||||
val message = me.rhunk.snapenhance.core.wrapper.impl.Message(param.arg(1)).toBridge()
|
val message = me.rhunk.snapenhance.core.wrapper.impl.Message(param.arg(0)).toBridge()
|
||||||
continuation.resumeWith(Result.success(message))
|
continuation.resumeWith(Result.success(message))
|
||||||
}
|
}
|
||||||
.override("onServerRequest", shouldUnhook = false) {}
|
.override("onServerRequest", shouldUnhook = false) {}
|
||||||
@ -47,7 +47,7 @@ class CoreMessagingBridge(
|
|||||||
context.classCache.conversationManager.methods.first { it.name == "fetchMessage" }.invoke(
|
context.classCache.conversationManager.methods.first { it.name == "fetchMessage" }.invoke(
|
||||||
conversationManager,
|
conversationManager,
|
||||||
SnapUUID.fromString(conversationId).instanceNonNull(),
|
SnapUUID.fromString(conversationId).instanceNonNull(),
|
||||||
clientMessageId,
|
clientMessageId.toLong(),
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user