forked from ReVanced/revanced-patches-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Tumblr): Add
Disable Tumblr Live
patch (ReVanced#2987)
Co-authored-by: oSumAtrIX <[email protected]>
- Loading branch information
Showing
6 changed files
with
184 additions
and
2 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
...h/DisableBlogNotificationReminderPatch.kt → ...s/DisableBlogNotificationReminderPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...ups/patch/DisableGiftMessagePopupPatch.kt → ...es/popups/DisableGiftMessagePopupPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package app.revanced.patches.tumblr.featureflags | ||
|
||
import app.revanced.extensions.exception | ||
import app.revanced.patcher.data.BytecodeContext | ||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions | ||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels | ||
import app.revanced.patcher.extensions.or | ||
import app.revanced.patcher.patch.BytecodePatch | ||
import app.revanced.patcher.patch.annotation.Patch | ||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable | ||
import app.revanced.patches.tumblr.featureflags.fingerprints.GetFeatureValueFingerprint | ||
import com.android.tools.smali.dexlib2.AccessFlags | ||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation | ||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod | ||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter | ||
|
||
@Patch(description = "Forcibly set the value of A/B testing features of your choice.") | ||
object OverrideFeatureFlagsPatch : BytecodePatch( | ||
setOf(GetFeatureValueFingerprint) | ||
) { | ||
/** | ||
* Override a feature flag with a value. | ||
* | ||
* @param name The name of the feature flag to override. | ||
* @param value The value to override the feature flag with. | ||
*/ | ||
@Suppress("KDocUnresolvedReference") | ||
internal lateinit var addOverride: (name: String, value: String) -> Unit private set | ||
|
||
override fun execute(context: BytecodeContext) = GetFeatureValueFingerprint.result?.let { | ||
// The method we want to inject into does not have enough registers, so we inject a helper method | ||
// and inject more instructions into it later, see addOverride. | ||
// This is not in an integration since the unused variable would get compiled away and the method would | ||
// get compiled to only have one register, which is not enough for our later injected instructions. | ||
val helperMethod = ImmutableMethod( | ||
it.method.definingClass, | ||
"getValueOverride", | ||
listOf(ImmutableMethodParameter("Lcom/tumblr/configuration/Feature;", null, "feature")), | ||
"Ljava/lang/String;", | ||
AccessFlags.PUBLIC or AccessFlags.FINAL, | ||
null, | ||
null, | ||
MutableMethodImplementation(4) | ||
).toMutable().apply { | ||
// This is the equivalent of | ||
// String featureName = feature.toString() | ||
// <inject more instructions here later> | ||
// return null | ||
addInstructions( | ||
0, | ||
""" | ||
# toString() the enum value | ||
invoke-virtual {p1}, Lcom/tumblr/configuration/Feature;->toString()Ljava/lang/String; | ||
move-result-object v0 | ||
# !!! If you add more instructions above this line, update helperInsertIndex below! | ||
# Here we will insert one compare & return for every registered Feature override | ||
# This is done below in the addOverride function | ||
# If none of the overrides returned a value, we should return null | ||
const/4 v0, 0x0 | ||
return-object v0 | ||
""" | ||
) | ||
}.also { helperMethod -> | ||
it.mutableClass.methods.add(helperMethod) | ||
} | ||
|
||
// Here we actually insert the hook to call our helper method and return its value if it returns not null | ||
// This is equivalent to | ||
// String forcedValue = getValueOverride(feature) | ||
// if (forcedValue != null) return forcedValue | ||
val getFeatureIndex = it.scanResult.patternScanResult!!.startIndex | ||
it.mutableMethod.addInstructionsWithLabels( | ||
getFeatureIndex, | ||
""" | ||
# Call the Helper Method with the Feature | ||
invoke-virtual {p0, p1}, Lcom/tumblr/configuration/Configuration;->getValueOverride(Lcom/tumblr/configuration/Feature;)Ljava/lang/String; | ||
move-result-object v0 | ||
# If it returned null, skip | ||
if-eqz v0, :is_null | ||
# If it didnt return null, return that string | ||
return-object v0 | ||
# If our override helper returned null, we let the function continue normally | ||
:is_null | ||
nop | ||
""" | ||
) | ||
|
||
val helperInsertIndex = 2 | ||
addOverride = { name, value -> | ||
// For every added override, we add a few instructions in the middle of the helper method | ||
// to check if the feature is the one we want and return the override value if it is. | ||
// This is equivalent to | ||
// if (featureName == {name}) return {value} | ||
helperMethod.addInstructionsWithLabels( | ||
helperInsertIndex, | ||
""" | ||
# v0 is still the string name of the currently checked feature from above | ||
# Compare the current string with the override string | ||
const-string v1, "$name" | ||
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z | ||
move-result v1 | ||
# If the current string is the one we want to override, we return the override value | ||
if-eqz v1, :no_override | ||
const-string v1, "$value" | ||
return-object v1 | ||
# Else we just continue... | ||
:no_override | ||
nop | ||
""" | ||
) | ||
} | ||
} ?: throw GetFeatureValueFingerprint.exception | ||
} |
23 changes: 23 additions & 0 deletions
23
...otlin/app/revanced/patches/tumblr/featureflags/fingerprints/GetFeatureValueFingerprint.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package app.revanced.patches.tumblr.featureflags.fingerprints | ||
|
||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint | ||
import com.android.tools.smali.dexlib2.Opcode | ||
|
||
// This fingerprint targets the method to get the value of a Feature in the class "com.tumblr.configuration.Feature". | ||
// Features seem to be Tumblr's A/B testing program. | ||
// Feature states are loaded from the server in the "api-http2.tumblr.com/v2/config" request on (first) startup. | ||
// A lot of features are returned there, but most of them do not seem to do anything (anymore). | ||
// They were likely removed in newer App versions to always be on, but are still returned | ||
// as enabled for old App versions. | ||
// Some features seem to be very old and never removed, though, such as Google Login. | ||
// The startIndex of the opcode pattern is at the start of the function after the arg null check. | ||
// we want to insert our instructions there. | ||
object GetFeatureValueFingerprint : MethodFingerprint( | ||
strings = listOf("feature"), | ||
opcodes = listOf( | ||
Opcode.IF_EQZ, | ||
Opcode.INVOKE_STATIC, | ||
Opcode.MOVE_RESULT | ||
), | ||
customFingerprint = { method, _ -> method.definingClass == "Lcom/tumblr/configuration/Configuration;" } | ||
) |
37 changes: 37 additions & 0 deletions
37
src/main/kotlin/app/revanced/patches/tumblr/live/DisableTumblrLivePatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package app.revanced.patches.tumblr.live | ||
|
||
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.BytecodePatch | ||
import app.revanced.patcher.patch.annotation.CompatiblePackage | ||
import app.revanced.patcher.patch.annotation.Patch | ||
import app.revanced.patches.tumblr.featureflags.OverrideFeatureFlagsPatch | ||
import app.revanced.patches.tumblr.live.fingerprints.LiveMarqueeFingerprint | ||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction | ||
|
||
@Patch( | ||
name = "Disable Tumblr Live", | ||
description = "Disable the Tumblr Live tab button and dashboard carousel.", | ||
dependencies = [OverrideFeatureFlagsPatch::class], | ||
compatiblePackages = [CompatiblePackage("com.tumblr")] | ||
) | ||
@Suppress("unused") | ||
object DisableTumblrLivePatch : BytecodePatch( | ||
setOf(LiveMarqueeFingerprint) | ||
) { | ||
override fun execute(context: BytecodeContext) = LiveMarqueeFingerprint.result?.let { | ||
it.scanResult.stringsScanResult!!.matches.forEach { match -> | ||
// Replace the string constant "live_marquee" | ||
// with a dummy so the app doesn't recognize this type of element in the Dashboard and skips it | ||
it.mutableMethod.apply { | ||
val stringRegister = getInstruction<OneRegisterInstruction>(match.index).registerA | ||
replaceInstruction(match.index, "const-string v$stringRegister, \"dummy2\"") | ||
} | ||
} | ||
|
||
// We hide the Tab button for Tumblr Live by forcing the feature flag to false | ||
OverrideFeatureFlagsPatch.addOverride("liveStreaming", "false") | ||
} ?: throw LiveMarqueeFingerprint.exception | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/kotlin/app/revanced/patches/tumblr/live/fingerprints/LiveMarqueeFingerprint.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package app.revanced.patches.tumblr.live.fingerprints | ||
|
||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint | ||
|
||
// This works identically to the Tumblr AdWaterfallFingerprint, see comments there | ||
object LiveMarqueeFingerprint : MethodFingerprint(strings = listOf("live_marquee")) |