0

Overview

This MutationObserver Wrapper should be able to provide developers with any changes that have been made in the DOM for security reasons.

Problem

I need a simple way to create a wrapper for MutationObserver. I just want to be informed when a MutationObserver was created on the page. Then I want to make sure the code runs before all other codes so that I can put it in an extension.

Code

This is what I tried:


const dump = console.log.bind(console);



    class Observer
    {
        static started = false
        static jacked = {}


        static start()
        {
            Observer.started = true;

            Observer.hijack( MutationObserver,  function constructor()
            {
                alert("CAREFUL!! - MutationObserver is running here!");

                return (Observer.jacked.MutationObserver).constructor.apply(this, [...arguments]);
            });

            // if (!Observer.fixes[document.domain])
            // {
            //     dump("not listining on: "+document.domain);
            //     return;
            // };
            //
            // Observer.fixes[document.domain]()
        }



        static hijack(target, impose)
        {
            let waiting = setInterval(()=>
            {
                if ((typeof target.prototype) !== "object"){ return };
                if ((typeof target.prototype.constructor) !== "function"){ return };

                clearInterval(waiting);
                let name = target.prototype.constructor.name;
                dump("hijacking: "+name);
                Observer.jacked[name] = target;
                Object.defineProperty(target.prototype, "constructor", {writable:false, configurable:false, enumerable:false, value:impose});
            },0);
        }





    let waiting = setInterval(() =>
    {
        let exists = ((typeof MutationObserver) !== "undefined");

        if ( !exists )
        {
            console.log("observer waiting for `MutationObserver`");
            return
        };

        if ( Observer.started )
        {
            clearInterval(waiting);
            console.log("observer already started .. exiting");
            return
        };

        clearInterval(waiting);
        Observer.start();
    }, 0);


Lusi
  • 39
  • 3
  • I don't get why you expect `typeof MutationObserver` to be `"undefined"`? – Bergi Feb 04 '23 at 19:44
  • 1
    I don't get what the problem is or what you are trying to do. Also what do you mean by "*for security reasons*"? Where does this code execute, and what is it supposed to guard against? What is your threat model? – Bergi Feb 04 '23 at 19:46
  • It's unclear what the problem is aside from this code being overengineered. Note that in an extension you'll need to run this code in [page context](/a/9517879) (Chrome) or via wrappedJSObject + exportFunction (Firefox). – wOxxOm Feb 05 '23 at 11:43

1 Answers1

1

Try something like this, however, be aware of what globalThis refers to in your extension:

    const jacked = {};

    jacked.MutationObserver = globalThis.MutationObserver;

    delete globalThis.MutationObserver;

    globalThis.MutationObserver = (class MutationObserver 
    {
        constructor()
        {
            console.log("jacked");
        }

        observe()
        {
            console.log("busy");
        }
    });

after running the above, anywhere, like in a function, you can test if your wrapper-test works like this:

    let watcher = (new MutationObserver(function(){}));
    watcher.observe();

You can use jacked to resume normal operation inside your supplementary class constructor by returning a new jacked.MutationObserver.

argon
  • 449
  • 4
  • 11