Stop Nefarious Redirects

Block unauthorized redirects and prevent history manipulation

目前為 2024-05-28 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Stop Nefarious Redirects
// @namespace    http://tampermonkey.net/
// @version      4.1
// @description  Block unauthorized redirects and prevent history manipulation
// @match        http://*/*
// @match        https://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @license      MIT
// @run-at       document-start
// ==/UserScript==

const manualBlacklist = new Set([
    'getrunkhomuto.info'
]);

// List of allowed popups domains
const allowedPopups = [
        '500px.com', 'accuweather.com', 'adobe.com', 'adulttime.com', 'alibaba.com', 'amazon.com', 'amazonaws.com',
        'amd.com', 'americanexpress.com', 'anaconda.com', 'angular.io', 'ap.org', 'apache.org', 'apnews.com',
        'apple.com', 'arstechnica.com', 'artstation.com', 'asana.com', 'asus.com', 'atlassian.com', 'autodesk.com',
        'axios.com', 'battle.net', 'bbc.co.uk', 'bbc.com', 'behance.net', 'bestbuy.com', 'bing.com', 'bitbucket.org',
        'blogger.com', 'bloomberg.com', 'bmw.com', 'boeing.com', 'booking.co.uk', 'booking.com', 'bootstrapcdn.com',
        'breitbart.com', 'buzzfeed.com', 'canva.com', 'capitalone.com', 'cbsnews.com', 'character.ai', 'chase.com',
        'chaturbate.com', 'cisco.com', 'citi.com', 'cnbc.com', 'cnet.com', 'cnn.com', 'codecademy.com', 'constantcontact.com',
        'coursera.org', 'craigslist.org', 'dailymail.co.uk', 'dell.com', 'deviantart.com', 'discord.com', 'disney.com',
        'django.com', 'docker.com', 'docusign.com', 'dribbble.com', 'dropbox.com', 'duckduckgo.com', 'duolingo.com',
        'duosecurity.com', 'ebay.com', 'economist.com', 'edx.org', 'elsevier.com', 'engadget.com', 'epicgames.com',
        'eporner.com', 'espn.com', 'etsy.com', 'eurogamer.net', 'expedia.com', 'facebook.com', 'fandom.com', 'fedex.com',
        'figma.com', 'finance.yahoo.com', 'flickr.com', 'flipkart.com', 'forbes.com', 'foxnews.com', 'framer.com',
        'freecodecamp.org', 'gamespot.com', 'gartner.com', 'gettyimages.com', 'git-scm.com', 'github.com', 'gizmodo.com',
        'go.com', 'godaddy.com', 'gog.com', 'goldmansachs.com', 'google.com', 'healthline.com', 'hilton.com', 'homedepot.com',
        'hp.com', 'hubspot.com', 'huffpost.com', 'hulu.com', 'humblebundle.com', 'ibm.com', 'ieee.org', 'ifixit.com',
        'ign.com', 'ikea.com', 'imdb.com', 'imgur.com', 'indeed.com', 'instagram.com', 'instructure.com', 'intel.com',
        'intuit.com', 'invisionapp.com', 'itch.io', 'java.com', 'jetbrains.com', 'joomla.org', 'jquery.com', 'khanacademy.org',
        'kotaku.com', 'kotlinlang.org', 'laravel.com', 'lenovo.com', 'lg.com', 'lifehacker.com', 'linkedin.com', 'live.com',
        'lowes.com', 'lynda.com', 'macys.com', 'mailchimp.com', 'marriott.com', 'mashable.com', 'masterclass.com',
        'mcdonalds.com', 'medium.com', 'mercedes-benz.com', 'microsoft.com', 'microsoftonline.commit.edu', 'mongodb.com',
        'moodle.org', 'mozilla.org', 'msn.com', 'msnbc.com', 'nasa.gov', 'nationalgeographic.com', 'nbc.com', 'nbcnews.com',
        'netflix.com', 'new.reddit.com', 'nextdoor.com', 'nih.gov', 'npr.org', 'nvidia.comnypost.com', 'nytimes.com',
        'office.com', 'okta.com', 'onlyfans.com', 'openai.com', 'oracle.com', 'oreilly.com', 'origin.com', 'outlook.com',
        'overstock.com', 'patreon.com', 'paypal.com', 'pcgamer.com', 'pexels.com', 'php.net', 'pinterest.com', 'pixabay.com',
        'pluralsight.com', 'polygon.com', 'pornhub.com', 'python.org', 'quizlet.com', 'quora.com', 'reactjs.org', 'realtor.com',
        'reddit.com', 'redhat.com', 'roblox.com', 'rubyonrails.org', 'salesforce.com', 'samsung.co.kr', 'samsung.com',
        'sap.com', 'sciencedirect.com', 'scopus.com', 'sears.com', 'sharepoint.com', 'shutterstock.com', 'siemens.com',
        'sketch.com', 'skillshare.com', 'skype.com', 'slack.com', 'sony.com', 'soundcloud.com', 'spotify.com', 'spring.io',
        'stackoverflow.com', 'steamcommunity.com', 'steampowered.com', 'surveymonkey.com', 'symantec.com', 'target.com',
        'techcrunch.com', 'temu.com', 'tesla.com', 'texasinstruments.com', 'theguardian.com', 'thenextweb.com', 'theverge.com',
        'tiktok.com', 'time.com', 'toyota.com', 'trello.com', 'trip.com', 'tripadvisor.com', 'tumblr.com', 'twitch.tv',
        'twitter.com', 'uber.com', 'ucla.edu', 'ucsf.edu', 'udemy.com', 'unity.com', 'unsplash.com', 'ups.com', 'usatoday.com',
        'usnews.com', 'usps.com', 'verizon.com', 'Vice.com', 'vice.com', 'vimeo.com', 'vk.com', 'vmware.com', 'volkswagen.com',
        'vox.com', 'walmart.com', 'washingtonpost.com', 'weather.com', 'weather.gov', 'webmd.com', 'whatsapp.com', 'wikimedia.org',
        'wikipedia.org', 'wired.com', 'wordpress.com', 'wsj.com', 'wunderground.com', 'x.com', 'xerox.com', 'xfinity.com',
        'yahoo.com', 'yelp.com', 'youtube.com', 'zapier.com', 'zendesk.com', 'zeplin.iozillow.com', 'zoom.us'
];

