mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-07 01:51:27 +01:00
feat(TikTok): Add Sanitize sharing links patch (#6176)
This commit is contained in:
@@ -17,9 +17,6 @@ public class LinkSanitizer {
|
|||||||
|
|
||||||
public LinkSanitizer(String ... parametersToRemove) {
|
public LinkSanitizer(String ... parametersToRemove) {
|
||||||
final int parameterCount = parametersToRemove.length;
|
final int parameterCount = parametersToRemove.length;
|
||||||
if (parameterCount == 0) {
|
|
||||||
throw new IllegalArgumentException("No parameters specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
// List is faster if only checking a few parameters.
|
// List is faster if only checking a few parameters.
|
||||||
this.parametersToRemove = parameterCount > 4
|
this.parametersToRemove = parameterCount > 4
|
||||||
@@ -40,10 +37,12 @@ public class LinkSanitizer {
|
|||||||
try {
|
try {
|
||||||
Uri.Builder builder = uri.buildUpon().clearQuery();
|
Uri.Builder builder = uri.buildUpon().clearQuery();
|
||||||
|
|
||||||
for (String paramName : uri.getQueryParameterNames()) {
|
if (!parametersToRemove.isEmpty()) {
|
||||||
if (!parametersToRemove.contains(paramName)) {
|
for (String paramName : uri.getQueryParameterNames()) {
|
||||||
for (String value : uri.getQueryParameters(paramName)) {
|
if (!parametersToRemove.contains(paramName)) {
|
||||||
builder.appendQueryParameter(paramName, value);
|
for (String value : uri.getQueryParameters(paramName)) {
|
||||||
|
builder.appendQueryParameter(paramName, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
|||||||
public void addPreferences(Context context) {
|
public void addPreferences(Context context) {
|
||||||
addPreference(new ReVancedTikTokAboutPreference(context));
|
addPreference(new ReVancedTikTokAboutPreference(context));
|
||||||
|
|
||||||
|
addPreference(new TogglePreference(context,
|
||||||
|
"Sanitize sharing links",
|
||||||
|
"Remove tracking parameters from shared links.",
|
||||||
|
BaseSettings.SANITIZE_SHARED_LINKS
|
||||||
|
));
|
||||||
|
|
||||||
addPreference(new TogglePreference(context,
|
addPreference(new TogglePreference(context,
|
||||||
"Enable debug log",
|
"Enable debug log",
|
||||||
"Show extension debug log.",
|
"Show extension debug log.",
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package app.revanced.extension.tiktok.share;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class ShareUrlSanitizer {
|
||||||
|
|
||||||
|
private static final LinkSanitizer sanitizer = new LinkSanitizer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point for setting check.
|
||||||
|
*/
|
||||||
|
public static boolean shouldSanitize() {
|
||||||
|
return BaseSettings.SANITIZE_SHARED_LINKS.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point for URL sanitization.
|
||||||
|
*/
|
||||||
|
public static String sanitizeShareUrl(final String url) {
|
||||||
|
if (url == null || url.isEmpty()) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sanitizer.sanitizeUrlString(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1188,6 +1188,10 @@ public final class app/revanced/patches/tiktok/misc/settings/SettingsPatchKt {
|
|||||||
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatchKt {
|
||||||
|
public static final fun getSanitizeShareUrlsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatchKt {
|
public final class app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatchKt {
|
||||||
public static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package app.revanced.patches.tiktok.misc.share
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal val urlShorteningFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL)
|
||||||
|
returns("LX/")
|
||||||
|
parameters(
|
||||||
|
"I",
|
||||||
|
"Ljava/lang/String;",
|
||||||
|
"Ljava/lang/String;",
|
||||||
|
"Ljava/lang/String;"
|
||||||
|
)
|
||||||
|
opcodes(Opcode.RETURN_OBJECT)
|
||||||
|
|
||||||
|
// Same Kotlin intrinsics literal on both variants.
|
||||||
|
strings("getShortShareUrlObservab\u2026ongUrl, subBizSceneValue)")
|
||||||
|
|
||||||
|
custom { method, _ ->
|
||||||
|
// LIZLLL is obfuscated by ProGuard/R8, but stable across both TikTok and Musically.
|
||||||
|
method.name == "LIZLLL"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package app.revanced.patches.tiktok.misc.share
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
|
||||||
|
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
|
||||||
|
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.util.findFreeRegister
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/tiktok/share/ShareUrlSanitizer;"
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val sanitizeShareUrlsPatch = bytecodePatch(
|
||||||
|
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
|
||||||
|
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
|
||||||
|
) {
|
||||||
|
dependsOn(sharedExtensionPatch)
|
||||||
|
|
||||||
|
compatibleWith(
|
||||||
|
"com.ss.android.ugc.trill"("36.5.4"),
|
||||||
|
"com.zhiliaoapp.musically"("36.5.4"),
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
urlShorteningFingerprint.method.apply {
|
||||||
|
val invokeIndex = indexOfFirstInstructionOrThrow {
|
||||||
|
val ref = getReference<MethodReference>()
|
||||||
|
ref?.name == "LIZ" && ref.definingClass.startsWith("LX/")
|
||||||
|
}
|
||||||
|
|
||||||
|
val moveResultIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||||
|
val urlRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
|
||||||
|
|
||||||
|
// Resolve Observable wrapper classes at runtime
|
||||||
|
val observableWrapperIndex = indexOfFirstInstructionOrThrow(Opcode.NEW_INSTANCE)
|
||||||
|
val observableWrapperClass = getInstruction<ReferenceInstruction>(observableWrapperIndex)
|
||||||
|
.reference.toString()
|
||||||
|
|
||||||
|
val observableFactoryIndex = indexOfFirstInstructionOrThrow {
|
||||||
|
val ref = getReference<MethodReference>()
|
||||||
|
ref?.name == "LJ" && ref.definingClass.startsWith("LX/")
|
||||||
|
}
|
||||||
|
val observableFactoryRef = getInstruction<ReferenceInstruction>(observableFactoryIndex)
|
||||||
|
.reference as MethodReference
|
||||||
|
|
||||||
|
val observableFactoryClass = observableFactoryRef.definingClass
|
||||||
|
val observableInterfaceType = observableFactoryRef.parameterTypes.first()
|
||||||
|
val observableReturnType = observableFactoryRef.returnType
|
||||||
|
|
||||||
|
val wrapperRegister = findFreeRegister(moveResultIndex + 1, urlRegister)
|
||||||
|
|
||||||
|
// Check setting and conditionally sanitize share URL.
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
moveResultIndex + 1,
|
||||||
|
"""
|
||||||
|
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldSanitize()Z
|
||||||
|
move-result v$wrapperRegister
|
||||||
|
if-eqz v$wrapperRegister, :skip_sanitization
|
||||||
|
|
||||||
|
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeShareUrl(Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v$urlRegister
|
||||||
|
|
||||||
|
# Wrap sanitized URL and return early to bypass ShareExtService
|
||||||
|
new-instance v$wrapperRegister, $observableWrapperClass
|
||||||
|
invoke-direct { v$wrapperRegister, v$urlRegister }, $observableWrapperClass-><init>(Ljava/lang/String;)V
|
||||||
|
invoke-static { v$wrapperRegister }, $observableFactoryClass->LJ($observableInterfaceType)$observableReturnType
|
||||||
|
move-result-object v$urlRegister
|
||||||
|
return-object v$urlRegister
|
||||||
|
|
||||||
|
:skip_sanitization
|
||||||
|
nop
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user