commit dded6acff08dc925213bb7ab80a172d52da462e6
parent c791fbbd005f1ec1acece35a6434ae3695d58290
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Thu, 31 Aug 2023 15:42:24 +0200

feat: add friend source spoof

Diffstat:
Mcore/src/main/assets/lang/en_US.json | 11+++++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/bridge/wrapper/MappingsWrapper.kt | 4+++-
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Experimental.kt | 7+++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/database/DatabaseAccess.kt | 3+++
Mcore/src/main/kotlin/me/rhunk/snapenhance/features/Feature.kt | 2+-
Acore/src/main/kotlin/me/rhunk/snapenhance/features/impl/experiments/AddFriendSourceSpoof.kt | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/manager/impl/FeatureManager.kt | 6++++--
Amapper/src/main/kotlin/me/rhunk/snapmapper/impl/FriendRelationshipChangerMapper.kt | 28++++++++++++++++++++++++++++
Mmapper/src/test/kotlin/me/rhunk/snapenhance/mapper/tests/TestMappings.kt | 1+
9 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/core/src/main/assets/lang/en_US.json b/core/src/main/assets/lang/en_US.json @@ -366,6 +366,10 @@ "no_friend_score_delay": { "name": "No Friend Score Delay", "description": "Removes the delay when viewing a friends score" + }, + "add_friend_source_spoof": { + "name": "Add Friend Source Spoof", + "description": "Spoofs the source of a friend request" } } } @@ -461,6 +465,13 @@ "ngs_community_icon_container": "Community / Stories", "ngs_spotlight_icon_container": "Spotlight", "ngs_search_icon_container": "Search" + }, + "add_friend_source_spoof": { + "added_by_username": "By Username", + "added_by_mention": "By Mention", + "added_by_group_chat": "By Group Chat", + "added_by_qr_code": "By QR Code", + "added_by_community": "By Community" } } }, diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/bridge/wrapper/MappingsWrapper.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/bridge/wrapper/MappingsWrapper.kt @@ -14,6 +14,7 @@ import me.rhunk.snapmapper.impl.CallbackMapper import me.rhunk.snapmapper.impl.CompositeConfigurationProviderMapper import me.rhunk.snapmapper.impl.DefaultMediaItemMapper import me.rhunk.snapmapper.impl.EnumMapper +import me.rhunk.snapmapper.impl.FriendRelationshipChangerMapper import me.rhunk.snapmapper.impl.FriendsFeedEventDispatcherMapper import me.rhunk.snapmapper.impl.MediaQualityLevelProviderMapper import me.rhunk.snapmapper.impl.OperaPageViewControllerMapper @@ -41,7 +42,8 @@ class MappingsWrapper : FileLoaderWrapper(BridgeFileType.MAPPINGS, "{}".toByteAr StoryBoostStateMapper::class, FriendsFeedEventDispatcherMapper::class, CompositeConfigurationProviderMapper::class, - ScoreUpdateMapper::class + ScoreUpdateMapper::class, + FriendRelationshipChangerMapper::class, ) } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Experimental.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Experimental.kt @@ -12,4 +12,11 @@ class Experimental : ConfigContainer() { val meoPasscodeBypass = boolean("meo_passcode_bypass") val unlimitedMultiSnap = boolean("unlimited_multi_snap") { addNotices(FeatureNotice.MAY_BAN)} val noFriendScoreDelay = boolean("no_friend_score_delay") + val addFriendSourceSpoof = unique("add_friend_source_spoof", + "added_by_username", + "added_by_mention", + "added_by_group_chat", + "added_by_qr_code", + "added_by_community", + ) { addNotices(FeatureNotice.MAY_BAN) } } \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/database/DatabaseAccess.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/database/DatabaseAccess.kt @@ -49,6 +49,9 @@ class DatabaseAccess(private val context: ModContext) : Manager { query: (SQLiteDatabase) -> T? ): T? { synchronized(databaseLock) { + if (!database.isOpen) { + return null + } return runCatching { query(database) }.onFailure { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/features/Feature.kt b/core/src/main/kotlin/me/rhunk/snapenhance/features/Feature.kt @@ -3,7 +3,7 @@ package me.rhunk.snapenhance.features import me.rhunk.snapenhance.ModContext abstract class Feature( - val nameKey: String, + val featureKey: String, val loadParams: Int = FeatureLoadParams.INIT_SYNC ) { lateinit var context: ModContext diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/experiments/AddFriendSourceSpoof.kt b/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/experiments/AddFriendSourceSpoof.kt @@ -0,0 +1,55 @@ +package me.rhunk.snapenhance.features.impl.experiments + +import me.rhunk.snapenhance.features.Feature +import me.rhunk.snapenhance.features.FeatureLoadParams +import me.rhunk.snapenhance.hook.HookStage +import me.rhunk.snapenhance.hook.hook + +class AddFriendSourceSpoof : Feature("AddFriendSourceSpoof", loadParams = FeatureLoadParams.ACTIVITY_CREATE_ASYNC) { + override fun asyncOnActivityCreate() { + val friendRelationshipChangerMapping = context.mappings.getMappedMap("FriendRelationshipChanger") + + findClass(friendRelationshipChangerMapping["class"].toString()) + .hook(friendRelationshipChangerMapping["addFriendMethod"].toString(), HookStage.BEFORE) { param -> + val spoofedSource = context.config.experimental.addFriendSourceSpoof.getNullable() ?: return@hook + + context.log.verbose("addFriendMethod: ${param.args().toList()}", featureKey) + + fun setEnum(index: Int, value: String) { + val enumData = param.arg<Any>(index) + enumData::class.java.enumConstants.first { it.toString() == value }.let { + param.setArg(index, it) + } + } + + when (spoofedSource) { + "added_by_group_chat" -> { + setEnum(1, "PROFILE") + setEnum(2, "GROUP_PROFILE") + setEnum(3, "ADDED_BY_GROUP_CHAT") + } + "added_by_username" -> { + setEnum(1, "SEARCH") + setEnum(2, "SEARCH") + setEnum(3, "ADDED_BY_USERNAME") + } + "added_by_qr_code" -> { + setEnum(1, "PROFILE") + setEnum(2, "PROFILE") + setEnum(3, "ADDED_BY_QR_CODE") + } + "added_by_mention" -> { + setEnum(1, "CONTEXT_CARDS") + setEnum(2, "CONTEXT_CARD") + setEnum(3, "ADDED_BY_MENTION") + } + "added_by_community" -> { + setEnum(1, "PROFILE") + setEnum(2, "PROFILE") + setEnum(3, "ADDED_BY_COMMUNITY") + } + else -> return@hook + } + } + } +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/manager/impl/FeatureManager.kt b/core/src/main/kotlin/me/rhunk/snapenhance/manager/impl/FeatureManager.kt @@ -9,6 +9,7 @@ import me.rhunk.snapenhance.features.impl.ConfigurationOverride import me.rhunk.snapenhance.features.impl.Messaging import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader import me.rhunk.snapenhance.features.impl.downloader.ProfilePictureDownloader +import me.rhunk.snapenhance.features.impl.experiments.AddFriendSourceSpoof import me.rhunk.snapenhance.features.impl.experiments.AmoledDarkMode import me.rhunk.snapenhance.features.impl.experiments.AppPasscode import me.rhunk.snapenhance.features.impl.experiments.DeviceSpooferHook @@ -93,6 +94,7 @@ class FeatureManager(private val context: ModContext) : Manager { register(GooglePlayServicesDialogs::class) register(NoFriendScoreDelay::class) register(ProfilePictureDownloader::class) + register(AddFriendSourceSpoof::class) initializeFeatures() } @@ -103,8 +105,8 @@ class FeatureManager(private val context: ModContext) : Manager { runCatching { action(feature) }.onFailure { - Logger.xposedLog("Failed to init feature ${feature.nameKey}", it) - context.longToast("Failed to init feature ${feature.nameKey}") + context.log.error("Failed to init feature ${feature.featureKey}", it) + context.longToast("Failed to load feature ${feature.featureKey}! Check logcat for more details.") } } if (!isAsync) { diff --git a/mapper/src/main/kotlin/me/rhunk/snapmapper/impl/FriendRelationshipChangerMapper.kt b/mapper/src/main/kotlin/me/rhunk/snapmapper/impl/FriendRelationshipChangerMapper.kt @@ -0,0 +1,27 @@ +package me.rhunk.snapmapper.impl + +import me.rhunk.snapmapper.AbstractClassMapper +import me.rhunk.snapmapper.MapperContext +import me.rhunk.snapmapper.ext.findConstString +import me.rhunk.snapmapper.ext.getClassName +import me.rhunk.snapmapper.ext.isEnum + +class FriendRelationshipChangerMapper : AbstractClassMapper() { + override fun run(context: MapperContext) { + for (classDef in context.classes) { + classDef.methods.firstOrNull { it.name == "<init>" }?.implementation?.findConstString("FriendRelationshipChangerImpl")?.takeIf { it } ?: continue + val addFriendMethod = classDef.methods.first { + it.parameterTypes.size > 4 && + context.getClass(it.parameterTypes[1])?.isEnum() == true && + context.getClass(it.parameterTypes[2])?.isEnum() == true && + context.getClass(it.parameterTypes[3])?.isEnum() == true && + it.parameters[4].type == "Ljava/lang/String;" + } + + context.addMapping("FriendRelationshipChanger", + "class" to classDef.getClassName(), + "addFriendMethod" to addFriendMethod.name + ) + } + } +}+ \ No newline at end of file diff --git a/mapper/src/test/kotlin/me/rhunk/snapenhance/mapper/tests/TestMappings.kt b/mapper/src/test/kotlin/me/rhunk/snapenhance/mapper/tests/TestMappings.kt @@ -24,6 +24,7 @@ class TestMappings { FriendsFeedEventDispatcherMapper::class, CompositeConfigurationProviderMapper::class, ScoreUpdateMapper::class, + FriendRelationshipChangerMapper::class, ) val gson = GsonBuilder().setPrettyPrinting().create()