feat: add friend source spoof

This commit is contained in:
rhunk 2023-08-31 15:42:24 +02:00
parent c791fbbd00
commit dded6acff0
9 changed files with 112 additions and 4 deletions

View File

@ -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"
}
}
},

View File

@ -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,
)
}

View File

@ -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) }
}

View File

@ -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 {

View File

@ -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

View File

@ -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
}
}
}
}

View File

@ -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) {

View File

@ -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
)
}
}
}

View File

@ -24,6 +24,7 @@ class TestMappings {
FriendsFeedEventDispatcherMapper::class,
CompositeConfigurationProviderMapper::class,
ScoreUpdateMapper::class,
FriendRelationshipChangerMapper::class,
)
val gson = GsonBuilder().setPrettyPrinting().create()