feat(experiments): disable composer modules
This commit is contained in:
@@ -622,6 +622,10 @@
|
||||
"hidden_snapchat_plus_features": {
|
||||
"name": "Hidden Snapchat Plus Features",
|
||||
"description": "Enables unreleased/beta Snapchat Plus features\nMight not work on older Snapchat versions"
|
||||
},
|
||||
"disable_composer_modules": {
|
||||
"name": "Disable Composer Modules",
|
||||
"description": "Prevents selected composer modules from being loaded\nNames must be separated by a comma"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -30,4 +30,5 @@ class Experimental : ConfigContainer() {
|
||||
"added_by_qr_code",
|
||||
"added_by_community",
|
||||
) { addNotices(FeatureNotice.BAN_RISK) }
|
||||
val disableComposerModules = string("disable_composer_modules") { requireRestart(); nativeHooks() }
|
||||
}
|
||||
@@ -149,7 +149,8 @@ class ModContext(
|
||||
native.loadNativeConfig(
|
||||
NativeConfig(
|
||||
disableBitmoji = config.experimental.nativeHooks.disableBitmoji.get(),
|
||||
disableMetrics = config.global.disableMetrics.get()
|
||||
disableMetrics = config.global.disableMetrics.get(),
|
||||
hookAssetOpen = config.experimental.disableComposerModules.get().isNotEmpty()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.rhunk.snapenhance.core.features.impl.experiments
|
||||
|
||||
import me.rhunk.snapenhance.core.features.Feature
|
||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||
|
||||
class DisableComposerModules : Feature("Disable Composer Modules", FeatureLoadParams.INIT_SYNC) {
|
||||
override fun init() {
|
||||
val disabledComposerModules = context.config.experimental.disableComposerModules.get().takeIf { it.isNotEmpty() }
|
||||
?.replace(" ", "")
|
||||
?.split(",")
|
||||
?: return
|
||||
|
||||
context.native.nativeShouldLoadAsset = callback@{ assetName ->
|
||||
if (!assetName.endsWith(".composermodule")) return@callback true
|
||||
val moduleName = assetName.replace(".composermodule", "")
|
||||
disabledComposerModules.contains(moduleName).not().also {
|
||||
if (it) context.log.debug("Loading $moduleName composer module")
|
||||
else context.log.warn("Skipping $moduleName composer module")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,7 @@ class FeatureManager(
|
||||
HalfSwipeNotifier::class,
|
||||
DisableConfirmationDialogs::class,
|
||||
Stories::class,
|
||||
DisableComposerModules::class,
|
||||
)
|
||||
|
||||
initializeFeatures()
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
typedef struct {
|
||||
bool disable_bitmoji;
|
||||
bool disable_metrics;
|
||||
bool hook_asset_open;
|
||||
} native_config_t;
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <string>
|
||||
#include <dobby.h>
|
||||
#include <vector>
|
||||
#include <android/asset_manager.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "config.h"
|
||||
@@ -16,9 +17,14 @@
|
||||
|
||||
static native_config_t *native_config;
|
||||
static JavaVM *java_vm;
|
||||
static jobject native_lib_object;
|
||||
static jmethodID native_lib_on_unary_call_method;
|
||||
static jmethodID native_lib_on_asset_load;
|
||||
|
||||
// original functions
|
||||
static void *(*unaryCall_original)(void *, const char *, grpc::grpc_byte_buffer **, void *, void *, void *);
|
||||
static auto fstat_original = (int (*)(int, struct stat *)) nullptr;
|
||||
static AAsset* (*AAssetManager_open_original)(AAssetManager*, const char*, int) = nullptr;
|
||||
|
||||
static int fstat_hook(int fd, struct stat *buf) {
|
||||
char name[256];
|
||||
@@ -40,7 +46,6 @@ static int fstat_hook(int fd, struct stat *buf) {
|
||||
return fstat_original(fd, buf);
|
||||
}
|
||||
|
||||
static jobject native_lib_object;
|
||||
|
||||
static void *unaryCall_hook(void *unk1, const char *uri, grpc::grpc_byte_buffer **buffer_ptr, void *unk4, void *unk5, void *unk6) {
|
||||
// request without reference counter can be hooked using xposed ig
|
||||
@@ -91,6 +96,19 @@ static void *unaryCall_hook(void *unk1, const char *uri, grpc::grpc_byte_buffer
|
||||
return unaryCall_original(unk1, uri, buffer_ptr, unk4, unk5, unk6);
|
||||
}
|
||||
|
||||
static AAsset* AAssetManager_open_hook(AAssetManager* mgr, const char* filename, int mode) {
|
||||
if (native_config->hook_asset_open) {
|
||||
JNIEnv *env = nullptr;
|
||||
java_vm->GetEnv((void **)&env, JNI_VERSION_1_6);
|
||||
|
||||
if (!env->CallBooleanMethod(native_lib_object, native_lib_on_asset_load, env->NewStringUTF(filename))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return AAssetManager_open_original(mgr, filename, mode);
|
||||
}
|
||||
|
||||
void JNICALL init(JNIEnv *env, jobject clazz, jobject classloader) {
|
||||
LOGD("Initializing native");
|
||||
// config
|
||||
@@ -99,6 +117,7 @@ void JNICALL init(JNIEnv *env, jobject clazz, jobject classloader) {
|
||||
// native lib object
|
||||
native_lib_object = env->NewGlobalRef(clazz);
|
||||
native_lib_on_unary_call_method = env->GetMethodID(env->GetObjectClass(clazz), "onNativeUnaryCall", "(Ljava/lang/String;[B)L" BUILD_NAMESPACE "/NativeRequestData;");
|
||||
native_lib_on_asset_load = env->GetMethodID(env->GetObjectClass(clazz), "shouldLoadAsset", "(Ljava/lang/String;)Z");
|
||||
|
||||
// load libclient.so
|
||||
util::load_library(env, classloader, "client");
|
||||
@@ -128,6 +147,7 @@ void JNICALL init(JNIEnv *env, jobject clazz, jobject classloader) {
|
||||
LOGE("can't find unaryCall signature");
|
||||
}
|
||||
|
||||
DobbyHook((void *) AAssetManager_open, (void *) AAssetManager_open_hook, (void **) &AAssetManager_open_original);
|
||||
LOGD("Native initialized");
|
||||
}
|
||||
|
||||
@@ -137,6 +157,7 @@ void JNICALL load_config(JNIEnv *env, jobject _, jobject config_object) {
|
||||
|
||||
native_config->disable_bitmoji = GET_CONFIG_BOOL("disableBitmoji");
|
||||
native_config->disable_metrics = GET_CONFIG_BOOL("disableMetrics");
|
||||
native_config->hook_asset_open = GET_CONFIG_BOOL("hookAssetOpen");
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *_) {
|
||||
|
||||
@@ -2,5 +2,6 @@ package me.rhunk.snapenhance.nativelib
|
||||
|
||||
data class NativeConfig(
|
||||
val disableBitmoji: Boolean = false,
|
||||
val disableMetrics: Boolean = false
|
||||
val disableMetrics: Boolean = false,
|
||||
val hookAssetOpen: Boolean = false,
|
||||
)
|
||||
@@ -4,6 +4,8 @@ import android.util.Log
|
||||
|
||||
class NativeLib {
|
||||
var nativeUnaryCallCallback: (NativeRequestData) -> Unit = {}
|
||||
var nativeShouldLoadAsset: (String) -> Boolean = { true }
|
||||
|
||||
companion object {
|
||||
var initialized = false
|
||||
private set
|
||||
@@ -33,6 +35,11 @@ class NativeLib {
|
||||
return null
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private fun shouldLoadAsset(name: String) = runCatching {
|
||||
nativeShouldLoadAsset(name)
|
||||
}.getOrNull() ?: true
|
||||
|
||||
fun loadNativeConfig(config: NativeConfig) {
|
||||
if (!initialized) return
|
||||
loadConfig(config)
|
||||
|
||||
Reference in New Issue
Block a user