services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rw-r--r--

Correct small whitespace inconsistency, lost while renaming variables.

     1 /* ***** BEGIN LICENSE BLOCK *****
     2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
     3  *
     4  * The contents of this file are subject to the Mozilla Public License Version
     5  * 1.1 (the "License"); you may not use this file except in compliance with
     6  * the License. You may obtain a copy of the License at
     7  * http://www.mozilla.org/MPL/
     8  *
     9  * Software distributed under the License is distributed on an "AS IS" basis,
    10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    11  * for the specific language governing rights and limitations under the
    12  * License.
    13  *
    14  * The Original Code is Jetpack.
    15  *
    16  * The Initial Developer of the Original Code is Mozilla.
    17  * Portions created by the Initial Developer are Copyright (C) 2007
    18  * the Initial Developer. All Rights Reserved.
    19  *
    20  * Contributor(s):
    21  *   Atul Varma <atul@mozilla.com>
    22  *
    23  * Alternatively, the contents of this file may be used under the terms of
    24  * either the GNU General Public License Version 2 or later (the "GPL"), or
    25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    26  * in which case the provisions of the GPL or the LGPL are applicable instead
    27  * of those above. If you wish to allow use of your version of this file only
    28  * under the terms of either the GPL or the LGPL, and not to allow others to
    29  * use your version of this file under the terms of the MPL, indicate your
    30  * decision by deleting the provisions above and replace them with the notice
    31  * and other provisions required by the GPL or the LGPL. If you do not delete
    32  * the provisions above, a recipient may use your version of this file under
    33  * the terms of any one of the MPL, the GPL or the LGPL.
    34  *
    35  * ***** END LICENSE BLOCK ***** */
    37 (function(global) {
    38    const Cc = Components.classes;
    39    const Ci = Components.interfaces;
    40    const Cu = Components.utils;
    41    const Cr = Components.results;
    43    var exports = {};
    45    var ios = Cc['@mozilla.org/network/io-service;1']
    46              .getService(Ci.nsIIOService);
    48    var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
    49                          .createInstance(Ci.nsIPrincipal);
    51    function resolvePrincipal(principal, defaultPrincipal) {
    52      if (principal === undefined)
    53        return defaultPrincipal;
    54      if (principal == "system")
    55        return systemPrincipal;
    56      return principal;
    57    }
    59    // The base URI to we use when we're given relative URLs, if any.
    60    var baseURI = null;
    61    if (global.window)
    62      baseURI = ios.newURI(global.location.href, null, null);
    63    exports.baseURI = baseURI;
    65    // The "parent" chrome URI to use if we're loading code that
    66    // needs chrome privileges but may not have a filename that
    67    // matches any of SpiderMonkey's defined system filename prefixes.
    68    // The latter is needed so that wrappers can be automatically
    69    // made for the code. For more information on this, see
    70    // bug 418356:
    71    //
    72    // https://bugzilla.mozilla.org/show_bug.cgi?id=418356
    73    var parentChromeURIString;
    74    if (baseURI)
    75      // We're being loaded from a chrome-privileged document, so
    76      // use its URL as the parent string.
    77      parentChromeURIString = baseURI.spec;
    78    else
    79      // We're being loaded from a chrome-privileged JS module or
    80      // SecurableModule, so use its filename (which may itself
    81      // contain a reference to a parent).
    82      parentChromeURIString = Components.stack.filename;
    84    function maybeParentifyFilename(filename) {
    85      var doParentifyFilename = true;
    86      try {
    87        // TODO: Ideally we should just make
    88        // nsIChromeRegistry.wrappersEnabled() available from script
    89        // and use it here. Until that's in the platform, though,
    90        // we'll play it safe and parentify the filename unless
    91        // we're absolutely certain things will be ok if we don't.
    92        var filenameURI = ios.newURI(options.filename,
    93                                     null,
    94                                     baseURI);
    95        if (filenameURI.scheme == 'chrome' &&
    96            filenameURI.path.indexOf('/content/') == 0)
    97          // Content packages will always have wrappers made for them;
    98          // if automatic wrappers have been disabled for the
    99          // chrome package via a chrome manifest flag, then
   100          // this still works too, to the extent that the
   101          // content package is insecure anyways.
   102          doParentifyFilename = false;
   103      } catch (e) {}
   104      if (doParentifyFilename)
   105        return parentChromeURIString + " -> " + filename;
   106      return filename;
   107    }
   109    function getRootDir(urlStr) {
   110      // TODO: This feels hacky, and like there will be edge cases.
   111      return urlStr.slice(0, urlStr.lastIndexOf("/") + 1);
   112    }
   114    exports.SandboxFactory = function SandboxFactory(defaultPrincipal) {
   115      // Unless specified otherwise, use a principal with limited
   116      // privileges.
   117      this._defaultPrincipal = resolvePrincipal(defaultPrincipal,
   118                                                "http://www.mozilla.org");
   119    },
   121    exports.SandboxFactory.prototype = {
   122      createSandbox: function createSandbox(options) {
   123        var principal = resolvePrincipal(options.principal,
   124                                         this._defaultPrincipal);
   126        return {
   127          _sandbox: new Cu.Sandbox(principal),
   128          _principal: principal,
   129          get globalScope() {
   130            return this._sandbox;
   131          },
   132          defineProperty: function defineProperty(name, value) {
   133            this._sandbox[name] = value;
   134          },
   135          getProperty: function getProperty(name) {
   136            return this._sandbox[name];
   137          },
   138          evaluate: function evaluate(options) {
   139            if (typeof(options) == 'string')
   140              options = {contents: options};
   141            options = {__proto__: options};
   142            if (typeof(options.contents) != 'string')
   143              throw new Error('Expected string for options.contents');
   144            if (options.lineNo === undefined)
   145              options.lineNo = 1;
   146            if (options.jsVersion === undefined)
   147              options.jsVersion = "1.8";
   148            if (typeof(options.filename) != 'string')
   149              options.filename = '<string>';
   151            if (this._principal == systemPrincipal)
   152              options.filename = maybeParentifyFilename(options.filename);
   154            return Cu.evalInSandbox(options.contents,
   155                                    this._sandbox,
   156                                    options.jsVersion,
   157                                    options.filename,
   158                                    options.lineNo);
   159          }
   160        };
   161      }
   162    };
   164    exports.Loader = function Loader(options) {
   165      options = {__proto__: options};
   166      if (options.fs === undefined) {
   167        var rootPaths = options.rootPath || options.rootPaths;
   168        if (rootPaths) {
   169          if (rootPaths.constructor.name != "Array")
   170            rootPaths = [rootPaths];
   171          var fses = [new exports.LocalFileSystem(path)
   172                      for each (path in rootPaths)];
   173          options.fs = new exports.CompositeFileSystem(fses);
   174        } else
   175          options.fs = new exports.LocalFileSystem();
   176      }
   177      if (options.sandboxFactory === undefined)
   178        options.sandboxFactory = new exports.SandboxFactory(
   179          options.defaultPrincipal
   180        );
   181      if (options.modules === undefined)
   182        options.modules = {};
   183      if (options.globals === undefined)
   184        options.globals = {};
   186      this.fs = options.fs;
   187      this.sandboxFactory = options.sandboxFactory;
   188      this.sandboxes = {};
   189      this.modules = options.modules;
   190      this.globals = options.globals;
   191    };
   193    exports.Loader.prototype = {
   194      _makeRequire: function _makeRequire(rootDir) {
   195        var self = this;
   196        return function require(module) {
   197          if (module == "chrome") {
   198            var chrome = { Cc: Components.classes,
   199                           Ci: Components.interfaces,
   200                           Cu: Components.utils,
   201                           Cr: Components.results,
   202                           Cm: Components.manager,
   203                           components: Components
   204                         };
   205            return chrome;
   206          }
   207          var path = self.fs.resolveModule(rootDir, module);
   208          if (!path)
   209            throw new Error('Module "' + module + '" not found');
   210          if (!(path in self.modules)) {
   211            var options = self.fs.getFile(path);
   212            if (options.filename === undefined)
   213              options.filename = path;
   215            var exports = {};
   216            var sandbox = self.sandboxFactory.createSandbox(options);
   217            self.sandboxes[path] = sandbox;
   218            for (name in self.globals)
   219              sandbox.defineProperty(name, self.globals[name]);
   220            sandbox.defineProperty('require', self._makeRequire(path));
   221            sandbox.evaluate("var exports = {};");
   222            let ES5 = self.modules.es5;
   223            if (ES5) {
   224              let { Object, Array, Function } = sandbox.globalScope;
   225              ES5.init(Object, Array, Function);
   226            }
   227            self.modules[path] = sandbox.getProperty("exports");
   228            sandbox.evaluate(options);
   229          }
   230          return self.modules[path];
   231        };
   232      },
   234      // This is only really used by unit tests and other
   235      // development-related facilities, allowing access to symbols
   236      // defined in the global scope of a module.
   237      findSandboxForModule: function findSandboxForModule(module) {
   238        var path = this.fs.resolveModule(null, module);
   239        if (!path)
   240          throw new Error('Module "' + module + '" not found');
   241        if (!(path in this.sandboxes))
   242          this.require(module);
   243        if (!(path in this.sandboxes))
   244          throw new Error('Internal error: path not in sandboxes: ' +
   245                          path);
   246        return this.sandboxes[path];
   247      },
   249      require: function require(module) {
   250        return (this._makeRequire(null))(module);
   251      },
   253      runScript: function runScript(options, extraOutput) {
   254        if (typeof(options) == 'string')
   255          options = {contents: options};
   256        options = {__proto__: options};
   257        var sandbox = this.sandboxFactory.createSandbox(options);
   258        if (extraOutput)
   259          extraOutput.sandbox = sandbox;
   260        for (name in this.globals)
   261          sandbox.defineProperty(name, this.globals[name]);
   262        sandbox.defineProperty('require', this._makeRequire(null));
   263        return sandbox.evaluate(options);
   264      }
   265    };
   267    exports.CompositeFileSystem = function CompositeFileSystem(fses) {
   268      this.fses = fses;
   269      this._pathMap = {};
   270    };
   272    exports.CompositeFileSystem.prototype = {
   273      resolveModule: function resolveModule(base, path) {
   274        for (var i = 0; i < this.fses.length; i++) {
   275          var fs = this.fses[i];
   276          var absPath = fs.resolveModule(base, path);
   277          if (absPath) {
   278            this._pathMap[absPath] = fs;
   279            return absPath;
   280          }
   281        }
   282        return null;
   283      },
   284      getFile: function getFile(path) {
   285        return this._pathMap[path].getFile(path);
   286      }
   287    };
   289    exports.LocalFileSystem = function LocalFileSystem(root) {
   290      if (root === undefined) {
   291        if (!baseURI)
   292          throw new Error("Need a root path for module filesystem");
   293        root = baseURI;
   294      }
   295      if (typeof(root) == 'string')
   296        root = ios.newURI(root, null, baseURI);
   297      if (root instanceof Ci.nsIFile)
   298        root = ios.newFileURI(root);
   299      if (!(root instanceof Ci.nsIURI))
   300        throw new Error('Expected nsIFile, nsIURI, or string for root');
   302      this.root = root.spec;
   303      this._rootURI = root;
   304      this._rootURIDir = getRootDir(root.spec);
   305    };
   307    exports.LocalFileSystem.prototype = {
   308      resolveModule: function resolveModule(base, path) {
   309        path = path + ".js";
   311        var baseURI;
   312        if (!base)
   313          baseURI = this._rootURI;
   314        else
   315          baseURI = ios.newURI(base, null, null);
   316        var newURI = ios.newURI(path, null, baseURI);
   317        var channel = ios.newChannelFromURI(newURI);
   318        try {
   319          channel.open().close();
   320        } catch (e if e.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
   321          return null;
   322        }
   323        return newURI.spec;
   324      },
   325      getFile: function getFile(path) {
   326        var channel = ios.newChannel(path, null, null);
   327        var iStream = channel.open();
   328        var ciStream = Cc["@mozilla.org/intl/converter-input-stream;1"].
   329                       createInstance(Ci.nsIConverterInputStream);
   330        var bufLen = 0x8000;
   331        ciStream.init(iStream, "UTF-8", bufLen,
   332                      Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
   333        var chunk = {};
   334        var data = "";
   335        while (ciStream.readString(bufLen, chunk) > 0)
   336          data += chunk.value;
   337        ciStream.close();
   338        iStream.close();
   339        return {contents: data};
   340      }
   341    };
   343    if (global.window) {
   344      // We're being loaded in a chrome window, or a web page with
   345      // UniversalXPConnect privileges.
   346      global.SecurableModule = exports;
   347    } else if (global.exports) {
   348      // We're being loaded in a SecurableModule.
   349      for (name in exports) {
   350        global.exports[name] = exports[name];
   351      }
   352    } else {
   353      // We're being loaded in a JS module.
   354      global.EXPORTED_SYMBOLS = [];
   355      for (name in exports) {
   356        global.EXPORTED_SYMBOLS.push(name);
   357        global[name] = exports[name];
   358      }
   359    }
   360  })(this);

mercurial