feat(Instagram): Add Sanitize sharing links patch (#5986)

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
brosssh
2025-10-03 09:19:01 +02:00
committed by GitHub
parent 0acba30245
commit 963a4ef43f
9 changed files with 164 additions and 37 deletions

View File

@@ -0,0 +1,15 @@
package app.revanced.extension.instagram.misc.privacy;
import app.revanced.extension.shared.privacy.LinkSanitizer;
@SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch {
private static final LinkSanitizer sanitizer = new LinkSanitizer("igsh");
/**
* Injection point.
*/
public static String sanitizeSharingLink(String url) {
return sanitizer.sanitizeUrlString(url);
}
}

View File

@@ -1,5 +1,6 @@
package app.revanced.extension.shared.patches; package app.revanced.extension.shared.patches;
import app.revanced.extension.shared.privacy.LinkSanitizer;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
/** /**
@@ -7,17 +8,18 @@ import app.revanced.extension.shared.settings.BaseSettings;
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch { public final class SanitizeSharingLinksPatch {
private static final String NEW_TRACKING_PARAMETER_REGEX = ".si=.+";
private static final String OLD_TRACKING_PARAMETER_REGEX = ".feature=.+"; private static final LinkSanitizer sanitizer = new LinkSanitizer(
"si",
"feature" // Old tracking parameter name, and may be obsolete.
);
/** /**
* Injection point. * Injection point.
*/ */
public static String sanitize(String url) { public static String sanitize(String url) {
if (BaseSettings.SANITIZE_SHARED_LINKS.get()) { if (BaseSettings.SANITIZE_SHARED_LINKS.get()) {
url = url url = sanitizer.sanitizeUrlString(url);
.replaceAll(NEW_TRACKING_PARAMETER_REGEX, "")
.replaceAll(OLD_TRACKING_PARAMETER_REGEX, "");
} }
if (BaseSettings.REPLACE_MUSIC_LINKS_WITH_YOUTUBE.get()) { if (BaseSettings.REPLACE_MUSIC_LINKS_WITH_YOUTUBE.get()) {

View File

@@ -0,0 +1,60 @@
package app.revanced.extension.shared.privacy;
import android.net.Uri;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import app.revanced.extension.shared.Logger;
/**
* Strips away specific parameters from URLs.
*/
public class LinkSanitizer {
private final Collection<String> parametersToRemove;
public LinkSanitizer(String ... parametersToRemove) {
final int parameterCount = parametersToRemove.length;
if (parameterCount == 0) {
throw new IllegalArgumentException("No parameters specified");
}
// List is faster if only checking a few parameters.
this.parametersToRemove = parameterCount > 4
? Set.of(parametersToRemove)
: List.of(parametersToRemove);
}
public String sanitizeUrlString(String url) {
try {
return sanitizeUri(Uri.parse(url)).toString();
} catch (Exception ex) {
Logger.printException(() -> "sanitizeUrlString failure: " + url, ex);
return url;
}
}
public Uri sanitizeUri(Uri uri) {
try {
Uri.Builder builder = uri.buildUpon().clearQuery();
for (String paramName : uri.getQueryParameterNames()) {
if (!parametersToRemove.contains(paramName)) {
for (String value : uri.getQueryParameters(paramName)) {
builder.appendQueryParameter(paramName, value);
}
}
}
Uri sanitizedUrl = builder.build();
Logger.printInfo(() -> "Sanitized url: " + uri + " to: " + sanitizedUrl);
return sanitizedUrl;
} catch (Exception ex) {
Logger.printException(() -> "sanitizeUri failure: " + uri, ex);
return uri;
}
}
}

View File

@@ -1,18 +1,11 @@
package app.revanced.extension.spotify.misc.privacy; package app.revanced.extension.spotify.misc.privacy;
import android.net.Uri; import app.revanced.extension.shared.privacy.LinkSanitizer;
import java.util.List;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch { public final class SanitizeSharingLinksPatch {
/** private static final LinkSanitizer sanitizer = new LinkSanitizer(
* Parameters that are considered undesirable and should be stripped away.
*/
private static final List<String> SHARE_PARAMETERS_TO_REMOVE = List.of(
"si", // Share tracking parameter. "si", // Share tracking parameter.
"utm_source" // Share source, such as "copy-link". "utm_source" // Share source, such as "copy-link".
); );
@@ -20,25 +13,7 @@ public final class SanitizeSharingLinksPatch {
/** /**
* Injection point. * Injection point.
*/ */
public static String sanitizeUrl(String url) { public static String sanitizeSharingLink(String url) {
try { return sanitizer.sanitizeUrlString(url);
Uri uri = Uri.parse(url);
Uri.Builder builder = uri.buildUpon().clearQuery();
for (String paramName : uri.getQueryParameterNames()) {
if (!SHARE_PARAMETERS_TO_REMOVE.contains(paramName)) {
for (String value : uri.getQueryParameters(paramName)) {
builder.appendQueryParameter(paramName, value);
}
}
}
String sanitizedUrl = builder.build().toString();
Logger.printInfo(() -> "Sanitized url " + url + " to " + sanitizedUrl);
return sanitizedUrl;
} catch (Exception ex) {
Logger.printException(() -> "sanitizeUrl failure with " + url, ex);
return url;
}
} }
} }

View File

@@ -288,6 +288,10 @@ public final class app/revanced/patches/instagram/misc/links/OpenLinksExternally
public static final fun getOpenLinksExternallyPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getOpenLinksExternallyPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/instagram/misc/privacy/SanitizeSharingLinksPatchKt {
public static final fun getSanitizeSharingLinksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt { public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }

View File

@@ -0,0 +1,23 @@
package app.revanced.patches.instagram.misc.privacy
import app.revanced.patcher.fingerprint
internal val permalinkResponseJsonParserFingerprint = fingerprint {
strings("permalink", "PermalinkResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val storyUrlResponseJsonParserFingerprint = fingerprint {
strings("story_item_to_share_url", "StoryItemUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val profileUrlResponseJsonParserFingerprint = fingerprint {
strings("profile_to_share_url", "ProfileUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val liveUrlResponseJsonParserFingerprint = fingerprint {
strings("live_to_share_url", "LiveItemLinkUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}

View File

@@ -0,0 +1,48 @@
package app.revanced.patches.instagram.misc.privacy
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/instagram/misc/privacy/SanitizeSharingLinksPatch;"
@Suppress("unused")
val sanitizeSharingLinksPatch = bytecodePatch(
name = "Sanitize sharing links",
description = "Removes the tracking query parameters from shared links.",
) {
compatibleWith("com.instagram.android")
dependsOn(sharedExtensionPatch)
execute {
arrayOf(
permalinkResponseJsonParserFingerprint,
storyUrlResponseJsonParserFingerprint,
profileUrlResponseJsonParserFingerprint,
liveUrlResponseJsonParserFingerprint
).forEach { fingerprint ->
fingerprint.method.apply {
val putSharingUrlIndex = indexOfFirstInstructionOrThrow(
fingerprint.stringMatches!!.first().index,
Opcode.IPUT_OBJECT
)
val sharingUrlRegister = getInstruction<TwoRegisterInstruction>(putSharingUrlIndex).registerA
addInstructions(
putSharingUrlIndex,
"""
invoke-static { v$sharingUrlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeSharingLink(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$sharingUrlRegister
"""
)
}
}
}
}

View File

@@ -6,7 +6,7 @@ import app.revanced.patcher.patch.bytecodePatch
@Suppress("unused") @Suppress("unused")
val sanitizeUrlQueryPatch = bytecodePatch( val sanitizeUrlQueryPatch = bytecodePatch(
name = "Sanitize sharing links", name = "Sanitize sharing links",
description = "Removes (tracking) query parameters from the URLs when sharing links.", description = "Removes the tracking query parameters from shared links.",
) { ) {
compatibleWith("com.reddit.frontpage") compatibleWith("com.reddit.frontpage")

View File

@@ -16,7 +16,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused") @Suppress("unused")
val sanitizeSharingLinksPatch = bytecodePatch( val sanitizeSharingLinksPatch = bytecodePatch(
name = "Sanitize sharing links", name = "Sanitize sharing links",
description = "Removes the tracking query parameters from links before they are shared.", description = "Removes the tracking query parameters from shared links.",
) { ) {
compatibleWith("com.spotify.music") compatibleWith("com.spotify.music")
@@ -24,7 +24,7 @@ val sanitizeSharingLinksPatch = bytecodePatch(
execute { execute {
val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->" + val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->" +
"sanitizeUrl(Ljava/lang/String;)Ljava/lang/String;" "sanitizeSharingLink(Ljava/lang/String;)Ljava/lang/String;"
val copyFingerprint = if (shareCopyUrlFingerprint.originalMethodOrNull != null) { val copyFingerprint = if (shareCopyUrlFingerprint.originalMethodOrNull != null) {
shareCopyUrlFingerprint shareCopyUrlFingerprint