Bug 1205886 - [webext] Allow content scripts to do cross-origin XHRs if they have permission (r=kmag)

This commit is contained in:
Bill McCloskey 2015-12-02 20:18:00 -08:00
parent 927a14f259
commit b1eab920e0
4 changed files with 161 additions and 4 deletions

View File

@ -231,13 +231,23 @@ function ExtensionContext(extensionId, contentWindow) {
let mm = getWindowMessageManager(contentWindow);
this.messageManager = mm;
let prin = [contentWindow];
if (Services.scriptSecurityManager.isSystemPrincipal(contentWindow.document.nodePrincipal)) {
let prin;
let contentPrincipal = contentWindow.document.nodePrincipal;
let ssm = Services.scriptSecurityManager;
if (ssm.isSystemPrincipal(contentPrincipal)) {
// Make sure we don't hand out the system principal by accident.
prin = Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal);
} else {
let extensionPrincipal = ssm.createCodebasePrincipal(this.extension.baseURI, {addonId: extensionId});
prin = [contentPrincipal, extensionPrincipal];
}
this.sandbox = Cu.Sandbox(prin, {sandboxPrototype: contentWindow, wantXrays: true, isWebExtensionContentScript: true});
this.sandbox = Cu.Sandbox(prin, {
sandboxPrototype: contentWindow,
wantXrays: true,
isWebExtensionContentScript: true,
wantGlobalProperties: ["XMLHttpRequest"],
});
let delegate = {
getSender(context, target, sender) {
@ -472,7 +482,7 @@ function BrowserExtensionContent(data) {
this.data = data;
this.scripts = data.content_scripts.map(scriptData => new Script(scriptData));
this.webAccessibleResources = data.webAccessibleResources;
this.whiteListedHosts = data.whiteListedHosts;
this.whiteListedHosts = new MatchPattern(data.whiteListedHosts);
this.localeData = new LocaleData(data.localeData);

View File

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script>
addEventListener("message", function rcv(event) {
removeEventListener("message", rcv, false);
function passListener() {
postMessage(true, "*");
}
function failListener() {
postMessage(false, "*");
}
var exc = null;
try {
new privilegedXHR();
} catch (e) {
exc = e;
}
if (!/Permission denied to access object/.exec(exc)) {
postMessage(false, "*");
return;
}
var req = new XMLHttpRequest();
req.addEventListener("load", failListener);
req.addEventListener("error", passListener);
req.open("GET", "http://example.org/example.txt");
req.send();
}, false);
</script>
</body>
</html>

View File

@ -20,6 +20,7 @@ support-files =
file_sample.html
file_privilege_escalation.html
file_ext_background_api_injection.js
file_permission_xhr.html
[test_ext_simple.html]
[test_ext_geturl.html]
@ -29,6 +30,7 @@ support-files =
[test_ext_localStorage.html]
[test_ext_onmessage_removelistener.html]
[test_ext_notifications.html]
[test_ext_permission_xhr.html]
[test_ext_runtime_connect.html]
[test_ext_runtime_connect2.html]
[test_ext_runtime_disconnect.html]

View File

@ -0,0 +1,104 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebExtension Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.8">
add_task(function* test_simple() {
function runTests(cx, assertTrue, finish) {
function run(shouldFail, finish) {
function passListener() {
assertTrue(true, `${cx} pass listener`);
finish();
}
function failListener() {
assertTrue(false, `${cx} fail listener`);
finish();
}
var req = new XMLHttpRequest();
if (shouldFail) {
req.addEventListener("load", failListener);
req.addEventListener("error", passListener);
req.open("GET", "http://example.org/example.txt");
} else {
req.addEventListener("load", passListener);
req.addEventListener("error", failListener);
req.open("GET", "http://example.com/example.txt");
}
req.send();
}
run(true, function() {
run(false, finish);
});
}
function background(runTests) {
browser.runtime.onMessage.addListener(([msg, ...args]) => {
if (msg == "assertTrue") {
browser.test.assertTrue(...args);
} else {
browser.test.sendMessage(msg, ...args);
}
});
runTests("bg", browser.test.assertTrue.bind(browser.test), () => {
browser.test.notifyPass("permission_xhr");
});
}
let extensionData = {
background: `(${background})(${runTests})`,
manifest: {
permissions: ["http://example.com/"],
content_scripts: [{
"matches": ["http://mochi.test/*/file_permission_xhr.html"],
"js": ["content.js"],
}],
},
files: {
"content.js": "new " + function(runTests) {
function assertTrue(...args) {
browser.runtime.sendMessage(["assertTrue", ...args]);
}
runTests("content", assertTrue, () => {
window.wrappedJSObject.privilegedXHR = XMLHttpRequest;
window.addEventListener("message", function rcv(event) {
if (event.data === "test") {
return;
}
window.removeEventListener("message", rcv, false);
browser.runtime.sendMessage(["assertTrue", event.data, "content page can't use XHR"]);
browser.runtime.sendMessage(["content-script-finished"]);
}, false);
window.postMessage("test", "*");
});
} + `(${runTests})`,
}
}
let extension = ExtensionTestUtils.loadExtension(extensionData);
yield extension.startup();
let win = window.open("file_permission_xhr.html");
yield extension.awaitMessage("content-script-finished");
win.close();
yield extension.awaitFinish("permission_xhr");
yield extension.unload();
});
</script>
</body>
</html>