fix(3rd-party Reddit apps): Spoof user agent to work around Reddit API issues (#3253)

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
Yan 2024-05-31 02:50:09 +03:00 committed by GitHub
parent d8415c0bee
commit 495e6d65e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 93 additions and 35 deletions

View file

@ -555,6 +555,7 @@ public final class app/revanced/patches/reddit/customclients/baconreader/api/Spo
public final class app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public final class app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch {
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch; public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch;
public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
} }
public final class app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public final class app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch {
@ -577,6 +578,11 @@ public final class app/revanced/patches/reddit/customclients/joeyforreddit/ads/D
public final class app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public final class app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch {
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch; public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch;
public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
}
public final class app/revanced/patches/reddit/customclients/joeyforreddit/api/fingerprints/AuthUtilityUserAgent : app/revanced/patcher/fingerprint/MethodFingerprint {
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/joeyforreddit/api/fingerprints/AuthUtilityUserAgent;
} }
public final class app/revanced/patches/reddit/customclients/joeyforreddit/detection/piracy/DisablePiracyDetectionPatch : app/revanced/patcher/patch/BytecodePatch { public final class app/revanced/patches/reddit/customclients/joeyforreddit/detection/piracy/DisablePiracyDetectionPatch : app/revanced/patcher/patch/BytecodePatch {
@ -621,6 +627,7 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/api/S
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/api/SpoofClientPatch; public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/api/SpoofClientPatch;
public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
public fun patchMiscellaneous (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchMiscellaneous (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
} }
public final class app/revanced/patches/reddit/customclients/syncforreddit/detection/piracy/DisablePiracyDetectionPatch : app/revanced/patcher/patch/BytecodePatch { public final class app/revanced/patches/reddit/customclients/syncforreddit/detection/piracy/DisablePiracyDetectionPatch : app/revanced/patcher/patch/BytecodePatch {

View file

@ -5,15 +5,14 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch
import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.GetClientIdFingerprint import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.GetClientIdFingerprint
import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.LoginActivityOnCreateFingerprint import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.JRAWUserAgent
@Suppress("unused") @Suppress("unused")
object SpoofClientPatch : BaseSpoofClientPatch( object SpoofClientPatch : BaseSpoofClientPatch(
redirectUri = "http://rubenmayayo.com", redirectUri = "http://rubenmayayo.com",
clientIdFingerprints = setOf(GetClientIdFingerprint), clientIdFingerprints = setOf(GetClientIdFingerprint),
userAgentFingerprints = setOf(LoginActivityOnCreateFingerprint), userAgentFingerprints = setOf(JRAWUserAgent),
compatiblePackages = setOf(CompatiblePackage("com.rubenmayayo.reddit")) compatiblePackages = setOf(CompatiblePackage("com.rubenmayayo.reddit")),
) { ) {
override fun Set<MethodFingerprintResult>.patchClientId(context: BytecodeContext) { override fun Set<MethodFingerprintResult>.patchClientId(context: BytecodeContext) {
first().mutableMethod.addInstructions( first().mutableMethod.addInstructions(
@ -21,7 +20,17 @@ object SpoofClientPatch : BaseSpoofClientPatch(
""" """
const-string v0, "$clientId" const-string v0, "$clientId"
return-object v0 return-object v0
""" """,
)
}
override fun Set<MethodFingerprintResult>.patchUserAgent(context: BytecodeContext) {
// Use a random user agent.
val randomName = (0..100000).random()
first().mutableMethod.addInstructions(
1,
"const-string v3, \"$randomName\"",
) )
} }
} }

View file

@ -0,0 +1,7 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object JRAWUserAgent : MethodFingerprint(
strings = listOf("platform", "appId", "version", "redditUsername"),
)

View file

@ -1,14 +0,0 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object LoginActivityOnCreateFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4
),
customFingerprint = { method, classDef ->
method.name == "onCreate" && classDef.type.endsWith("LoginActivity;")
}
)

View file

@ -2,8 +2,10 @@ package app.revanced.patches.reddit.customclients.joeyforreddit.api
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch
import app.revanced.patches.reddit.customclients.joeyforreddit.api.fingerprints.AuthUtilityUserAgent
import app.revanced.patches.reddit.customclients.joeyforreddit.api.fingerprints.GetClientIdFingerprint import app.revanced.patches.reddit.customclients.joeyforreddit.api.fingerprints.GetClientIdFingerprint
import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.DisablePiracyDetectionPatch import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.DisablePiracyDetectionPatch
@ -12,6 +14,7 @@ import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.
object SpoofClientPatch : BaseSpoofClientPatch( object SpoofClientPatch : BaseSpoofClientPatch(
redirectUri = "https://127.0.0.1:65023/authorize_callback", redirectUri = "https://127.0.0.1:65023/authorize_callback",
clientIdFingerprints = setOf(GetClientIdFingerprint), clientIdFingerprints = setOf(GetClientIdFingerprint),
userAgentFingerprints = setOf(AuthUtilityUserAgent),
compatiblePackages = setOf( compatiblePackages = setOf(
CompatiblePackage("o.o.joey"), CompatiblePackage("o.o.joey"),
CompatiblePackage("o.o.joey.pro"), CompatiblePackage("o.o.joey.pro"),
@ -28,4 +31,18 @@ object SpoofClientPatch : BaseSpoofClientPatch(
""" """
) )
} }
override fun Set<MethodFingerprintResult>.patchUserAgent(context: BytecodeContext) {
// Use a random user agent.
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
first().mutableMethod.replaceInstructions(
0,
"""
const-string v0, "$userAgent"
return-object v0
""",
)
}
} }

View file

@ -0,0 +1,15 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.api.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object AuthUtilityUserAgent : MethodFingerprint(
returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
opcodes = listOf(Opcode.APUT_OBJECT),
customFingerprint = { _, classDef ->
classDef.sourceFile == "AuthUtility.java"
},
)

View file

@ -1,18 +1,16 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy package app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint
import app.revanced.util.exception
object DisablePiracyDetectionPatch : BytecodePatch(setOf(PiracyDetectionFingerprint)) { object DisablePiracyDetectionPatch : BytecodePatch(setOf(PiracyDetectionFingerprint)) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
PiracyDetectionFingerprint.result?.mutableMethod?.addInstruction( PiracyDetectionFingerprint.result?.mutableMethod?.addInstruction(
0, 0,
""" "return-void",
return-void
"""
) ?: throw PiracyDetectionFingerprint.exception ) ?: throw PiracyDetectionFingerprint.exception
} }
} }

