1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,360 @@ 1.4 +/* ***** BEGIN LICENSE BLOCK ***** 1.5 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 1.6 + * 1.7 + * The contents of this file are subject to the Mozilla Public License Version 1.8 + * 1.1 (the "License"); you may not use this file except in compliance with 1.9 + * the License. You may obtain a copy of the License at 1.10 + * http://www.mozilla.org/MPL/ 1.11 + * 1.12 + * Software distributed under the License is distributed on an "AS IS" basis, 1.13 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1.14 + * for the specific language governing rights and limitations under the 1.15 + * License. 1.16 + * 1.17 + * The Original Code is Jetpack. 1.18 + * 1.19 + * The Initial Developer of the Original Code is Mozilla. 1.20 + * Portions created by the Initial Developer are Copyright (C) 2007 1.21 + * the Initial Developer. All Rights Reserved. 1.22 + * 1.23 + * Contributor(s): 1.24 + * Atul Varma <atul@mozilla.com> 1.25 + * 1.26 + * Alternatively, the contents of this file may be used under the terms of 1.27 + * either the GNU General Public License Version 2 or later (the "GPL"), or 1.28 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 1.29 + * in which case the provisions of the GPL or the LGPL are applicable instead 1.30 + * of those above. If you wish to allow use of your version of this file only 1.31 + * under the terms of either the GPL or the LGPL, and not to allow others to 1.32 + * use your version of this file under the terms of the MPL, indicate your 1.33 + * decision by deleting the provisions above and replace them with the notice 1.34 + * and other provisions required by the GPL or the LGPL. If you do not delete 1.35 + * the provisions above, a recipient may use your version of this file under 1.36 + * the terms of any one of the MPL, the GPL or the LGPL. 1.37 + * 1.38 + * ***** END LICENSE BLOCK ***** */ 1.39 + 1.40 +(function(global) { 1.41 + const Cc = Components.classes; 1.42 + const Ci = Components.interfaces; 1.43 + const Cu = Components.utils; 1.44 + const Cr = Components.results; 1.45 + 1.46 + var exports = {}; 1.47 + 1.48 + var ios = Cc['@mozilla.org/network/io-service;1'] 1.49 + .getService(Ci.nsIIOService); 1.50 + 1.51 + var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"] 1.52 + .createInstance(Ci.nsIPrincipal); 1.53 + 1.54 + function resolvePrincipal(principal, defaultPrincipal) { 1.55 + if (principal === undefined) 1.56 + return defaultPrincipal; 1.57 + if (principal == "system") 1.58 + return systemPrincipal; 1.59 + return principal; 1.60 + } 1.61 + 1.62 + // The base URI to we use when we're given relative URLs, if any. 1.63 + var baseURI = null; 1.64 + if (global.window) 1.65 + baseURI = ios.newURI(global.location.href, null, null); 1.66 + exports.baseURI = baseURI; 1.67 + 1.68 + // The "parent" chrome URI to use if we're loading code that 1.69 + // needs chrome privileges but may not have a filename that 1.70 + // matches any of SpiderMonkey's defined system filename prefixes. 1.71 + // The latter is needed so that wrappers can be automatically 1.72 + // made for the code. For more information on this, see 1.73 + // bug 418356: 1.74 + // 1.75 + // https://bugzilla.mozilla.org/show_bug.cgi?id=418356 1.76 + var parentChromeURIString; 1.77 + if (baseURI) 1.78 + // We're being loaded from a chrome-privileged document, so 1.79 + // use its URL as the parent string. 1.80 + parentChromeURIString = baseURI.spec; 1.81 + else 1.82 + // We're being loaded from a chrome-privileged JS module or 1.83 + // SecurableModule, so use its filename (which may itself 1.84 + // contain a reference to a parent). 1.85 + parentChromeURIString = Components.stack.filename; 1.86 + 1.87 + function maybeParentifyFilename(filename) { 1.88 + var doParentifyFilename = true; 1.89 + try { 1.90 + // TODO: Ideally we should just make 1.91 + // nsIChromeRegistry.wrappersEnabled() available from script 1.92 + // and use it here. Until that's in the platform, though, 1.93 + // we'll play it safe and parentify the filename unless 1.94 + // we're absolutely certain things will be ok if we don't. 1.95 + var filenameURI = ios.newURI(options.filename, 1.96 + null, 1.97 + baseURI); 1.98 + if (filenameURI.scheme == 'chrome' && 1.99 + filenameURI.path.indexOf('/content/') == 0) 1.100 + // Content packages will always have wrappers made for them; 1.101 + // if automatic wrappers have been disabled for the 1.102 + // chrome package via a chrome manifest flag, then 1.103 + // this still works too, to the extent that the 1.104 + // content package is insecure anyways. 1.105 + doParentifyFilename = false; 1.106 + } catch (e) {} 1.107 + if (doParentifyFilename) 1.108 + return parentChromeURIString + " -> " + filename; 1.109 + return filename; 1.110 + } 1.111 + 1.112 + function getRootDir(urlStr) { 1.113 + // TODO: This feels hacky, and like there will be edge cases. 1.114 + return urlStr.slice(0, urlStr.lastIndexOf("/") + 1); 1.115 + } 1.116 + 1.117 + exports.SandboxFactory = function SandboxFactory(defaultPrincipal) { 1.118 + // Unless specified otherwise, use a principal with limited 1.119 + // privileges. 1.120 + this._defaultPrincipal = resolvePrincipal(defaultPrincipal, 1.121 + "http://www.mozilla.org"); 1.122 + }, 1.123 + 1.124 + exports.SandboxFactory.prototype = { 1.125 + createSandbox: function createSandbox(options) { 1.126 + var principal = resolvePrincipal(options.principal, 1.127 + this._defaultPrincipal); 1.128 + 1.129 + return { 1.130 + _sandbox: new Cu.Sandbox(principal), 1.131 + _principal: principal, 1.132 + get globalScope() { 1.133 + return this._sandbox; 1.134 + }, 1.135 + defineProperty: function defineProperty(name, value) { 1.136 + this._sandbox[name] = value; 1.137 + }, 1.138 + getProperty: function getProperty(name) { 1.139 + return this._sandbox[name]; 1.140 + }, 1.141 + evaluate: function evaluate(options) { 1.142 + if (typeof(options) == 'string') 1.143 + options = {contents: options}; 1.144 + options = {__proto__: options}; 1.145 + if (typeof(options.contents) != 'string') 1.146 + throw new Error('Expected string for options.contents'); 1.147 + if (options.lineNo === undefined) 1.148 + options.lineNo = 1; 1.149 + if (options.jsVersion === undefined) 1.150 + options.jsVersion = "1.8"; 1.151 + if (typeof(options.filename) != 'string') 1.152 + options.filename = '<string>'; 1.153 + 1.154 + if (this._principal == systemPrincipal) 1.155 + options.filename = maybeParentifyFilename(options.filename); 1.156 + 1.157 + return Cu.evalInSandbox(options.contents, 1.158 + this._sandbox, 1.159 + options.jsVersion, 1.160 + options.filename, 1.161 + options.lineNo); 1.162 + } 1.163 + }; 1.164 + } 1.165 + }; 1.166 + 1.167 + exports.Loader = function Loader(options) { 1.168 + options = {__proto__: options}; 1.169 + if (options.fs === undefined) { 1.170 + var rootPaths = options.rootPath || options.rootPaths; 1.171 + if (rootPaths) { 1.172 + if (rootPaths.constructor.name != "Array") 1.173 + rootPaths = [rootPaths]; 1.174 + var fses = [new exports.LocalFileSystem(path) 1.175 + for each (path in rootPaths)]; 1.176 + options.fs = new exports.CompositeFileSystem(fses); 1.177 + } else 1.178 + options.fs = new exports.LocalFileSystem(); 1.179 + } 1.180 + if (options.sandboxFactory === undefined) 1.181 + options.sandboxFactory = new exports.SandboxFactory( 1.182 + options.defaultPrincipal 1.183 + ); 1.184 + if (options.modules === undefined) 1.185 + options.modules = {}; 1.186 + if (options.globals === undefined) 1.187 + options.globals = {}; 1.188 + 1.189 + this.fs = options.fs; 1.190 + this.sandboxFactory = options.sandboxFactory; 1.191 + this.sandboxes = {}; 1.192 + this.modules = options.modules; 1.193 + this.globals = options.globals; 1.194 + }; 1.195 + 1.196 + exports.Loader.prototype = { 1.197 + _makeRequire: function _makeRequire(rootDir) { 1.198 + var self = this; 1.199 + return function require(module) { 1.200 + if (module == "chrome") { 1.201 + var chrome = { Cc: Components.classes, 1.202 + Ci: Components.interfaces, 1.203 + Cu: Components.utils, 1.204 + Cr: Components.results, 1.205 + Cm: Components.manager, 1.206 + components: Components 1.207 + }; 1.208 + return chrome; 1.209 + } 1.210 + var path = self.fs.resolveModule(rootDir, module); 1.211 + if (!path) 1.212 + throw new Error('Module "' + module + '" not found'); 1.213 + if (!(path in self.modules)) { 1.214 + var options = self.fs.getFile(path); 1.215 + if (options.filename === undefined) 1.216 + options.filename = path; 1.217 + 1.218 + var exports = {}; 1.219 + var sandbox = self.sandboxFactory.createSandbox(options); 1.220 + self.sandboxes[path] = sandbox; 1.221 + for (name in self.globals) 1.222 + sandbox.defineProperty(name, self.globals[name]); 1.223 + sandbox.defineProperty('require', self._makeRequire(path)); 1.224 + sandbox.evaluate("var exports = {};"); 1.225 + let ES5 = self.modules.es5; 1.226 + if (ES5) { 1.227 + let { Object, Array, Function } = sandbox.globalScope; 1.228 + ES5.init(Object, Array, Function); 1.229 + } 1.230 + self.modules[path] = sandbox.getProperty("exports"); 1.231 + sandbox.evaluate(options); 1.232 + } 1.233 + return self.modules[path]; 1.234 + }; 1.235 + }, 1.236 + 1.237 + // This is only really used by unit tests and other 1.238 + // development-related facilities, allowing access to symbols 1.239 + // defined in the global scope of a module. 1.240 + findSandboxForModule: function findSandboxForModule(module) { 1.241 + var path = this.fs.resolveModule(null, module); 1.242 + if (!path) 1.243 + throw new Error('Module "' + module + '" not found'); 1.244 + if (!(path in this.sandboxes)) 1.245 + this.require(module); 1.246 + if (!(path in this.sandboxes)) 1.247 + throw new Error('Internal error: path not in sandboxes: ' + 1.248 + path); 1.249 + return this.sandboxes[path]; 1.250 + }, 1.251 + 1.252 + require: function require(module) { 1.253 + return (this._makeRequire(null))(module); 1.254 + }, 1.255 + 1.256 + runScript: function runScript(options, extraOutput) { 1.257 + if (typeof(options) == 'string') 1.258 + options = {contents: options}; 1.259 + options = {__proto__: options}; 1.260 + var sandbox = this.sandboxFactory.createSandbox(options); 1.261 + if (extraOutput) 1.262 + extraOutput.sandbox = sandbox; 1.263 + for (name in this.globals) 1.264 + sandbox.defineProperty(name, this.globals[name]); 1.265 + sandbox.defineProperty('require', this._makeRequire(null)); 1.266 + return sandbox.evaluate(options); 1.267 + } 1.268 + }; 1.269 + 1.270 + exports.CompositeFileSystem = function CompositeFileSystem(fses) { 1.271 + this.fses = fses; 1.272 + this._pathMap = {}; 1.273 + }; 1.274 + 1.275 + exports.CompositeFileSystem.prototype = { 1.276 + resolveModule: function resolveModule(base, path) { 1.277 + for (var i = 0; i < this.fses.length; i++) { 1.278 + var fs = this.fses[i]; 1.279 + var absPath = fs.resolveModule(base, path); 1.280 + if (absPath) { 1.281 + this._pathMap[absPath] = fs; 1.282 + return absPath; 1.283 + } 1.284 + } 1.285 + return null; 1.286 + }, 1.287 + getFile: function getFile(path) { 1.288 + return this._pathMap[path].getFile(path); 1.289 + } 1.290 + }; 1.291 + 1.292 + exports.LocalFileSystem = function LocalFileSystem(root) { 1.293 + if (root === undefined) { 1.294 + if (!baseURI) 1.295 + throw new Error("Need a root path for module filesystem"); 1.296 + root = baseURI; 1.297 + } 1.298 + if (typeof(root) == 'string') 1.299 + root = ios.newURI(root, null, baseURI); 1.300 + if (root instanceof Ci.nsIFile) 1.301 + root = ios.newFileURI(root); 1.302 + if (!(root instanceof Ci.nsIURI)) 1.303 + throw new Error('Expected nsIFile, nsIURI, or string for root'); 1.304 + 1.305 + this.root = root.spec; 1.306 + this._rootURI = root; 1.307 + this._rootURIDir = getRootDir(root.spec); 1.308 + }; 1.309 + 1.310 + exports.LocalFileSystem.prototype = { 1.311 + resolveModule: function resolveModule(base, path) { 1.312 + path = path + ".js"; 1.313 + 1.314 + var baseURI; 1.315 + if (!base) 1.316 + baseURI = this._rootURI; 1.317 + else 1.318 + baseURI = ios.newURI(base, null, null); 1.319 + var newURI = ios.newURI(path, null, baseURI); 1.320 + var channel = ios.newChannelFromURI(newURI); 1.321 + try { 1.322 + channel.open().close(); 1.323 + } catch (e if e.result == Cr.NS_ERROR_FILE_NOT_FOUND) { 1.324 + return null; 1.325 + } 1.326 + return newURI.spec; 1.327 + }, 1.328 + getFile: function getFile(path) { 1.329 + var channel = ios.newChannel(path, null, null); 1.330 + var iStream = channel.open(); 1.331 + var ciStream = Cc["@mozilla.org/intl/converter-input-stream;1"]. 1.332 + createInstance(Ci.nsIConverterInputStream); 1.333 + var bufLen = 0x8000; 1.334 + ciStream.init(iStream, "UTF-8", bufLen, 1.335 + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); 1.336 + var chunk = {}; 1.337 + var data = ""; 1.338 + while (ciStream.readString(bufLen, chunk) > 0) 1.339 + data += chunk.value; 1.340 + ciStream.close(); 1.341 + iStream.close(); 1.342 + return {contents: data}; 1.343 + } 1.344 + }; 1.345 + 1.346 + if (global.window) { 1.347 + // We're being loaded in a chrome window, or a web page with 1.348 + // UniversalXPConnect privileges. 1.349 + global.SecurableModule = exports; 1.350 + } else if (global.exports) { 1.351 + // We're being loaded in a SecurableModule. 1.352 + for (name in exports) { 1.353 + global.exports[name] = exports[name]; 1.354 + } 1.355 + } else { 1.356 + // We're being loaded in a JS module. 1.357 + global.EXPORTED_SYMBOLS = []; 1.358 + for (name in exports) { 1.359 + global.EXPORTED_SYMBOLS.push(name); 1.360 + global[name] = exports[name]; 1.361 + } 1.362 + } 1.363 + })(this);