How is unsafeWindow implemented by user script extensions?
F

1

7

Today I came across a situation where I need to make an extension to monkey-patch some objects in a web page.

However I found little to none documentation on how it can actually be achieved, I've tried using the userScripts API (currently exclusive to Firefox) but the window object is contextually isolated from the window on the HTML DOM of the page.

I know that this is possible because user script managers like GreaseMonkey implement an unsafeWindow object which gives the script direct access to objects in the unisolated context of the web page, thus making monkey-patching very easy.

So I would like to know how this is actually achieved. I've attempted to study the source code of an user script manager called ViolentMonkey, I found that it defines unsafeWindow in src/injected/web/gm-api-wrapper.js:53 as a reference to the global object but I could not locate where this in turn is defined in the source code.

I know that this is not implemented by simply injecting a <script> element in the page because none is visible in the page's DOM upon my inspection.

I'm very curious about the implementation of this cool mechanism, I'm pretty sure I missed something obvious so I need your help to remove my blind-folds!

Flagrant answered 28/6, 2022 at 21:18 Comment(1)
In Firefox you should use wrappedJSObject to access the page context and exportFunction to expose your code into the page context. See Monkey patch getUserMedia in a WebExtension?Rhythmical
U
-1

What you need to do is basically load the DOM and modify the content injecting Content Scripts.

For example to modify the following HTML:

<html>
     <button id="mybutton">click me</button>
     <script>
        var greeting = "hello, ";
        var button = document.getElementById("mybutton");
        button.person_name = "Bob";
        button.addEventListener(
            "click", () => alert(greeting + button.person_name + "."), false);
      </script>
</html>

You can inject this code:

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener(
    "click", () => alert(greeting + button.person_name + "."), false);

You can inject the script with dynamic or static declarations on a Chrome extension.

Here is a sample manifest.json using static declarations:

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["https://*.nytimes.com/*"],
     "css": ["my-styles.css"],
     "js": ["content-script.js"]
   }
 ],
 ...
}

In addition, you can check [Chrome extension's docs] for more information.

Ulric answered 1/8, 2023 at 20:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.