View file

@ -14,7 +14,6 @@ import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused") @Suppress("unused")
object SpoofClientPatch : BaseSpoofClientPatch( object SpoofClientPatch : BaseSpoofClientPatch(
redirectUri = "redditisfun://auth", redirectUri = "redditisfun://auth",
@ -54,7 +53,7 @@ object SpoofClientPatch : BaseSpoofClientPatch(
override fun Set<MethodFingerprintResult>.patchUserAgent(context: BytecodeContext) { override fun Set<MethodFingerprintResult>.patchUserAgent(context: BytecodeContext) {
// Use a random user agent. // Use a random user agent.
val randomName = (0..100000).random() val randomName = (0..100000).random()
val userAgent = "android:app.revanced.$randomName:v1.0.0 (by /u/revanced)" val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
first().mutableMethod.addInstructions( first().mutableMethod.addInstructions(
0, 0,

View file

@ -6,10 +6,10 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch
import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.*
import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.GetAuthorizationStringFingerprint import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.GetAuthorizationStringFingerprint
import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.GetBearerTokenFingerprint import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.GetBearerTokenFingerprint
import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.ImgurImageAPIFingerprint import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.ImgurImageAPIFingerprint
import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.LoadBrowserURLFingerprint
import app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.DisablePiracyDetectionPatch import app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.DisablePiracyDetectionPatch
import app.revanced.util.exception import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -17,19 +17,18 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference import com.android.tools.smali.dexlib2.iface.reference.StringReference
import java.util.* import java.util.*
@Suppress("unused") @Suppress("unused")
object SpoofClientPatch : BaseSpoofClientPatch( object SpoofClientPatch : BaseSpoofClientPatch(
redirectUri = "http://redditsync/auth", redirectUri = "http://redditsync/auth",
miscellaneousFingerprints = setOf(ImgurImageAPIFingerprint), miscellaneousFingerprints = setOf(ImgurImageAPIFingerprint),
clientIdFingerprints = setOf(GetAuthorizationStringFingerprint), clientIdFingerprints = setOf(GetAuthorizationStringFingerprint),
userAgentFingerprints = setOf(LoadBrowserURLFingerprint), userAgentFingerprints = setOf(GetUserAgentFingerprint),
compatiblePackages = setOf( compatiblePackages = setOf(
CompatiblePackage("com.laurencedawson.reddit_sync"), CompatiblePackage("com.laurencedawson.reddit_sync"),
CompatiblePackage("com.laurencedawson.reddit_sync.pro"), CompatiblePackage("com.laurencedawson.reddit_sync.pro"),
CompatiblePackage("com.laurencedawson.reddit_sync.dev") CompatiblePackage("com.laurencedawson.reddit_sync.dev"),
), ),
dependencies = setOf(DisablePiracyDetectionPatch::class) dependencies = setOf(DisablePiracyDetectionPatch::class),
) { ) {
override fun Set<MethodFingerprintResult>.patchClientId(context: BytecodeContext) { override fun Set<MethodFingerprintResult>.patchClientId(context: BytecodeContext) {
forEach { fingerprintResult -> forEach { fingerprintResult ->
@ -41,7 +40,7 @@ object SpoofClientPatch : BaseSpoofClientPatch(
""" """
const-string v0, "Basic $auth" const-string v0, "Basic $auth"
return-object v0 return-object v0
""" """,
) )
} ?: throw GetBearerTokenFingerprint.exception } ?: throw GetBearerTokenFingerprint.exception
}.let { }.let {
@ -54,12 +53,12 @@ object SpoofClientPatch : BaseSpoofClientPatch(
val newAuthorizationUrl = reference.string.replace( val newAuthorizationUrl = reference.string.replace(
"client_id=.*?&".toRegex(), "client_id=.*?&".toRegex(),
"client_id=$clientId&" "client_id=$clientId&",
) )
replaceInstruction( replaceInstruction(
occurrenceIndex, occurrenceIndex,
"const-string v$targetRegister, \"$newAuthorizationUrl\"" "const-string v$targetRegister, \"$newAuthorizationUrl\"",
) )
} }
} }
@ -72,7 +71,21 @@ object SpoofClientPatch : BaseSpoofClientPatch(
it.mutableMethod.replaceInstruction( it.mutableMethod.replaceInstruction(
apiUrlIndex, apiUrlIndex,
"const-string v1, \"https://api.imgur.com/3/image\"" "const-string v1, \"https://api.imgur.com/3/image\"",
)
}
override fun Set<MethodFingerprintResult>.patchUserAgent(context: BytecodeContext) {
// Use a random user agent.
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
first().mutableMethod.replaceInstruction(
0,
"""
const-string v0, "$userAgent"
return-object v0
""",
) )
} }
} }

View file

@ -0,0 +1,7 @@
package app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object GetUserAgentFingerprint : MethodFingerprint(
strings = listOf("android:com.laurencedawson.reddit_sync"),
)