summaryrefslogtreecommitdiffstats
path: root/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js')
-rw-r--r--services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js370
1 files changed, 370 insertions, 0 deletions
diff --git a/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js b/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js
new file mode 100644
index 000000000..2648afd27
--- /dev/null
+++ b/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js
@@ -0,0 +1,370 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Jetpack.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+(function(global) {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const Cu = Components.utils;
+ const Cr = Components.results;
+
+ Cu.import("resource://gre/modules/NetUtil.jsm");
+
+ var exports = {};
+
+ var ios = Cc['@mozilla.org/network/io-service;1']
+ .getService(Ci.nsIIOService);
+
+ var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
+ .createInstance(Ci.nsIPrincipal);
+
+ function resolvePrincipal(principal, defaultPrincipal) {
+ if (principal === undefined)
+ return defaultPrincipal;
+ if (principal == "system")
+ return systemPrincipal;
+ return principal;
+ }
+
+ // The base URI to we use when we're given relative URLs, if any.
+ var baseURI = null;
+ if (global.window)
+ baseURI = ios.newURI(global.location.href, null, null);
+ exports.baseURI = baseURI;
+
+ // The "parent" chrome URI to use if we're loading code that
+ // needs chrome privileges but may not have a filename that
+ // matches any of SpiderMonkey's defined system filename prefixes.
+ // The latter is needed so that wrappers can be automatically
+ // made for the code. For more information on this, see
+ // bug 418356:
+ //
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=418356
+ var parentChromeURIString;
+ if (baseURI)
+ // We're being loaded from a chrome-privileged document, so
+ // use its URL as the parent string.
+ parentChromeURIString = baseURI.spec;
+ else
+ // We're being loaded from a chrome-privileged JS module or
+ // SecurableModule, so use its filename (which may itself
+ // contain a reference to a parent).
+ parentChromeURIString = Components.stack.filename;
+
+ function maybeParentifyFilename(filename) {
+ var doParentifyFilename = true;
+ try {
+ // TODO: Ideally we should just make
+ // nsIChromeRegistry.wrappersEnabled() available from script
+ // and use it here. Until that's in the platform, though,
+ // we'll play it safe and parentify the filename unless
+ // we're absolutely certain things will be ok if we don't.
+ var filenameURI = ios.newURI(options.filename,
+ null,
+ baseURI);
+ if (filenameURI.scheme == 'chrome' &&
+ filenameURI.path.indexOf('/content/') == 0)
+ // Content packages will always have wrappers made for them;
+ // if automatic wrappers have been disabled for the
+ // chrome package via a chrome manifest flag, then
+ // this still works too, to the extent that the
+ // content package is insecure anyways.
+ doParentifyFilename = false;
+ } catch (e) {}
+ if (doParentifyFilename)
+ return parentChromeURIString + " -> " + filename;
+ return filename;
+ }
+
+ function getRootDir(urlStr) {
+ // TODO: This feels hacky, and like there will be edge cases.
+ return urlStr.slice(0, urlStr.lastIndexOf("/") + 1);
+ }
+
+ exports.SandboxFactory = function SandboxFactory(defaultPrincipal) {
+ // Unless specified otherwise, use a principal with limited
+ // privileges.
+ this._defaultPrincipal = resolvePrincipal(defaultPrincipal,
+ "http://www.mozilla.org");
+ },
+
+ exports.SandboxFactory.prototype = {
+ createSandbox: function createSandbox(options) {
+ var principal = resolvePrincipal(options.principal,
+ this._defaultPrincipal);
+
+ return {
+ _sandbox: new Cu.Sandbox(principal),
+ _principal: principal,
+ get globalScope() {
+ return this._sandbox;
+ },
+ defineProperty: function defineProperty(name, value) {
+ this._sandbox[name] = value;
+ },
+ getProperty: function getProperty(name) {
+ return this._sandbox[name];
+ },
+ evaluate: function evaluate(options) {
+ if (typeof(options) == 'string')
+ options = {contents: options};
+ options = {__proto__: options};
+ if (typeof(options.contents) != 'string')
+ throw new Error('Expected string for options.contents');
+ if (options.lineNo === undefined)
+ options.lineNo = 1;
+ if (options.jsVersion === undefined)
+ options.jsVersion = "1.8";
+ if (typeof(options.filename) != 'string')
+ options.filename = '<string>';
+
+ if (this._principal == systemPrincipal)
+ options.filename = maybeParentifyFilename(options.filename);
+
+ return Cu.evalInSandbox(options.contents,
+ this._sandbox,
+ options.jsVersion,
+ options.filename,
+ options.lineNo);
+ }
+ };
+ }
+ };
+
+ exports.Loader = function Loader(options) {
+ options = {__proto__: options};
+ if (options.fs === undefined) {
+ var rootPaths = options.rootPath || options.rootPaths;
+ if (rootPaths) {
+ if (rootPaths.constructor.name != "Array")
+ rootPaths = [rootPaths];
+ var fses = rootPaths.map(path => new exports.LocalFileSystem(path));
+ options.fs = new exports.CompositeFileSystem(fses);
+ } else
+ options.fs = new exports.LocalFileSystem();
+ }
+ if (options.sandboxFactory === undefined)
+ options.sandboxFactory = new exports.SandboxFactory(
+ options.defaultPrincipal
+ );
+ if (options.modules === undefined)
+ options.modules = {};
+ if (options.globals === undefined)
+ options.globals = {};
+
+ this.fs = options.fs;
+ this.sandboxFactory = options.sandboxFactory;
+ this.sandboxes = {};
+ this.modules = options.modules;
+ this.globals = options.globals;
+ };
+
+ exports.Loader.prototype = {
+ _makeRequire: function _makeRequire(rootDir) {
+ var self = this;
+ return function require(module) {
+ if (module == "chrome") {
+ var chrome = { Cc: Components.classes,
+ Ci: Components.interfaces,
+ Cu: Components.utils,
+ Cr: Components.results,
+ Cm: Components.manager,
+ components: Components
+ };
+ return chrome;
+ }
+ var path = self.fs.resolveModule(rootDir, module);
+ if (!path)
+ throw new Error('Module "' + module + '" not found');
+ if (!(path in self.modules)) {
+ var options = self.fs.getFile(path);
+ if (options.filename === undefined)
+ options.filename = path;
+
+ var exports = {};
+ var sandbox = self.sandboxFactory.createSandbox(options);
+ self.sandboxes[path] = sandbox;
+ for (name in self.globals)
+ sandbox.defineProperty(name, self.globals[name]);
+ sandbox.defineProperty('require', self._makeRequire(path));
+ sandbox.evaluate("var exports = {};");
+ let ES5 = self.modules.es5;
+ if (ES5) {
+ let { Object, Array, Function } = sandbox.globalScope;
+ ES5.init(Object, Array, Function);
+ }
+ self.modules[path] = sandbox.getProperty("exports");
+ sandbox.evaluate(options);
+ }
+ return self.modules[path];
+ };
+ },
+
+ // This is only really used by unit tests and other
+ // development-related facilities, allowing access to symbols
+ // defined in the global scope of a module.
+ findSandboxForModule: function findSandboxForModule(module) {
+ var path = this.fs.resolveModule(null, module);
+ if (!path)
+ throw new Error('Module "' + module + '" not found');
+ if (!(path in this.sandboxes))
+ this.require(module);
+ if (!(path in this.sandboxes))
+ throw new Error('Internal error: path not in sandboxes: ' +
+ path);
+ return this.sandboxes[path];
+ },
+
+ require: function require(module) {
+ return (this._makeRequire(null))(module);
+ },
+
+ runScript: function runScript(options, extraOutput) {
+ if (typeof(options) == 'string')
+ options = {contents: options};
+ options = {__proto__: options};
+ var sandbox = this.sandboxFactory.createSandbox(options);
+ if (extraOutput)
+ extraOutput.sandbox = sandbox;
+ for (name in this.globals)
+ sandbox.defineProperty(name, this.globals[name]);
+ sandbox.defineProperty('require', this._makeRequire(null));
+ return sandbox.evaluate(options);
+ }
+ };
+
+ exports.CompositeFileSystem = function CompositeFileSystem(fses) {
+ this.fses = fses;
+ this._pathMap = {};
+ };
+
+ exports.CompositeFileSystem.prototype = {
+ resolveModule: function resolveModule(base, path) {
+ for (var i = 0; i < this.fses.length; i++) {
+ var fs = this.fses[i];
+ var absPath = fs.resolveModule(base, path);
+ if (absPath) {
+ this._pathMap[absPath] = fs;
+ return absPath;
+ }
+ }
+ return null;
+ },
+ getFile: function getFile(path) {
+ return this._pathMap[path].getFile(path);
+ }
+ };
+
+ exports.LocalFileSystem = function LocalFileSystem(root) {
+ if (root === undefined) {
+ if (!baseURI)
+ throw new Error("Need a root path for module filesystem");
+ root = baseURI;
+ }
+ if (typeof(root) == 'string')
+ root = ios.newURI(root, null, baseURI);
+ if (root instanceof Ci.nsIFile)
+ root = ios.newFileURI(root);
+ if (!(root instanceof Ci.nsIURI))
+ throw new Error('Expected nsIFile, nsIURI, or string for root');
+
+ this.root = root.spec;
+ this._rootURI = root;
+ this._rootURIDir = getRootDir(root.spec);
+ };
+
+ exports.LocalFileSystem.prototype = {
+ resolveModule: function resolveModule(base, path) {
+ path = path + ".js";
+
+ var baseURI;
+ if (!base)
+ baseURI = this._rootURI;
+ else
+ baseURI = ios.newURI(base, null, null);
+ var newURI = ios.newURI(path, null, baseURI);
+ var channel = NetUtil.newChannel({
+ uri: newURI,
+ loadUsingSystemPrincipal: true
+ });
+ try {
+ channel.open2().close();
+ } catch (e) {
+ if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) {
+ throw e;
+ }
+ return null;
+ }
+ return newURI.spec;
+ },
+ getFile: function getFile(path) {
+ var channel = NetUtil.newChannel({
+ uri: path,
+ loadUsingSystemPrincipal: true
+ });
+ var iStream = channel.open2();
+ var ciStream = Cc["@mozilla.org/intl/converter-input-stream;1"].
+ createInstance(Ci.nsIConverterInputStream);
+ var bufLen = 0x8000;
+ ciStream.init(iStream, "UTF-8", bufLen,
+ Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
+ var chunk = {};
+ var data = "";
+ while (ciStream.readString(bufLen, chunk) > 0)
+ data += chunk.value;
+ ciStream.close();
+ iStream.close();
+ return {contents: data};
+ }
+ };
+
+ if (global.window) {
+ // We're being loaded in a chrome window, or a web page with
+ // UniversalXPConnect privileges.
+ global.SecurableModule = exports;
+ } else if (global.exports) {
+ // We're being loaded in a SecurableModule.
+ for (name in exports) {
+ global.exports[name] = exports[name];
+ }
+ } else {
+ // We're being loaded in a JS module.
+ global.EXPORTED_SYMBOLS = [];
+ for (name in exports) {
+ global.EXPORTED_SYMBOLS.push(name);
+ global[name] = exports[name];
+ }
+ }
+ })(this);