feat(core): stealth mode save snap in chat
Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
@@ -9,11 +9,17 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import me.rhunk.snapenhance.common.data.ContentType
|
||||
import me.rhunk.snapenhance.common.data.MessageUpdate
|
||||
import me.rhunk.snapenhance.core.event.events.impl.OnSnapInteractionEvent
|
||||
import me.rhunk.snapenhance.core.event.events.impl.SendMessageWithContentEvent
|
||||
import me.rhunk.snapenhance.core.features.Feature
|
||||
import me.rhunk.snapenhance.core.features.impl.spying.StealthMode
|
||||
import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper
|
||||
import me.rhunk.snapenhance.core.util.CallbackBuilder
|
||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||
import me.rhunk.snapenhance.core.util.hook.hook
|
||||
import me.rhunk.snapenhance.core.util.ktx.getObjectFieldOrNull
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID
|
||||
import me.rhunk.snapenhance.mapper.impl.CallbackMapper
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.random.Random
|
||||
@@ -82,6 +88,52 @@ class AutoMarkAsRead : Feature("Auto Mark As Read") {
|
||||
val config by context.config.messaging.autoMarkAsRead
|
||||
if (config.isEmpty()) return
|
||||
|
||||
if (config.contains("save_snap_in_chat")) {
|
||||
var lastInteractedSnapClientMessageId = -1L
|
||||
|
||||
context.event.subscribe(OnSnapInteractionEvent::class) { event ->
|
||||
lastInteractedSnapClientMessageId = event.messageId
|
||||
}
|
||||
|
||||
context.classCache.conversationManager.hook("updateMessage", HookStage.BEFORE) { param ->
|
||||
if (param.arg<Any>(2).toString() != "SAVE") return@hook
|
||||
|
||||
val clientMessageId = param.arg<Long>(1)
|
||||
if (lastInteractedSnapClientMessageId != clientMessageId) return@hook
|
||||
|
||||
val conversationId = SnapUUID(param.arg(0))
|
||||
|
||||
param.setResult(null)
|
||||
|
||||
val snapManager = context.feature(Messaging::class).snapManager ?: return@hook
|
||||
val stealthMode = context.feature(StealthMode::class)
|
||||
|
||||
// ignore non-stealth mode conversations
|
||||
if (!stealthMode.canUseRule(conversationId.toString())) return@hook
|
||||
|
||||
stealthMode.addSnapInteractionException(clientMessageId)
|
||||
|
||||
val onSnapInteraction = snapManager.javaClass.methods.firstOrNull { it.name == "onSnapInteraction" } ?: return@hook
|
||||
|
||||
context.mappings.useMapper(CallbackMapper::class) {
|
||||
onSnapInteraction.invoke(snapManager,
|
||||
findClass("com.snapchat.client.messaging.SnapInteractionType").enumConstants!!.first { it.toString() == "VIEWING_INITIATED" },
|
||||
conversationId.instanceNonNull(),
|
||||
clientMessageId,
|
||||
CallbackBuilder(callbacks.getClass("SnapInteractionCallback")!!)
|
||||
.override("onSuccess") {
|
||||
param.invokeOriginal()
|
||||
stealthMode.addSnapInteractionException(clientMessageId)
|
||||
}
|
||||
.override("onError") {
|
||||
context.log.verbose("error ${it.arg<Any>(0)}")
|
||||
}
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.event.subscribe(SendMessageWithContentEvent::class) { event ->
|
||||
event.addCallbackResult("onSuccess") {
|
||||
if (canMarkConversationAsRead) {
|
||||
|
||||
@@ -14,11 +14,7 @@ import me.rhunk.snapenhance.core.util.hook.hook
|
||||
import me.rhunk.snapenhance.core.util.hook.hookConstructor
|
||||
import me.rhunk.snapenhance.core.util.ktx.getObjectField
|
||||
import me.rhunk.snapenhance.core.util.ktx.getObjectFieldOrNull
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.ConversationManager
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.Message
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.Snapchatter
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.toSnapUUID
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.*
|
||||
import me.rhunk.snapenhance.mapper.impl.CallbackMapper
|
||||
import me.rhunk.snapenhance.mapper.impl.FriendsFeedEventDispatcherMapper
|
||||
import java.util.UUID
|
||||
@@ -27,6 +23,9 @@ import java.util.concurrent.Future
|
||||
class Messaging : Feature("Messaging") {
|
||||
var conversationManager: ConversationManager? = null
|
||||
private set
|
||||
var snapManager: Any? = null
|
||||
private set
|
||||
|
||||
private var conversationManagerDelegate: Any? = null
|
||||
private var identityDelegate: Any? = null
|
||||
|
||||
@@ -69,6 +68,10 @@ class Messaging : Feature("Messaging") {
|
||||
}
|
||||
}
|
||||
|
||||
context.classCache.snapManager.hookConstructor(HookStage.BEFORE) { param ->
|
||||
snapManager = param.thisObject()
|
||||
}
|
||||
|
||||
context.mappings.useMapper(CallbackMapper::class) {
|
||||
callbacks.getClass("ConversationManagerDelegate")?.apply {
|
||||
hookConstructor(HookStage.AFTER) { param ->
|
||||
|
||||
@@ -10,15 +10,19 @@ import java.util.concurrent.CopyOnWriteArraySet
|
||||
|
||||
class StealthMode : MessagingRuleFeature("StealthMode", MessagingRuleType.STEALTH) {
|
||||
private val displayedMessageQueue = CopyOnWriteArraySet<Long>()
|
||||
private val snapInteractionQueue = CopyOnWriteArraySet<Long>()
|
||||
|
||||
fun addDisplayedMessageException(clientMessageId: Long) {
|
||||
displayedMessageQueue.add(clientMessageId)
|
||||
}
|
||||
|
||||
fun addSnapInteractionException(messageId: Long) {
|
||||
snapInteractionQueue.add(messageId)
|
||||
}
|
||||
|
||||
|
||||
override fun init() {
|
||||
val isConversationInStealthMode: (SnapUUID) -> Boolean = hook@{
|
||||
context.feature(StealthMode::class).canUseRule(it.toString())
|
||||
}
|
||||
val isConversationInStealthMode: (SnapUUID) -> Boolean = { canUseRule(it.toString()) }
|
||||
|
||||
arrayOf("mediaMessagesDisplayed", "displayedMessages").forEach { methodName: String ->
|
||||
context.classCache.conversationManager.hook(methodName, HookStage.BEFORE) { param ->
|
||||
@@ -30,6 +34,7 @@ class StealthMode : MessagingRuleFeature("StealthMode", MessagingRuleType.STEALT
|
||||
}
|
||||
|
||||
context.event.subscribe(OnSnapInteractionEvent::class) { event ->
|
||||
if (snapInteractionQueue.removeIf { event.messageId == it }) return@subscribe
|
||||
if (isConversationInStealthMode(event.conversationId)) {
|
||||
event.canceled = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user