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 Comments

  1. Bill said,

    March 18, 2008 @ 5:00 pm

    Is there a bug # associated with this change?

  2. zeniko said,

    March 18, 2008 @ 5:29 pm

    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…

  3. Simon said,

    March 18, 2008 @ 6:07 pm

    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?

  4. Boris said,

    March 18, 2008 @ 6:13 pm

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

  5. mrtech said,

    March 18, 2008 @ 6:17 pm

    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?

  6. Michael Kaply said,

    March 18, 2008 @ 6:45 pm

    This breaks Operator big time.

    Basically I can’t allow people to download user scripts and then load them on the fly…

  7. Michael Kaply said,

    March 18, 2008 @ 6:47 pm

    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)

  8. Andreas Wuest said,

    March 18, 2008 @ 7:09 pm

    > 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.

  9. François de Metz said,

    March 19, 2008 @ 4:15 am

    We use mosJSSubScriptLoader to load js files in directory profile. These files are updated in a different way of extension.

    It also breaks MozUnit extension.

  10. Dennis said,

    March 19, 2008 @ 6:37 am

    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.

  11. John J. Barton said,

    March 19, 2008 @ 3:40 pm

    If you switch to import you might hit the bug I hit:
    https://bugzilla.mozilla.org/show_bug.cgi?id=421392
    So far it seems to be specific to my extension.
    John

  12. Mark Finkle said,

    March 19, 2008 @ 7:42 pm

    @mkaply and @dennis: Extensions can now register their own resource: aliases. See these MDC articles:
    http://developer.mozilla.org/en/docs/Chrome_Registration#resource
    http://developer.mozilla.org/en/docs/Using_JavaScript_code_modules

  13. Samuel Sieb said,

    March 20, 2008 @ 1:48 am

    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?

  14. Justin Wood (Callek) said,

    March 20, 2008 @ 2:06 am

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

  15. Massimiliano Mirra said,

    March 20, 2008 @ 9:56 am

    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. :-)

  16. Massimiliano Mirra said,

    March 20, 2008 @ 10:03 am

    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).

  17. DigDug said,

    March 20, 2008 @ 1:30 pm

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

  18. Shinya Kasatani said,

    March 21, 2008 @ 4:10 am

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

  19. Nils Maier said,

    March 21, 2008 @ 3:09 pm

    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?

  20. Mark Finkle’s Weblog » Extension Developers - Unbreaking News, Part 2 said,

    March 22, 2008 @ 12:32 am

    […] love reporting “unbreaking news” and I have some report. I posted about a security change (bug 418356) to mozIJSSubScriptLoader that broke loading scripts from any […]

  21. Boris said,

    March 22, 2008 @ 8:55 pm

    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.

RSS feed for comments on this post