fix(Spotify): Fix Hide Create button and Sanitize sharing links for older but supported app targets (#5159)

This commit is contained in:
Nuckyz
2025-06-11 17:20:19 -03:00
committed by GitHub
parent 756b28dca0
commit e7dd061c51
5 changed files with 73 additions and 41 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)
) )

View File

@ -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()
} }

View File

@ -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(