Extension Developers – Breaking News, Part 2

If you have an extension that uses mozIJSSubScriptLoader (a mouthful, I know) then you should be aware of a recent change (bug 418356). The mozIJSSubScriptLoader interface can be used from JS to load and run JavaScript code from the given URL at run-time. Previously, the URL could be chrome:, file:, data: or resource:, but due to a security fix, the URL is now limited to chrome: only.

Therefore, this will no longer work:

var obj = {};
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
                       .getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("file:///blah.js", obj)

Instead, try moving the JS file into a chrome area and use chrome: or you can try to refactor your code to use Components.utils.import and a resource: URL. Firefox 3 has new ways for extensions to define resource: aliases in chrome manifests, which will make the refactor easier.

Components.utils.import("resource://myext/modules/blah.jsm");

Let me know if there is a reason this change or workaround is completely unacceptable to you.

21 Replies to “Extension Developers – Breaking News, Part 2”

  1. As already asked over IRC: Does a clean way to load code dynamically remain (e.g. from user input or from a pref)? eval’ing might have unwanted side effects WRT closures and saving the JS snippet to a file in a jar-less extension’s directory so that it gets accessible through a chrome: URL just to delete it right afterwards sounds like a chore…

  2. Mark, I already posted this to mozilla.dev.security, but will also say it here:

    This completely broke the Calendar apps (Lightning extension, Sunbird application) on trunk (see 423727). This isn’t a huge deal for us right now, since we’re currently developing primarily on the 1.8 branch, but it will become a problem, if that patch gets ported to the 1.8 branch.

    So, is porting this patch to the 1.8 branch in the works?

  3. Note that this may not be the final word on how things will work… We might allow non-chrome URIs with some restrictions.

  4. this add yet another set of hiccups, here’s my dilemma, I use mozIJSSubScriptLoader to import previously exported preferences that I wrapped with nsPreferences calls. How can I mimic the same functionality? I have this type of functionality in two or three extensions, but here’s a sample export that a user would manually export or import:

    nsPreferences.setBoolPref(‘local_install.ToolsThemes’, false);
    nsPreferences.setBoolPref(‘local_install.addonsEnabled’, true);
    nsPreferences.setUnicharPref(‘local_install.addons_view_override’, ‘installs’);

    this was generated by using getBranch, getPrefType and values and is easily imported and customizable. Do I need to re-eng this to be a simple list and manually parse through it?

  5. Also, I didn’t think this syntax worked:

    Components.utils.import(“resource://myext/modules/blah.jsm”);

    As in you can’t load JS components from extensions (I could be wrong)

  6. > Let me know if there is a reason this change or workaround is
    > completely unacceptable to you.

    We are using the jssubscript-loader to load testcases into our unit-test framework. Since the location of those testcases must be configurable, testcases may well lie beyond chrome’s reach. And since this should be configurable dynamically, we can’t simply modify chrome.manifests.

    If there was a way to fix the security issue at hand but continue to be able to use non-chrome URIs (under certain conditions), then the jssubscript-loader’s needed flexibility could be retained.

  7. I’ve tried registering a resource: from my extension, and couldn’t get it to work.
    I’m now using the __LOCATION__ variable to create a file:// uri programmatically and use that in Components.utils.import(”file://myext/modules/blah.jsm”);
    I’d rather use a resource: but i cant seem to find any example of an extension doing that.
    Songbird and other xul apps are creating their own resource: aliases.
    But i dont think those methods are available to extension authors since they (songbird) provide a complete set of modified chrome. Extension authors can only use a chrome.manifest.

  8. This breaks the ability to use plugins in ChatZilla. I guess we could work around it by setting up a resource url location and forcing users to put the plugins in there, but that’s unpleasant. Also, are resource: urls cached?

  9. Chatzilla is said to be broken because of this (the chatzilla “plugins” feature anyway)

  10. I develop MozRepl, MozUnit, and SamePlace, and this breaks loading JavaScript files in MozRepl, loading testcases in MozUnit, and loading scriptlets in SamePlace. But hey, could be worse — could be raining. 🙂

  11. Correction: this doesn’t just break loading files in MozRepl, it breaks it completely, as code typed at the prompt is sent via data: URI (and couldn’t alternatively be eval’ed, since eval() no longer support evaluation in a given context).

  12. This broke APNGEdit. I don’t think its possible for it to load external scripts from “resource” directories either.

  13. Selenium IDE also uses jssubscript-loader to load user-defined extensions from file:// URLs.

  14. This appears to be a rather strange and pointless change as this affects only code that is trusted anyway and can do whatever it wants in the user context (untrusted code doesn’t have access to C.classes).
    So at the moment it appears that this breaks a lot of extensions/applications and nothing more. Is there any *public* information on why these changes are indeed necessary?

  15. To answer Nils’ question, yes, the _calling_ code can already do anything it wants to. But the _called_ code can as well. Before this change, unless the called code was extremely careful (much more careful than extension code usually has to be), it was exploitable. Furthermore, if the calling code loaded something it didn’t expect (by accident, error, whatever), things were really bad.

Comments are closed.