diff --git a/api/revanced-patches.api b/api/revanced-patches.api index e0a49a1e..5b4d8681 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -535,6 +535,18 @@ public final class app/revanced/patches/reddit/ad/general/HideAdsPatch : app/rev public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public abstract class app/revanced/patches/reddit/customclients/BaseFixSLinksPatch : app/revanced/patcher/patch/BytecodePatch { + public fun (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Ljava/util/Set;)V + public synthetic fun (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V + protected abstract fun getIntegrationsClassDescriptor ()Ljava/lang/String; + protected final fun getResolveSLinkMethod ()Ljava/lang/String; + protected final fun getSetAccessTokenMethod ()Ljava/lang/String; + protected abstract fun patchNavigationHandler (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;Lapp/revanced/patcher/data/BytecodeContext;)V + protected abstract fun patchSetAccessToken (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;Lapp/revanced/patcher/data/BytecodeContext;)V +} + public abstract class app/revanced/patches/reddit/customclients/BaseSpoofClientPatch : app/revanced/patcher/patch/BytecodePatch { public fun (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V public synthetic fun (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -570,6 +582,14 @@ public final class app/revanced/patches/reddit/customclients/boostforreddit/api/ public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } +public final class app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch : app/revanced/patches/reddit/customclients/BaseFixSLinksPatch { + public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch; +} + +public final class app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch { + public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch; +} + public final class app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V @@ -648,10 +668,12 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/detec public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patcher/patch/BytecodePatch { +public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patches/reddit/customclients/BaseFixSLinksPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch; - public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V - public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + +public final class app/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch { + public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch; } public final class app/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch : app/revanced/patcher/patch/BytecodePatch { diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/BaseFixSLinksPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/BaseFixSLinksPatch.kt new file mode 100644 index 00000000..bc7b4ee3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/BaseFixSLinksPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.reddit.customclients + +import app.revanced.patcher.PatchClass +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.fingerprint.MethodFingerprintResult +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.util.resultOrThrow + +abstract class BaseFixSLinksPatch( + private val handleNavigationFingerprint: MethodFingerprint, + private val setAccessTokenFingerprint: MethodFingerprint, + compatiblePackages: Set, + dependencies: Set = emptySet(), +) : BytecodePatch( + name = "Fix /s/ links", + fingerprints = setOf(handleNavigationFingerprint, setAccessTokenFingerprint), + compatiblePackages = compatiblePackages, + dependencies = dependencies, +) { + protected abstract val integrationsClassDescriptor: String + + protected val resolveSLinkMethod = + "patchResolveSLink(Ljava/lang/String;)Z" + + protected val setAccessTokenMethod = + "patchSetAccessToken(Ljava/lang/String;)V" + + override fun execute(context: BytecodeContext) { + handleNavigationFingerprint.resultOrThrow().patchNavigationHandler(context) + setAccessTokenFingerprint.resultOrThrow().patchSetAccessToken(context) + } + + /** + * Patch app's navigation handler to resolve /s/ links. + * + * @param context The current [BytecodeContext]. + * + */ + protected abstract fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext) + + /** + * Patch access token setup in app to resolve /s/ links with an access token + * in order to bypass API bans when making unauthorized requests. + * + * @param context The current [BytecodeContext]. + */ + protected abstract fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext) +} diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch.kt new file mode 100644 index 00000000..b651abde --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch.kt @@ -0,0 +1,44 @@ +package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.fingerprint.MethodFingerprintResult +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.reddit.customclients.BaseFixSLinksPatch +import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints.GetOAuthAccessTokenFingerprint +import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints.HandleNavigationFingerprint +import app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.IntegrationsPatch + +@Suppress("unused") +object FixSLinksPatch : BaseFixSLinksPatch( + handleNavigationFingerprint = HandleNavigationFingerprint, + setAccessTokenFingerprint = GetOAuthAccessTokenFingerprint, + compatiblePackages = setOf(CompatiblePackage("com.rubenmayayo.reddit")), + dependencies = setOf(IntegrationsPatch::class), +) { + override val integrationsClassDescriptor = "Lapp/revanced/integrations/boostforreddit/FixSLinksPatch;" + + override fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext) { + mutableMethod.apply { + val urlRegister = "p1" + val tempRegister = "v1" + addInstructionsWithLabels( + 0, + """ + invoke-static { $urlRegister }, $integrationsClassDescriptor->$resolveSLinkMethod + move-result $tempRegister + if-eqz $tempRegister, :continue + return $tempRegister + """, + ExternalLabel("continue", getInstruction(0)), + ) + } + } + + override fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext) = mutableMethod.addInstruction( + 3, + "invoke-static { v0 }, $integrationsClassDescriptor->$setAccessTokenMethod", + ) +} diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/fingerprints/GetOAuthAccessTokenFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/fingerprints/GetOAuthAccessTokenFingerprint.kt new file mode 100644 index 00000000..9a9103f6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/fingerprints/GetOAuthAccessTokenFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object GetOAuthAccessTokenFingerprint : MethodFingerprint( + strings = listOf("access_token"), + accessFlags = AccessFlags.PUBLIC.value, + returnType = "Ljava/lang/String", + customFingerprint = { _, classDef -> classDef.type == "Lnet/dean/jraw/http/oauth/OAuthData;" }, +) diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/fingerprints/HandleNavigationFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/fingerprints/HandleNavigationFingerprint.kt new file mode 100644 index 00000000..2a7120a6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/fingerprints/HandleNavigationFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object HandleNavigationFingerprint : MethodFingerprint( + strings = listOf( + "android.intent.action.SEARCH", + "subscription", + "sort", + "period", + "boostforreddit.com/themes", + ), +) diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch.kt new file mode 100644 index 00000000..c0909a7a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations + +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch +import app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.fingerprints.InitFingerprint + +@Patch(requiresIntegrations = true) +object IntegrationsPatch : BaseIntegrationsPatch( + setOf(InitFingerprint) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/fingerprints/InitFingerprint.kt new file mode 100644 index 00000000..ae28bc63 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/fingerprints/InitFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object InitFingerprint : IntegrationsFingerprint( + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/rubenmayayo/reddit/MyApplication;" && methodDef.name == "onCreate" }, + insertIndexResolver = { 1 } // Insert after call to super class. +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt index 09fa4e37..26c87582 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt @@ -1,32 +1,49 @@ package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.CompatiblePackage -import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.fingerprint.MethodFingerprintResult +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.reddit.customclients.BaseFixSLinksPatch import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.LinkHelperOpenLinkFingerprint -import app.revanced.util.exception +import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.SetAuthorizationHeaderFingerprint +import app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.IntegrationsPatch -@Patch( - name = "Fix /s/ links", - description = "Fixes the issue where /s/ links do not work.", - compatiblePackages = [ +@Suppress("unused") +object FixSLinksPatch : BaseFixSLinksPatch( + handleNavigationFingerprint = LinkHelperOpenLinkFingerprint, + setAccessTokenFingerprint = SetAuthorizationHeaderFingerprint, + compatiblePackages = setOf( CompatiblePackage("com.laurencedawson.reddit_sync"), CompatiblePackage("com.laurencedawson.reddit_sync.pro"), - CompatiblePackage("com.laurencedawson.reddit_sync.dev") - ], - requiresIntegrations = true -) -object FixSLinksPatch : BytecodePatch( - setOf(LinkHelperOpenLinkFingerprint) + CompatiblePackage("com.laurencedawson.reddit_sync.dev"), + ), + dependencies = setOf(IntegrationsPatch::class), ) { - override fun execute(context: BytecodeContext) = - LinkHelperOpenLinkFingerprint.result?.mutableMethod?.addInstructions( - 1, - """ - invoke-static { p3 }, Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;->resolveSLink(Ljava/lang/String;)Ljava/lang/String; - move-result-object p3 - """ - ) ?: throw LinkHelperOpenLinkFingerprint.exception + override val integrationsClassDescriptor = "Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;" + + override fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext) { + mutableMethod.apply { + val urlRegister = "p3" + val tempRegister = "v2" + + addInstructionsWithLabels( + 0, + """ + invoke-static { $urlRegister }, $integrationsClassDescriptor->$resolveSLinkMethod + move-result $tempRegister + if-eqz $tempRegister, :continue + return $tempRegister + """, + ExternalLabel("continue", getInstruction(0)), + ) + } + } + + override fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext) = mutableMethod.addInstruction( + 0, + "invoke-static { p0 }, $integrationsClassDescriptor->$setAccessTokenMethod", + ) } diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/fingerprints/SetAuthorizationHeaderFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/fingerprints/SetAuthorizationHeaderFingerprint.kt new file mode 100644 index 00000000..217ee859 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/fingerprints/SetAuthorizationHeaderFingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object SetAuthorizationHeaderFingerprint : MethodFingerprint( + strings = listOf("Authorization", "bearer "), + returnType = "Ljava/util/HashMap;", + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/laurencedawson/reddit_sync/singleton/a;" }, +) diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/misc.integrations/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/misc.integrations/IntegrationsPatch.kt new file mode 100644 index 00000000..bf5ebc32 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/misc.integrations/IntegrationsPatch.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations + +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch +import app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.fingerprints.InitFingerprint + +@Patch(requiresIntegrations = true) +object IntegrationsPatch : BaseIntegrationsPatch( + setOf(InitFingerprint) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/misc.integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/misc.integrations/fingerprints/InitFingerprint.kt new file mode 100644 index 00000000..950f2cbe --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/misc.integrations/fingerprints/InitFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.fingerprints + +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint + +internal object InitFingerprint : IntegrationsFingerprint( + customFingerprint = { methodDef, classDef -> + methodDef.name == "onCreate" && classDef.type == "Lcom/laurencedawson/reddit_sync/RedditApplication;" + }, + insertIndexResolver = { 1 }, // Insert after call to super class. +)