Bug 821809 - Using nsExpandedPrincipal for jetpack content-scripts. r=rFobic

This commit is contained in:
Gabor Krizsanits 2014-04-09 11:52:24 +02:00
parent 23d9392934
commit aa234947d3
4 changed files with 115 additions and 8 deletions

View File

@ -38,6 +38,12 @@ const metadata = require('@loader/options').metadata;
const permissions = (metadata && metadata['permissions']) || {};
const EXPANDED_PRINCIPALS = permissions['cross-domain-content'] || [];
const waiveSecurityMembrane = !!permissions['unsafe-content-script'];
const nsIScriptSecurityManager = Ci.nsIScriptSecurityManager;
const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
getService(Ci.nsIScriptSecurityManager);
const JS_VERSION = '1.8';
const WorkerSandbox = Class({
@ -96,8 +102,10 @@ const WorkerSandbox = Class({
this.emit = this.emit.bind(this);
this.emitSync = this.emitSync.bind(this);
// Eventually use expanded principal sandbox feature, if some are given.
//
// Use expanded principal for content-script if the content is a
// regular web content for better isolation.
// (This behavior can be turned off for now with the unsafe-content-script
// flag to give addon developers time for making the necessary changes)
// But prevent it when the Worker isn't used for a content script but for
// injecting `addon` object into a Panel, Widget, ... scope.
// That's because:
@ -110,13 +118,18 @@ const WorkerSandbox = Class({
// domain principal.
let principals = window;
let wantGlobalProperties = [];
if (EXPANDED_PRINCIPALS.length > 0 && !requiresAddonGlobal(worker)) {
principals = EXPANDED_PRINCIPALS.concat(window);
let isSystemPrincipal = secMan.isSystemPrincipal(
window.document.nodePrincipal);
if (!isSystemPrincipal && !requiresAddonGlobal(worker)) {
if (EXPANDED_PRINCIPALS.length > 0) {
// We have to replace XHR constructor of the content document
// with a custom cross origin one, automagically added by platform code:
delete proto.XMLHttpRequest;
wantGlobalProperties.push('XMLHttpRequest');
}
if (!waiveSecurityMembrane)
principals = EXPANDED_PRINCIPALS.concat(window);
}
// Instantiate trusted code in another Sandbox in order to prevent content
// script from messing with standard classes used by proxy and API code.
@ -129,6 +142,7 @@ const WorkerSandbox = Class({
sandboxPrototype: proto,
wantXrays: true,
wantGlobalProperties: wantGlobalProperties,
wantExportHelpers: !waiveSecurityMembrane,
sameZoneAs: window,
metadata: {
SDKContentScript: true,

View File

@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { create: makeFrame } = require("sdk/frame/utils");
const { window } = require("sdk/addon/window");
const { Loader } = require('sdk/test/loader');
const loader = Loader(module);
const Worker = loader.require("sdk/content/worker").Worker;
exports.testMembranelessMode = function(assert, done) {
let url = "data:text/html;charset=utf-8," + encodeURIComponent(
'<script>' +
'function runTest() {' +
' assert(fuu.bar == 42, "Content-script objects should be accessible to content with' +
' the unsafe-content-script flag on.");' +
'}' +
'</script>'
);
let element = makeFrame(window.document, {
nodeName: "iframe",
type: "content",
allowJavascript: true,
allowPlugins: true,
allowAuth: true,
uri: url
});
element.addEventListener("DOMContentLoaded", onDOMReady, false);
function onDOMReady() {
let worker = Worker({
window: element.contentWindow,
contentScript:
'new ' + function () {
var assert = function assert(v, msg) {
self.port.emit("assert", { assertion: v, msg: msg });
}
var done = function done() {
self.port.emit("done");
}
window.wrappedJSObject.fuu = { bar: 42 };
window.wrappedJSObject.assert = assert;
window.wrappedJSObject.runTest();
done();
}
});
worker.port.on("done", function () {
element.parentNode.removeChild(element);
done();
});
worker.port.on("assert", function (data) {
assert.ok(data.assertion, data.msg);
});
}
};
require("sdk/test/runner").runTestsFromModule(module);

View File

@ -0,0 +1,6 @@
{
"id": "content-permissions",
"permissions": {
"unsafe-content-script": true
}
}

View File

@ -842,4 +842,30 @@ exports["test MutationObvserver"] = createProxyTest(html, function (helper) {
});
let html = '<script>' +
'var accessCheck = function() {' +
' assert(true, "exporting function works");' +
' try{' +
' exportedObj.prop;' +
' assert(false, "content should not have access to content-script");' +
' } catch(e) {' +
' assert(e.toString().indexOf("Permission denied") != -1,' +
' "content should not have access to content-script");' +
' }' +
'}</script>';
exports["test nsEp for content-script"] = createProxyTest(html, function (helper) {
helper.createWorker(
'let glob = this; new ' + function ContentScriptScope() {
exportFunction(assert, unsafeWindow, { defineAs: "assert" });
window.wrappedJSObject.assert(true, "assert exported");
window.wrappedJSObject.exportedObj = { prop: 42 };
window.wrappedJSObject.accessCheck();
done();
}
);
});
require("test").run(exports);