fix(Spotify): Fix Hide Create button
and Sanitize sharing links
for older but supported app targets (#5159)
This commit is contained in:
@ -37,20 +37,24 @@ public final class HideCreateButtonPatch {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String stringifiedNavigationBarItem = navigationBarItem.toString();
|
try {
|
||||||
|
String stringifiedNavigationBarItem = navigationBarItem.toString();
|
||||||
|
|
||||||
for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
|
for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
|
||||||
if (componentFilter.filterUnavailable()) {
|
if (componentFilter.filterUnavailable()) {
|
||||||
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
|
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
|
||||||
componentFilter.getFilterRepresentation() + " not available, skipping");
|
componentFilter.getFilterRepresentation() + " not available, skipping");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
|
if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
|
||||||
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " + navigationBarItem +
|
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " +
|
||||||
" matched the filter " + componentFilter.getFilterRepresentation());
|
navigationBarItem + " matched the filter " + componentFilter.getFilterRepresentation());
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "returnNullIfIsCreateButton failure", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return navigationBarItem;
|
return navigationBarItem;
|
||||||
|
@ -202,37 +202,41 @@ public final class UnlockPremiumPatch {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String stringifiedContextMenuItem = contextMenuItem.toString();
|
try {
|
||||||
|
String stringifiedContextMenuItem = contextMenuItem.toString();
|
||||||
|
|
||||||
for (List<ComponentFilter> componentFilters : CONTEXT_MENU_ITEMS_COMPONENT_FILTERS) {
|
for (List<ComponentFilter> componentFilters : CONTEXT_MENU_ITEMS_COMPONENT_FILTERS) {
|
||||||
boolean allMatch = true;
|
boolean allMatch = true;
|
||||||
StringBuilder matchedFilterRepresentations = new StringBuilder();
|
StringBuilder matchedFilterRepresentations = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0, filterSize = componentFilters.size(); i < filterSize; i++) {
|
for (int i = 0, filterSize = componentFilters.size(); i < filterSize; i++) {
|
||||||
ComponentFilter componentFilter = componentFilters.get(i);
|
ComponentFilter componentFilter = componentFilters.get(i);
|
||||||
|
|
||||||
if (componentFilter.filterUnavailable()) {
|
if (componentFilter.filterUnavailable()) {
|
||||||
Logger.printInfo(() -> "isFilteredContextMenuItem: Filter " +
|
Logger.printInfo(() -> "isFilteredContextMenuItem: Filter " +
|
||||||
componentFilter.getFilterRepresentation() + " not available, skipping");
|
componentFilter.getFilterRepresentation() + " not available, skipping");
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stringifiedContextMenuItem.contains(componentFilter.getFilterValue())) {
|
||||||
|
allMatch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchedFilterRepresentations.append(componentFilter.getFilterRepresentation());
|
||||||
|
if (i < filterSize - 1) {
|
||||||
|
matchedFilterRepresentations.append(", ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stringifiedContextMenuItem.contains(componentFilter.getFilterValue())) {
|
if (allMatch) {
|
||||||
allMatch = false;
|
Logger.printInfo(() -> "Filtering context menu item " + stringifiedContextMenuItem +
|
||||||
break;
|
" because the following filters matched: " + matchedFilterRepresentations);
|
||||||
}
|
return true;
|
||||||
|
|
||||||
matchedFilterRepresentations.append(componentFilter.getFilterRepresentation());
|
|
||||||
if (i < filterSize - 1) {
|
|
||||||
matchedFilterRepresentations.append(", ");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
if (allMatch) {
|
Logger.printException(() -> "isFilteredContextMenuItem failure", ex);
|
||||||
Logger.printInfo(() -> "Filtering context menu item " + stringifiedContextMenuItem +
|
|
||||||
" because the following filters matched: " + matchedFilterRepresentations);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -72,7 +72,7 @@ val hideCreateButtonPatch = bytecodePatch(
|
|||||||
|
|
||||||
if (oldNavigationBarAddItemMethod != null) {
|
if (oldNavigationBarAddItemMethod != null) {
|
||||||
// In case an older version of the app is being patched, hook the old method which adds navigation bar items.
|
// In case an older version of the app is being patched, hook the old method which adds navigation bar items.
|
||||||
// Return null early if the navigation bar item title resource id is the old Create button title resource id.
|
// Return early if the navigation bar item title resource id is the old Create button title resource id.
|
||||||
oldNavigationBarAddItemFingerprint.methodOrNull?.apply {
|
oldNavigationBarAddItemFingerprint.methodOrNull?.apply {
|
||||||
val getNavigationBarItemTitleStringIndex = indexOfFirstInstructionOrThrow {
|
val getNavigationBarItemTitleStringIndex = indexOfFirstInstructionOrThrow {
|
||||||
val reference = getReference<MethodReference>()
|
val reference = getReference<MethodReference>()
|
||||||
@ -89,6 +89,16 @@ val hideCreateButtonPatch = bytecodePatch(
|
|||||||
val isOldCreateButtonDescriptor =
|
val isOldCreateButtonDescriptor =
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->isOldCreateButton(I)Z"
|
"$EXTENSION_CLASS_DESCRIPTOR->isOldCreateButton(I)Z"
|
||||||
|
|
||||||
|
val returnEarlyInstruction = if (returnType == "V") {
|
||||||
|
// In older implementations the method return value is void.
|
||||||
|
"return-void"
|
||||||
|
} else {
|
||||||
|
// In newer implementations
|
||||||
|
// return null because the method return value is a BottomNavigationItemView.
|
||||||
|
"const/4 v0, 0\n" +
|
||||||
|
"return-object v0"
|
||||||
|
}
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
@ -98,9 +108,7 @@ val hideCreateButtonPatch = bytecodePatch(
|
|||||||
# If this navigation bar item is not the Create button, jump to the normal method logic.
|
# If this navigation bar item is not the Create button, jump to the normal method logic.
|
||||||
if-eqz v0, :normal-method-logic
|
if-eqz v0, :normal-method-logic
|
||||||
|
|
||||||
# Return null early because this method return value is a BottomNavigationItemView.
|
$returnEarlyInstruction
|
||||||
const/4 v0, 0
|
|
||||||
return-object v0
|
|
||||||
""",
|
""",
|
||||||
ExternalLabel("normal-method-logic", firstInstruction)
|
ExternalLabel("normal-method-logic", firstInstruction)
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,7 @@ package app.revanced.patches.spotify.misc.privacy
|
|||||||
import app.revanced.patcher.fingerprint
|
import app.revanced.patcher.fingerprint
|
||||||
import app.revanced.util.literal
|
import app.revanced.util.literal
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal val shareCopyUrlFingerprint = fingerprint {
|
internal val shareCopyUrlFingerprint = fingerprint {
|
||||||
returns("Ljava/lang/Object;")
|
returns("Ljava/lang/Object;")
|
||||||
@ -23,9 +24,15 @@ internal val shareCopyUrlLegacyFingerprint = fingerprint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val formatAndroidShareSheetUrlFingerprint = fingerprint {
|
internal val formatAndroidShareSheetUrlFingerprint = fingerprint {
|
||||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
|
||||||
returns("Ljava/lang/String;")
|
returns("Ljava/lang/String;")
|
||||||
parameters("L", "Ljava/lang/String;")
|
parameters("L", "Ljava/lang/String;")
|
||||||
|
opcodes(
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.RETURN_OBJECT
|
||||||
|
)
|
||||||
literal {
|
literal {
|
||||||
'\n'.code.toLong()
|
'\n'.code.toLong()
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
|
|||||||
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
@ -56,7 +57,15 @@ val sanitizeSharingLinksPatch = bytecodePatch(
|
|||||||
shareUrlParameter = "p2"
|
shareUrlParameter = "p2"
|
||||||
} else {
|
} else {
|
||||||
shareSheetFingerprint = formatAndroidShareSheetUrlFingerprint
|
shareSheetFingerprint = formatAndroidShareSheetUrlFingerprint
|
||||||
shareUrlParameter = "p1"
|
val methodAccessFlags = formatAndroidShareSheetUrlFingerprint.originalMethod.accessFlags
|
||||||
|
shareUrlParameter = if (AccessFlags.STATIC.isSet(methodAccessFlags)) {
|
||||||
|
// In newer implementations the method is static, so p0 is not `this`.
|
||||||
|
"p1"
|
||||||
|
} else {
|
||||||
|
// In older implementations the method is not static, making it so p0 is `this`.
|
||||||
|
// For that reason, add one to the parameter register.
|
||||||
|
"p2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shareSheetFingerprint.method.addInstructions(
|
shareSheetFingerprint.method.addInstructions(
|
||||||
|
Reference in New Issue
Block a user