Chop Labalagun
Chop Labalagun

Reputation: 612

How to make a ViolentMokey userScript into a Browser Extension?

I have been trying to migrate an userScript into my own extension but for some reason I am not able to run the following code:

// ==/UserScript==
console.info('BEFORE Hooked! MONKEY');
(function() {
    'use strict';
    // Reference [Augular loaded detect]: https://stackoverflow.com/a/31970556/9182265
    var initWatcher = setInterval(function () {
        if (window.MegaUtils) {
            console.info(window.MegaUtils);
            clearInterval(initWatcher);
            hookImport();
            hookFull();
            console.info('FUNtions Hooked! MONKEY');
        }
    }, 500);
})();

But for some reason the IF statement is never TRUE, but the same exact code is run from ViolentMonkey, it works right away.

So window.MegaUtils is not been detected at all and i have no idea why. I was told that my extension might not have access to the DOM object but why ViolentMonkey does have access to it.

This is the manifest i am using when importing the extension in Chrome:

{
    "manifest_version": 2,
    "content_scripts": [ {
        "exclude_globs":    [  ],
        "include_globs":    [ "*" ],
        "js":               [ "mega.user.js" ],
        "matches":          [   "https://mega.nz/*",
                                "http://mega.nz/*" ],
        "run_at": "document_end"
    } ],
    "converted_from_user_script": true,
    "description":  "testing extension",
    "permissions": [],
    "name":         "MegaByPass",
    "icons": {
        "16": "images/mega-cloud-icon.png",
        "32": "images/mega-cloud-icon.png",
        "48": "images/download.png",
        "128": "images/873133.png"
      },
    "version":      "1.0"
}

source

Thanks in advance.

Upvotes: 3

Views: 4104

Answers (2)

cougarten
cougarten

Reputation: 1

I'm pretty sure user_script instead of content_script is the way to go.

This API offers similar capabilities to contentScripts but with features suited to handling third-party scripts:

  • access to the window and document global values related to the webpage the user script is attached to.

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts

It works a bit different though, still trying to understand it :)

Upvotes: 0

erosman
erosman

Reputation: 7721

To start with, remove the glob as it can cause issues.

"content_scripts": [
  {
    "matches": ["http://mega.nz/*", "https://mega.nz/*"],
    "js": ["mega.user.js"]
  }
]

ViolentMonkey injects by default at document-end. However, GM/VM/TM inject user-scripts manually and not using the dedicated API (FireMonkey in Firefox uses dedicated API), therefore the injection time may be later than when browser API injects.

Try with "document_idle" which is the default (you can leave it out).

Using "document_end" may result in the script running before the external Angualr is loaded and that can be the reason for the issue.

For proper testing, the actual extension is needed.

Update 1

Content scripts are injected into a different scope/context than the page that they are in. Therefore they can not directly interact with JS on the page and vice versa.

The global window behaviour is not uniform between different browsers (e.g. eval() in chrome always run in the context of the content script but in Firefox eval() runs in content scope but window.eval() in page scope).

After a quick testing, the content script doesn't have access to the global window & window.MegaUtils. There are ways to fix that but why the user-script works may have something to do with the way ViolentMonkey inject it or grants access to window object without using unsafewindow.

Have you tested the script with any other script managers?!! Does the script work on all script managers or only ViolentMonkey?

More Info:
Accessing all the window variables of the current tab in chrome extension
Insert code into the page context using a content script

PS. I only tested on Firefox as I don't use Chrome.

Update 2

Looking at Can't find page variables when used GM_ functions, it appears that GM|TM|VM may be injecting user-scripts into the page contents when there is @grant none (needs proper confirmation). That would explain why above user-script with @grant none works and can get window.MegaUtils in GM|TM|VM (not FM). In that case you would need to inject the script in the page JS.

Here is an example:

const script = document.createElement('script');
script.textContent = `(function() {
    'use strict';
    // Reference [Augular loaded detect]: https://stackoverflow.com/a/31970556/9182265
    var initWatcher = setInterval(function () {
        if (window.MegaUtils) {
            clearInterval(initWatcher);
            hookImport();
            hookFull();
            console.info('FUNtions Hooked!');
        }
    }, 500);
})();

....`;
document.body.appendChild(script);

Update 3 CSP

At the moment, browsers adhere to page CSP (Content Security Policy) which is the issue you refereed to in the comment.
ref:
[meta] Page CSP should not apply to content inserted by content scripts (V2 issue)
CSP 'sandbox' directive prevents content scripts from matching, due to unique origin, breaking also browser features [Screenshots]

There are ways around that but they are not standard and extensions shouldn't circumvent browser or page CSP.

Upvotes: 1

Related Questions