(function() {
    'use strict';

    console.log('Script initialization started.');

    /**
     * Get the current automated blacklist
     * @returns {Set} The automated blacklist
     */
    function getAutomatedBlacklist() {
        return new Set(GM_getValue('blacklist', []));
    }

    /**
     * Add a URL to the automated blacklist
     * @param {string} url - The URL to add to the blacklist
     */
    function addToAutomatedBlacklist(url) {
        const encodedUrl = encodeURIComponent(url);
        const blacklist = getAutomatedBlacklist();
        if (!blacklist.has(encodedUrl)) {
            blacklist.add(encodedUrl);
            GM_setValue('blacklist', Array.from(blacklist));
            console.log('Added to automated blacklist:', url);
        }
    }

    /**
     * Check if navigation to a URL is allowed
     * @param {string} url - The URL to check
     * @returns {boolean} True if navigation is allowed, false otherwise
     */
    function isNavigationAllowed(url) {
        if (!isUrlBlocked(url)) {
            console.log('Navigation allowed to:', url);
            lastKnownGoodUrl = url;
            return true;
        } else {
            console.error('Blocked navigation to:', url);
            addToAutomatedBlacklist(url);
            if (lastKnownGoodUrl) {
                window.location.replace(lastKnownGoodUrl);
            }
            return false;
        }
    }

    const originalAssign = window.location.assign.bind(window.location);
    const originalOpen = window.open;

    console.log('Original window.location.assign and window.open saved.');

    window.location.assign = function(url) {
        console.log('Redirect attempt detected:', url);
        if (!allowedPopups.some(domain => url.includes(domain)) && !isNavigationAllowed(url)) {
            console.log('Redirect to undesired domain blocked:', url);
            return;
        }
        console.log('Redirect allowed to:', url);
        return originalAssign(url);
    };

    console.log('window.location.assign overridden with custom logic.');

    window.open = function(url, name, features) {
        console.log('Popup attempt detected:', url);
        if (allowedPopups.some(domain => url.includes(domain)) || isNavigationAllowed(url)) {
            console.log('Popup allowed for:', url);
            return originalOpen(url, name, features);
        }
        console.log('Blocked a popup from:', url);
        return null;
    };

    console.log('window.open overridden with custom logic.');

    let lastKnownGoodUrl = window.location.href;

    const locationProxy = new Proxy(window.location, {
        set(target, prop, value) {
            if (prop === 'href' || prop === 'assign' || prop === 'replace') {
                if (!isNavigationAllowed(value)) {
                    return false;
                }
            }
            return Reflect.set(target, prop, value);
        },
        get(target, prop) {
            if (prop === 'assign' || prop === 'replace') {
                return function(url) {
                    if (isNavigationAllowed(url)) {
                        return target[prop].call(target, url);
                    }
                };
            }
            return Reflect.get(target, prop);
        }
    });

    Object.defineProperty(window, 'location', {
        configurable: true,
        enumerable: true,
        get() {
            return locationProxy;
        }
    });

    window.addEventListener('popstate', function(event) {
        if (!isNavigationAllowed(window.location.href)) {
            console.error('Blocked navigation to:', window.location.href);
            history.pushState(null, "", lastKnownGoodUrl);
            window.location.replace(lastKnownGoodUrl);
            event.preventDefault();
        }
    });

    /**
     * Handle history manipulation
     * @param {Function} originalMethod - The original history method
     * @param {*} data - The state data
     * @param {string} title - The page title
     * @param {string|null} url - The URL
     * @returns {*} The result of calling the original method
     */
    function handleHistoryManipulation(originalMethod, data, title, url) {
        if (!isUrlBlocked(url)) {
            return originalMethod.call(history, data, title, url);
        }
        console.error('Blocked history manipulation to:', url);
    }

    const originalPushState = history.pushState;
    const originalReplaceState = history.replaceState;

    history.pushState = function(data, title, url) {
        return handleHistoryManipulation(originalPushState, data, title, url);
    };

    history.replaceState = function(data, title, url) {
        return handleHistoryManipulation(originalReplaceState, data, title, url);
    };

    /**
     * Check if a URL is blocked based on the blacklist
     * @param {string} url - The URL to check
     * @returns {boolean} True if the URL is blocked, false otherwise
     */
    function isUrlBlocked(url) {
        const encodedUrl = encodeURIComponent(url);
        const automatedBlacklist = getAutomatedBlacklist();
        const isBlocked = [...manualBlacklist, ...automatedBlacklist].some(blockedUrl => encodedUrl.includes(blockedUrl));
        if (isBlocked) {
            console.log(`Blocked URL: ${url}`);
        }
        return isBlocked;
    }

    console.log('Redirect control script with blacklist initialized.');
})();