diff --git a/src/main/kotlin/app/revanced/patches/shared/fingerprints/tracking/CopyTextEndpointFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/tracking/CopyTextEndpointFingerprint.kt new file mode 100644 index 000000000..7e54120aa --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/fingerprints/tracking/CopyTextEndpointFingerprint.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.shared.fingerprints.tracking + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +/** + * Copy URL from sharing panel + */ +object CopyTextEndpointFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L", "Ljava/util/Map;"), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.CONST_STRING, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.RETURN_VOID + ), + strings = listOf("text/plain") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/patch/tracking/AbstractSanitizeUrlQueryPatch.kt b/src/main/kotlin/app/revanced/patches/shared/patch/tracking/AbstractSanitizeUrlQueryPatch.kt new file mode 100644 index 000000000..8fe5ebdde --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/patch/tracking/AbstractSanitizeUrlQueryPatch.kt @@ -0,0 +1,40 @@ +package app.revanced.patches.shared.patch.tracking + +import app.revanced.extensions.exception +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction + +abstract class AbstractSanitizeUrlQueryPatch( + private val descriptor: String, + private val sharedFingerprints: List, + private val additionalFingerprints: List? = null +) : BytecodePatch( + buildSet { + addAll(sharedFingerprints) + additionalFingerprints?.let(::addAll) + } +) { + private fun MethodFingerprint.invoke() { + result?.let { + it.mutableMethod.apply { + val targetIndex = it.scanResult.patternScanResult!!.startIndex + val targetRegister = getInstruction(targetIndex).registerA + + addInstructions( + targetIndex + 2, """ + invoke-static {v$targetRegister}, $descriptor->stripQueryParameters(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$targetRegister + """ + ) + } + } ?: throw exception + } + override fun execute(context: BytecodeContext) { + for (fingerprint in sharedFingerprints) + fingerprint.invoke() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/SanitizeUrlQueryPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/SanitizeUrlQueryPatch.kt new file mode 100644 index 000000000..5359c66a5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/SanitizeUrlQueryPatch.kt @@ -0,0 +1,100 @@ +package app.revanced.patches.youtube.misc.tracking + +import app.revanced.extensions.exception +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.shared.fingerprints.tracking.CopyTextEndpointFingerprint +import app.revanced.patches.shared.patch.tracking.AbstractSanitizeUrlQueryPatch +import app.revanced.patches.youtube.misc.tracking.fingerprints.ShareLinkFormatterFingerprint +import app.revanced.patches.youtube.misc.tracking.fingerprints.SystemShareLinkFormatterFingerprint +import app.revanced.patches.youtube.utils.settings.SettingsPatch +import app.revanced.util.integrations.Constants.MISC_PATH +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction + +@Patch( + name = "Sanitize sharing links", + description = "Removes tracking query parameters from the URLs when sharing links.", + dependencies = [SettingsPatch::class], + compatiblePackages = [ + CompatiblePackage( + "com.google.android.youtube", + [ + "18.25.40", + "18.27.36", + "18.29.38", + "18.30.37", + "18.31.40", + "18.32.39", + "18.33.40", + "18.34.38", + "18.35.36", + "18.36.39", + "18.37.36", + "18.38.44", + "18.39.41", + "18.40.34" + ] + ) + ] +) +@Suppress("unused") +object SanitizeUrlQueryPatch : AbstractSanitizeUrlQueryPatch( + "$MISC_PATH/SanitizeUrlQueryPatch;", + listOf(CopyTextEndpointFingerprint), + listOf( + ShareLinkFormatterFingerprint, + SystemShareLinkFormatterFingerprint + ) +) { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "$MISC_PATH/SanitizeUrlQueryPatch;" + + override fun execute(context: BytecodeContext) { + super.execute(context) + + arrayOf( + ShareLinkFormatterFingerprint, + SystemShareLinkFormatterFingerprint + ).forEach { fingerprint -> + fingerprint.result?.let { + it.mutableMethod.apply { + for ((index, instruction) in implementation!!.instructions.withIndex()) { + if (instruction.opcode != Opcode.INVOKE_VIRTUAL) + continue + + if ((instruction as ReferenceInstruction).reference.toString() != "Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;") + continue + + if (getInstruction(index + 1).opcode != Opcode.GOTO) + continue + + val invokeInstruction = instruction as FiveRegisterInstruction + + replaceInstruction( + index, + "invoke-static {v${invokeInstruction.registerC}, v${invokeInstruction.registerD}, v${invokeInstruction.registerE}}, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->stripQueryParameters(Landroid/content/Intent;Ljava/lang/String;Ljava/lang/String;)V" + ) + } + } + } ?: throw fingerprint.exception + } + + + /** + * Add settings + */ + SettingsPatch.addPreference( + arrayOf( + "SETTINGS: SANITIZE_SHARING_LINKS" + ) + ) + + SettingsPatch.updatePatchStatus("Sanitize sharing links") + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/fingerprints/ShareLinkFormatterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/fingerprints/ShareLinkFormatterFingerprint.kt new file mode 100644 index 000000000..f3dd4a53c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/fingerprints/ShareLinkFormatterFingerprint.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.youtube.misc.tracking.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference + +/** + * Sharing panel of YouTube + * + * This fingerprint is quite complex to be compatible with all versions from YouTube v18.25.40 to the latest version. + * If you drop supporting the old version, please change the fingerprint to be more intuitive. + */ +object ShareLinkFormatterFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.GOTO, + Opcode.MOVE_OBJECT, + Opcode.INVOKE_VIRTUAL + ), + customFingerprint = custom@{ methodDef, _ -> + if (methodDef.implementation == null) + return@custom false + + var count = 0 + for (instruction in methodDef.implementation!!.instructions) { + if (instruction.opcode != Opcode.SGET_OBJECT) + continue + + val objectInstruction = instruction as ReferenceInstruction + if ((objectInstruction.reference as FieldReference).name != "androidAppEndpoint") + continue + + count++ + } + count == 2 + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/fingerprints/SystemShareLinkFormatterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/fingerprints/SystemShareLinkFormatterFingerprint.kt new file mode 100644 index 000000000..cb68c5964 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/tracking/fingerprints/SystemShareLinkFormatterFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.misc.tracking.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +/** + * Sharing panel of System + */ +object SystemShareLinkFormatterFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L", "Ljava/util/Map;"), + strings = listOf("YTShare_Logging_Share_Intent_Endpoint_Byte_Array") +) \ No newline at end of file diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml index 482342f54..dd99dec31 100644 --- a/src/main/resources/youtube/settings/host/values/strings.xml +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -653,6 +653,8 @@ Tap and hold to set playback speed to 1.0x." Show dislikes on Shorts Hidden + Removes tracking query parameters from the URLs when sharing links. + Sanitize sharing links Changing default speed to: Changing default mobile data quality to: Failed to set quality. diff --git a/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 3414ad825..c16973627 100644 --- a/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -300,6 +300,9 @@ PREFERENCE: MICROG_SETTINGS --> + + @@ -394,6 +397,7 @@ +