From af0217594d9c7526f550fc7e6f09f8a9232e72cf Mon Sep 17 00:00:00 2001 From: xehpuk Date: Mon, 25 Sep 2023 16:29:06 +0200 Subject: [PATCH] feat(Strava): Add `Disable subscription suggestions` patch (#2997) Co-authored-by: oSumAtrIX --- .../subscription/UnlockSubscriptionPatch.kt | 4 +- .../fingerprints/GetSubscribedFingerprint.kt | 2 +- .../DisableSubscriptionSuggestionsPatch.kt | 72 +++++++++++++++++++ .../fingerprints/GetModulesFingerprint.kt | 11 +++ 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/strava/upselling/fingerprints/GetModulesFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt b/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt index 1c16dfc53..965077ff9 100644 --- a/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt @@ -10,7 +10,7 @@ import app.revanced.patches.strava.subscription.fingerprints.GetSubscribedFinger @Patch( name = "Unlock subscription features", - description = "Unlocks \"Matched Runs\" and \"Segment Efforts\".", + description = "Unlocks \"Routes\", \"Matched Runs\" and \"Segment Efforts\".", compatiblePackages = [CompatiblePackage("com.strava", ["320.12"])] ) @Suppress("unused") @@ -19,4 +19,4 @@ object UnlockSubscriptionPatch : BytecodePatch(setOf(GetSubscribedFingerprint)) val isSubscribedIndex = result.scanResult.patternScanResult!!.startIndex result.mutableMethod.replaceInstruction(isSubscribedIndex, "const/4 v0, 0x1") } ?: throw GetSubscribedFingerprint.exception -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/strava/subscription/fingerprints/GetSubscribedFingerprint.kt b/src/main/kotlin/app/revanced/patches/strava/subscription/fingerprints/GetSubscribedFingerprint.kt index a0f6ff393..c9cf6f921 100644 --- a/src/main/kotlin/app/revanced/patches/strava/subscription/fingerprints/GetSubscribedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/strava/subscription/fingerprints/GetSubscribedFingerprint.kt @@ -6,6 +6,6 @@ import com.android.tools.smali.dexlib2.Opcode object GetSubscribedFingerprint : MethodFingerprint( opcodes = listOf(Opcode.IGET_BOOLEAN), customFingerprint = { methodDef, classDef -> - classDef.type.endsWith("SubscriptionDetailResponse;") && methodDef.name == "getSubscribed" + classDef.type.endsWith("/SubscriptionDetailResponse;") && methodDef.name == "getSubscribed" } ) diff --git a/src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt b/src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt new file mode 100644 index 000000000..22e50c854 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt @@ -0,0 +1,72 @@ +package app.revanced.patches.strava.upselling + +import app.revanced.extensions.exception +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.strava.upselling.fingerprints.GetModulesFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation +import com.android.tools.smali.dexlib2.immutable.ImmutableMethod + +@Patch( + name = "Disable subscription suggestions", + compatiblePackages = [CompatiblePackage("com.strava", ["320.12"])] +) +@Suppress("unused") +object DisableSubscriptionSuggestionsPatch : BytecodePatch( + setOf(GetModulesFingerprint) +) { + private const val HELPER_METHOD_NAME = "getModulesIfNotUpselling" + private const val PAGE_SUFFIX = "_upsell" + private const val LABEL = "original" + + override fun execute(context: BytecodeContext) = GetModulesFingerprint.result?.let { result -> + val className = result.classDef.type + val originalMethod = result.mutableMethod + val returnType = originalMethod.returnType + + result.mutableClass.methods.add(ImmutableMethod( + className, + HELPER_METHOD_NAME, + emptyList(), + returnType, + AccessFlags.PRIVATE.value, + null, + null, + MutableMethodImplementation(3) + ).toMutable().apply { + addInstructions( + """ + iget-object v0, p0, $className->page:Ljava/lang/String; + const-string v1, "$PAGE_SUFFIX" + invoke-virtual {v0, v1}, Ljava/lang/String;->endsWith(Ljava/lang/String;)Z + move-result v0 + if-eqz v0, :$LABEL + invoke-static {}, Ljava/util/Collections;->emptyList()Ljava/util/List; + move-result-object v0 + return-object v0 + :$LABEL + iget-object v0, p0, $className->modules:Ljava/util/List; + return-object v0 + """ + ) + }) + + val getModulesIndex = result.scanResult.patternScanResult!!.startIndex + with(originalMethod) { + removeInstruction(getModulesIndex) + addInstructions( + getModulesIndex, + """ + invoke-direct {p0}, $className->$HELPER_METHOD_NAME()$returnType + move-result-object v0 + """ + ) + } + } ?: throw GetModulesFingerprint.exception +} diff --git a/src/main/kotlin/app/revanced/patches/strava/upselling/fingerprints/GetModulesFingerprint.kt b/src/main/kotlin/app/revanced/patches/strava/upselling/fingerprints/GetModulesFingerprint.kt new file mode 100644 index 000000000..a343d62f8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/strava/upselling/fingerprints/GetModulesFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.strava.upselling.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +object GetModulesFingerprint : MethodFingerprint( + opcodes = listOf(Opcode.IGET_OBJECT), + customFingerprint = { methodDef, classDef -> + classDef.type.endsWith("/GenericLayoutEntry;") && methodDef.name == "getModules" + } +)