diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch.java new file mode 100644 index 00000000..48c8fd8c --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch.java @@ -0,0 +1,76 @@ +package app.revanced.integrations.youtube.patches; + +import static app.revanced.integrations.shared.StringRef.str; + +import android.app.Activity; +import android.text.Html; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import app.revanced.integrations.shared.Logger; +import app.revanced.integrations.shared.Utils; +import app.revanced.integrations.youtube.settings.Settings; + +@SuppressWarnings("unused") +public class CheckWatchHistoryDomainNameResolutionPatch { + + private static final String HISTORY_TRACKING_ENDPOINT = "s.youtube.com"; + + private static final String SINKHOLE_IPV4 = "0.0.0.0"; + private static final String SINKHOLE_IPV6 = "::"; + + /** @noinspection SameParameterValue */ + private static boolean domainResolvesToValidIP(String host) { + try { + InetAddress address = InetAddress.getByName(host); + String hostAddress = address.getHostAddress(); + + if (address.isLoopbackAddress()) { + Logger.printDebug(() -> host + " resolves to localhost"); + } else if (SINKHOLE_IPV4.equals(hostAddress) || SINKHOLE_IPV6.equals(hostAddress)) { + Logger.printDebug(() -> host + " resolves to sinkhole ip"); + } else { + return true; // Domain is not blocked. + } + } catch (UnknownHostException e) { + Logger.printDebug(() -> host + " failed to resolve"); + } + + return false; + } + + /** + * Injection point. + * + * Checks if s.youtube.com is blacklisted and playback history will fail to work. + */ + public static void checkDnsResolver(Activity context) { + if (!Utils.isNetworkConnected() || !Settings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return; + + Utils.runOnBackgroundThread(() -> { + try { + if (domainResolvesToValidIP(HISTORY_TRACKING_ENDPOINT)) { + return; + } + + Utils.runOnMainThread(() -> { + var alertDialog = new android.app.AlertDialog.Builder(context) + .setTitle(str("revanced_check_watch_history_domain_name_dialog_title")) + .setMessage(Html.fromHtml(str("revanced_check_watch_history_domain_name_dialog_message"))) + .setIconAttribute(android.R.attr.alertDialogIcon) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + dialog.dismiss(); + }).setNegativeButton(str("revanced_check_watch_history_domain_name_dialog_ignore"), (dialog, which) -> { + Settings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false); + dialog.dismiss(); + }) + .setCancelable(false) + .show(); + }); + } catch (Exception ex) { + Logger.printException(() -> "checkDnsResolver failure", ex); + } + }); + } +} diff --git a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java index 9c18932f..47ee02c8 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java +++ b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java @@ -258,6 +258,7 @@ public class Settings extends BaseSettings { @Deprecated public static final StringSetting DEPRECATED_ANNOUNCEMENT_LAST_HASH = new StringSetting("revanced_announcement_last_hash", ""); public static final IntegerSetting ANNOUNCEMENT_LAST_ID = new IntegerSetting("revanced_announcement_last_id", -1); + public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false); public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE); // Debugging