feat: disable hold to replay in FF

- add setEnumField ktx
- refactor AbstractWrapper delegate (nullable getValue)
This commit is contained in:
rhunk
2023-09-01 16:01:21 +02:00
parent 89a1552277
commit d0e6c55717
11 changed files with 52 additions and 12 deletions

View File

@ -233,6 +233,10 @@
"name": "Unlimited Snap View Time",
"description": "Removes the time limit for viewing Snaps"
},
"disable_replay_in_ff": {
"name": "Disable Replay in FF",
"description": "Disables the ability to replay with a long press from the friend feed"
},
"prevent_message_sending": {
"name": "Prevent Message Sending",
"description": "Prevents sending certain types of messages"

View File

@ -35,13 +35,15 @@ class EventDispatcher(
}
context.classCache.snapManager.hook("onSnapInteraction", HookStage.BEFORE) { param ->
val interactionType = param.arg<Any>(0).toString()
val conversationId = SnapUUID(param.arg(1))
val messageId = param.arg<Long>(2)
context.event.post(
OnSnapInteractionEvent(
conversationId = conversationId,
messageId = messageId
)
interactionType = interactionType,
conversationId = conversationId,
messageId = messageId
)
)?.also {
if (it.canceled) {
param.setResult(null)

View File

@ -9,6 +9,7 @@ class MessagingTweaks : ConfigContainer() {
val hideBitmojiPresence = boolean("hide_bitmoji_presence")
val hideTypingNotifications = boolean("hide_typing_notifications")
val unlimitedSnapViewTime = boolean("unlimited_snap_view_time")
val disableReplayInFF = boolean("disable_replay_in_ff")
val autoSaveMessagesInConversations = multiple("auto_save_messages_in_conversations",
"CHAT",
"SNAP",

View File

@ -4,6 +4,7 @@ import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
class OnSnapInteractionEvent(
val interactionType: String,
val conversationId: SnapUUID,
val messageId: Long
) : AbstractHookEvent()

View File

@ -9,8 +9,8 @@ abstract class AbstractWrapper(
) {
@Suppress("UNCHECKED_CAST")
inner class EnumAccessor<T>(private val fieldName: String, private val defaultValue: T) {
operator fun getValue(obj: Any, property: KProperty<*>): T = getEnumValue(fieldName, defaultValue as Enum<*>) as T
operator fun setValue(obj: Any, property: KProperty<*>, value: Any) = setEnumValue(fieldName, value as Enum<*>)
operator fun getValue(obj: Any, property: KProperty<*>): T? = getEnumValue(fieldName, defaultValue as Enum<*>) as? T
operator fun setValue(obj: Any, property: KProperty<*>, value: Any?) = setEnumValue(fieldName, value as Enum<*>)
}
companion object {
@ -32,9 +32,10 @@ abstract class AbstractWrapper(
protected fun <T> enum(fieldName: String, defaultValue: T) = EnumAccessor(fieldName, defaultValue)
fun <T : Enum<*>> getEnumValue(fieldName: String, defaultValue: T): T {
fun <T : Enum<*>> getEnumValue(fieldName: String, defaultValue: T?): T? {
if (defaultValue == null) return null
val mContentType = XposedHelpers.getObjectField(instance, fieldName) as Enum<*>
return java.lang.Enum.valueOf(defaultValue::class.java, mContentType.name) as T
return java.lang.Enum.valueOf(defaultValue::class.java, mContentType.name)
}
@Suppress("UNCHECKED_CAST")

View File

@ -24,7 +24,7 @@ class PreventMessageSending : Feature("Prevent message sending", loadParams = Fe
context.event.subscribe(SendMessageWithContentEvent::class) { event ->
val contentType = event.messageContent.contentType
val associatedType = NotificationType.fromContentType(contentType) ?: return@subscribe
val associatedType = NotificationType.fromContentType(contentType ?: return@subscribe) ?: return@subscribe
if (preventMessageSending.contains(associatedType.key)) {
context.log.verbose("Preventing message sending for $associatedType")

View File

@ -0,0 +1,22 @@
package me.rhunk.snapenhance.features.impl.tweaks
import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.hook.HookStage
import me.rhunk.snapenhance.hook.hookConstructor
import me.rhunk.snapenhance.util.ktx.getObjectField
import me.rhunk.snapenhance.util.ktx.setEnumField
class DisableReplayInFF : Feature("DisableReplayInFF", loadParams = FeatureLoadParams.ACTIVITY_CREATE_ASYNC) {
override fun asyncOnActivityCreate() {
val state by context.config.messaging.disableReplayInFF
findClass("com.snapchat.client.messaging.InteractionInfo")
.hookConstructor(HookStage.AFTER, { state }) { param ->
val instance = param.thisObject<Any>()
if (instance.getObjectField("mLongPressActionState").toString() == "REQUEST_SNAP_REPLAY") {
instance.setEnumField("mLongPressActionState", "SHOW_CONVERSATION_ACTION_MENU")
}
}
}
}

View File

@ -221,7 +221,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
}
}
val contentType = snapMessage.messageContent.contentType
val contentType = snapMessage.messageContent.contentType ?: return@onEach
val contentData = snapMessage.messageContent.content
val formatUsername: (String) -> String = { "$senderUsername: $it" }

View File

@ -25,6 +25,7 @@ import me.rhunk.snapenhance.features.impl.spying.PreventReadReceipts
import me.rhunk.snapenhance.features.impl.spying.StealthMode
import me.rhunk.snapenhance.features.impl.tweaks.AutoSave
import me.rhunk.snapenhance.features.impl.tweaks.CameraTweaks
import me.rhunk.snapenhance.features.impl.tweaks.DisableReplayInFF
import me.rhunk.snapenhance.features.impl.tweaks.DisableVideoLengthRestriction
import me.rhunk.snapenhance.features.impl.tweaks.GalleryMediaSendOverride
import me.rhunk.snapenhance.features.impl.tweaks.GooglePlayServicesDialogs
@ -95,6 +96,7 @@ class FeatureManager(private val context: ModContext) : Manager {
register(NoFriendScoreDelay::class)
register(ProfilePictureDownloader::class)
register(AddFriendSourceSpoof::class)
register(DisableReplayInFF::class)
initializeFeatures()
}

View File

@ -87,7 +87,7 @@ class MessageExporter(
val sender = conversationParticipants[message.senderId.toString()]
val senderUsername = sender?.usernameForSorting ?: message.senderId.toString()
val senderDisplayName = sender?.displayName ?: message.senderId.toString()
val messageContent = serializeMessageContent(message) ?: message.messageContent.contentType.name
val messageContent = serializeMessageContent(message) ?: message.messageContent.contentType?.name
val date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH).format(Date(message.messageMetadata.createdAt))
writer.write("[$date] - $senderDisplayName (${senderUsername}): $messageContent\n")
}
@ -118,7 +118,7 @@ class MessageExporter(
runCatching {
val downloadedMedia = MediaDownloaderHelper.downloadMediaFromReference(protoMediaReference) {
EncryptionHelper.decryptInputStream(it, message.messageContent.contentType, ProtoReader(message.messageContent.content), isArroyo = false)
EncryptionHelper.decryptInputStream(it, message.messageContent.contentType!!, ProtoReader(message.messageContent.content), isArroyo = false)
}
printLog("downloaded media ${message.orderKey}")
@ -276,7 +276,7 @@ class MessageExporter(
addProperty("serializedContent", serializeMessageContent(message))
addProperty("rawContent", Base64.getUrlEncoder().encodeToString(message.messageContent.content))
val messageContentType = message.messageContent.contentType
val messageContentType = message.messageContent.contentType ?: ContentType.CHAT
EncryptionHelper.getEncryptionKeys(messageContentType, ProtoReader(message.messageContent.content), isArroyo = false)?.let { encryptionKeyPair ->
add("encryption", JsonObject().apply encryption@{

View File

@ -6,6 +6,13 @@ fun Any.getObjectField(fieldName: String): Any? {
return XposedHelpers.getObjectField(this, fieldName)
}
fun Any.setEnumField(fieldName: String, value: String) {
this::class.java.getDeclaredField(fieldName)
.type.enumConstants?.firstOrNull { it.toString() == value }?.let { enum ->
setObjectField(fieldName, enum)
}
}
fun Any.setObjectField(fieldName: String, value: Any?) {
XposedHelpers.setObjectField(this, fieldName, value)
}