Stop Nefarious Redirects

Block unauthorized redirects and prevent history manipulation

当前为 2024-05-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Stop Nefarious Redirects
  3. // @namespace http://tampermonkey.net/
  4. // @version 4.1
  5. // @description Block unauthorized redirects and prevent history manipulation
  6. // @match http://*/*
  7. // @match https://*/*
  8. // @grant GM_setValue
  9. // @grant GM_getValue
  10. // @grant GM_xmlhttpRequest
  11. // @license MIT
  12. // @run-at document-start
  13. // ==/UserScript==
  14.  
  15. const manualBlacklist = new Set([
  16. 'getrunkhomuto.info'
  17. ]);
  18.  
  19. const allowedPopups = [
  20. '500px.com', 'accuweather.com', 'adobe.com', 'adulttime.com', 'alibaba.com', 'amazon.com', 'amazonaws.com',
  21. /* ... */
  22. 'zeplin.iozillow.com', 'zoom.us'
  23. ];
  24.  
  25. (function() {
  26. 'use strict';
  27.  
  28. console.log('Script initialization started.');
  29.  
  30. /**
  31. * Get the current automated blacklist
  32. * @returns {Set} The automated blacklist
  33. */
  34. function getAutomatedBlacklist() {
  35. return new Set(GM_getValue('blacklist', []));
  36. }
  37.  
  38. /**
  39. * Add a URL to the automated blacklist
  40. * @param {string} url - The URL to add to the blacklist
  41. */
  42. function addToAutomatedBlacklist(url) {
  43. const encodedUrl = encodeURIComponent(url);
  44. const blacklist = getAutomatedBlacklist();
  45. if (!blacklist.has(encodedUrl)) {
  46. blacklist.add(encodedUrl);
  47. GM_setValue('blacklist', Array.from(blacklist));
  48. console.log('Added to automated blacklist:', url);
  49. }
  50. }
  51.  
  52. /**
  53. * Check if navigation to a URL is allowed
  54. * @param {string} url - The URL to check
  55. * @returns {boolean} True if navigation is allowed, false otherwise
  56. */
  57. function isNavigationAllowed(url) {
  58. if (!isUrlBlocked(url)) {
  59. console.log('Navigation allowed to:', url);
  60. lastKnownGoodUrl = url;
  61. return true;
  62. } else {
  63. console.error('Blocked navigation to:', url);
  64. addToAutomatedBlacklist(url);
  65. if (lastKnownGoodUrl) {
  66. window.location.replace(lastKnownGoodUrl);
  67. }
  68. return false;
  69. }
  70. }
  71.  
  72. const originalAssign = window.location.assign.bind(window.location);
  73. const originalOpen = window.open;
  74.  
  75. console.log('Original window.location.assign and window.open saved.');
  76.  
  77. window.location.assign = function(url) {
  78. console.log('Redirect attempt detected:', url);
  79. if (!allowedPopups.some(domain => url.includes(domain)) && !isNavigationAllowed(url)) {
  80. console.log('Redirect to undesired domain blocked:', url);
  81. return;
  82. }
  83. console.log('Redirect allowed to:', url);
  84. return originalAssign(url);
  85. };
  86.  
  87. console.log('window.location.assign overridden with custom logic.');
  88.  
  89. window.open = function(url, name, features) {
  90. console.log('Popup attempt detected:', url);
  91. if (allowedPopups.some(domain => url.includes(domain)) || isNavigationAllowed(url)) {
  92. console.log('Popup allowed for:', url);
  93. return originalOpen(url, name, features);
  94. }
  95. console.log('Blocked a popup from:', url);
  96. return null;
  97. };
  98.  
  99. console.log('window.open overridden with custom logic.');
  100.  
  101. let lastKnownGoodUrl = window.location.href;
  102.  
  103. const locationProxy = new Proxy(window.location, {
  104. set(target, prop, value) {
  105. if (prop === 'href' || prop === 'assign' || prop === 'replace') {
  106. if (!isNavigationAllowed(value)) {
  107. return false;
  108. }
  109. }
  110. return Reflect.set(target, prop, value);
  111. },
  112. get(target, prop) {
  113. if (prop === 'assign' || prop === 'replace') {
  114. return function(url) {
  115. if (isNavigationAllowed(url)) {
  116. return target[prop].call(target, url);
  117. }
  118. };
  119. }
  120. return Reflect.get(target, prop);
  121. }
  122. });
  123.  
  124. Object.defineProperty(window, 'location', {
  125. configurable: true,
  126. enumerable: true,
  127. get() {
  128. return locationProxy;
  129. }
  130. });
  131.  
  132. window.addEventListener('popstate', function(event) {
  133. if (!isNavigationAllowed(window.location.href)) {
  134. console.error('Blocked navigation to:', window.location.href);
  135. history.pushState(null, "", lastKnownGoodUrl);
  136. window.location.replace(lastKnownGoodUrl);
  137. event.preventDefault();
  138. }
  139. });
  140.  
  141. /**
  142. * Handle history manipulation
  143. * @param {Function} originalMethod - The original history method
  144. * @param {*} data - The state data
  145. * @param {string} title - The page title
  146. * @param {string|null} url - The URL
  147. * @returns {*} The result of calling the original method
  148. */
  149. function handleHistoryManipulation(originalMethod, data, title, url) {
  150. if (!isUrlBlocked(url)) {
  151. return originalMethod.call(history, data, title, url);
  152. }
  153. console.error('Blocked history manipulation to:', url);
  154. }
  155.  
  156. const originalPushState = history.pushState;
  157. const originalReplaceState = history.replaceState;
  158.  
  159. history.pushState = function(data, title, url) {
  160. return handleHistoryManipulation(originalPushState, data, title, url);
  161. };
  162.  
  163. history.replaceState = function(data, title, url) {
  164. return handleHistoryManipulation(originalReplaceState, data, title, url);
  165. };
  166.  
  167. /**
  168. * Check if a URL is blocked based on the blacklist
  169. * @param {string} url - The URL to check
  170. * @returns {boolean} True if the URL is blocked, false otherwise
  171. */
  172. function isUrlBlocked(url) {
  173. const encodedUrl = encodeURIComponent(url);
  174. const automatedBlacklist = getAutomatedBlacklist();
  175. const isBlocked = [...manualBlacklist, ...automatedBlacklist].some(blockedUrl => encodedUrl.includes(blockedUrl));
  176. if (isBlocked) {
  177. console.log(`Blocked URL: ${url}`);
  178. }
  179. return isBlocked;
  180. }
  181.  
  182. console.log('Redirect control script with blacklist initialized.');
  183. })();