You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm trying to write a Userscript to change the behavior of websites by monkey-patching the built-in JavaScript functions, for example, replacing them with my custom versions to intercept their actions. This requires one to execute the Userscript before everything else. Unfortunately, I found even with @run-at document-start, early JavaScript function calls cannot be intercepted, since the Userscript is still running too late.
Demo
To replicate this problem, I selected the JavaScript alert() function as a demo. First, save the following webpage as test.html:
Then save the following Userscript as intercept-alert.user.js, which monkey-patches the JavaScript "alert()` function with a custom version:
// ==UserScript==
// @name Intercept Test
// @version 1
// @run-at document-start
// @include http://127.0.0.1:8000/*
// @grant none
// ==/UserScript==
function monkeyPatch() {
let realAlert = window.alert;
window.alert = function(text) {
realAlert("alert has been intercepted: " + text);
}
}
// inject the monkey patch into DOM
var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ monkeyPatch +')();'));
(document.body || document.head || document.documentElement).appendChild(script);
Open the webpage, you would see that the Userscript cannot intercept the alert("Early call!");, only the alert("Late call!"); can be intercepted.
Discussion
In fact, one can also replicate this problem with TamperMonkey and ViolentMonkey on Chromium. To overcome this problem, both plugins implemented a workaround. TamperMonkey calls it "inject mode: instant", and ViolentMonkey calls it "Synchronous page mode`.
ViolentMonkey's description is:
Runs scripts at the real <document-start> reliably. Don't enable unless you do have a script that needs to run before the page starts loading and Violentmonkey is currently running it too late. This mode will be using the deprecated synchronous XHR so you'll see warnings in devtools console, although you can safely ignore them as the adverse affects it warns about are negligible in this case and you can hide the warnings for good by right-clicking one.
The workaround basically abuses document.cookie and a synchronous XMLHttpRequest call in a tricky way in order to force the browser to run the scripts in a synchronous manner, ensuring that the Userscript runs before everything else.
The background script makes a Blob in the background script with the data, gets its URL via URL.createObjectURL, puts it into a Set-Cookie header via chrome.webRequest API.
The content script reads the URL from document.cookie and uses it in a synchronous XMLHttpRequest to get the original data synchronously.
Is it possible to implement the same feature in quoid/userscripts? Or is there an alternative method to monkey-patch and intercept JavaScript function without this limitation?
The text was updated successfully, but these errors were encountered:
biergaizi
changed the title
Early JavaScript code cannot be intercepted even with "@run-at document-start"
Early JavaScript code cannot be intercepted even with "@run-at document-start", Need "Instant" Injection Mode.
Mar 30, 2023
biergaizi
changed the title
Early JavaScript code cannot be intercepted even with "@run-at document-start", Need "Instant" Injection Mode.
Early JavaScript code cannot be intercepted even with "@run-at document-start", "Instant" Injection Mode Needed
Mar 30, 2023
biergaizi
changed the title
Early JavaScript code cannot be intercepted even with "@run-at document-start", "Instant" Injection Mode Needed
Early JavaScript code cannot be intercepted even with "@run-at document-start", "Instant" injection mode needed
Mar 30, 2023
Thanks for the feedback. Apple strictly restricts the API related to cookies, and as far as we know, it is impossible to achieve the same trick. Duplicate issue #184
I'm trying to write a Userscript to change the behavior of websites by monkey-patching the built-in JavaScript functions, for example, replacing them with my custom versions to intercept their actions. This requires one to execute the Userscript before everything else. Unfortunately, I found even with
@run-at document-start
, early JavaScript function calls cannot be intercepted, since the Userscript is still running too late.Demo
To replicate this problem, I selected the JavaScript
alert()
function as a demo. First, save the following webpage astest.html
:Then save the following Userscript as
intercept-alert.user.js
, which monkey-patches the JavaScript "alert()` function with a custom version:Open the webpage, you would see that the Userscript cannot intercept the
alert("Early call!");
, only thealert("Late call!");
can be intercepted.Discussion
In fact, one can also replicate this problem with TamperMonkey and ViolentMonkey on Chromium. To overcome this problem, both plugins implemented a workaround. TamperMonkey calls it "inject mode: instant", and ViolentMonkey calls it "Synchronous
page
mode`.ViolentMonkey's description is:
The workaround basically abuses
document.cookie
and a synchronousXMLHttpRequest
call in a tricky way in order to force the browser to run the scripts in a synchronous manner, ensuring that the Userscript runs before everything else.The source code of ViolentMonkey's implementation is available here: violentmonkey/violentmonkey#1100
Is it possible to implement the same feature in quoid/userscripts? Or is there an alternative method to monkey-patch and intercept JavaScript function without this limitation?
The text was updated successfully, but these errors were encountered: