Bug 1184973 - Part 2: Tests for new storage permissions model, r=ehsan, r=smaug

This commit is contained in:
Michael Layzell 2015-07-24 13:42:05 -04:00
Родитель f8dabc3197
Коммит 5930cf1896
12 изменённых файлов: 641 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,22 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>frame for storage allowed test</title>
<script type="text/javascript" src="https://example.com/tests/dom/tests/mochitest/general/storagePermissionsUtils.js"></script>
<script type="text/javascript">
task(function* () {
// We should be able to access storage
yield storageAllowed();
// We should be able to run a web worker which can access storage
yield runWorker("workerStorageAllowed.js");
});
</script>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,19 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>frame for storage allowed test</title>
<script type="text/javascript" src="https://example.com/tests/dom/tests/mochitest/general/storagePermissionsUtils.js"></script>
<script type="text/javascript">
task(function* () {
// We just check if we can access storage as chrome using special powers!
yield chromePower();
});
</script>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,33 @@
// This is a sjs file which reads in frameStoragePrevented.html, and writes it out as a data: URI, which this page redirects to.
// This produces a URI with the null principal, which should be unable to access storage.
// We append the #nullprincipal hash to the end of the data: URI to tell the script that it shouldn't try to spawn a webworker,
// as it won't be allowed to, as it has a null principal.
function handleRequest(request, response) {
// Get the nsIFile for frameStoragePrevented.html
var file;
getObjectState("SERVER_ROOT", function(serverRoot) {
file = serverRoot.getFile("/tests/dom/tests/mochitest/general/frameStoragePrevented.html");
});
// Set up the file streams to read in the file as UTF-8
let fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
fstream.init(file, -1, 0, 0);
let cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Components.interfaces.nsIConverterInputStream);
cstream.init(fstream, "UTF-8", 0, 0);
// Read in the file, and concatenate it onto the data string
let data = "";
let str = {};
let read = 0;
do {
read = cstream.readString(0xffffffff, str);
data += str.value;
} while (read != 0);
// Write out the file as a data: URI, and redirect to it
response.setStatusLine('1.1', 302, 'Found');
response.setHeader('Location', 'data:text/html,' + encodeURIComponent(data) + "#nullprincipal");
}

Просмотреть файл

@ -0,0 +1,35 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>frame for storage prevented test</title>
<script type="text/javascript" src="https://example.com/tests/dom/tests/mochitest/general/storagePermissionsUtils.js"></script>
<script type="text/javascript">
task(function* () {
// We shouldn't be able to access storage
yield storagePrevented();
// This hash of the URI is set to #nullprincipal by the test if the current page has a null principal,
// and thus attempting to create a dedicated worker will throw
if (location.hash == "#nullprincipal") {
try {
new Worker("workerStoragePrevented.js");
ok(false, "Running workers should not have been allowed");
} catch (e) {
ok(true, "Running workers was prevented");
}
return;
}
// Try to run a worker, which shouldn't be able to access storage
yield runWorker("workerStoragePrevented.js");
});
</script>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -37,6 +37,13 @@ support-files =
resource_timing.js
navigation_timing.html
test_bug1012662_common.js
frameStorageAllowed.html
frameStoragePrevented.html
frameStorageChrome.html
frameStorageNullprincipal.sjs
workerStorageAllowed.js
workerStoragePrevented.js
storagePermissionsUtils.js
[test_497898.html]
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage
@ -105,3 +112,7 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet'
[test_bug1012662_noeditor.html]
[test_bug1161721.html]
[test_bug1170911.html]
[test_storagePermissionsAccept.html]
[test_storagePermissionsRejectForeign.html]
[test_storagePermissionsReject.html]
[test_storagePermissionsLimitForeign.html]

Просмотреть файл

@ -0,0 +1,232 @@
const BEHAVIOR_ACCEPT = 0;
const BEHAVIOR_REJECT_FOREIGN = 1;
const BEHAVIOR_REJECT = 2;
const BEHAVIOR_LIMIT_FOREIGN = 3;
const kPrefName = "network.cookie.cookieBehavior";
// Check if we are in frame, and declare ok and finishTest appropriately
const inFrame = ("" + location).match(/frame/);
if (inFrame) {
ok = function(a, message) {
if (!a) {
parent.postMessage("FAILURE: " + message, "http://mochi.test:8888");
} else {
parent.postMessage(message, "http://mochi.test:8888");
}
};
finishTest = function() {
parent.postMessage("done", "http://mochi.test:8888");
};
} else {
finishTest = function() {
SimpleTest.finish();
};
}
function setCookieBehavior(behavior) {
return new Promise((resolve, reject) => {
SpecialPowers.pushPrefEnv({"set": [[kPrefName, behavior]]}, resolve);
});
}
function runIFrame(url) {
return new Promise((resolve, reject) => {
function onMessage(e) {
if (e.data == "done") {
resolve();
window.removeEventListener('message', onMessage);
return;
}
ok(!e.data.match(/^FAILURE/), e.data + " (IFRAME = " + url + ")");
}
window.addEventListener('message', onMessage, false);
document.querySelector('iframe').src = url;
});
}
function runWorker(url) {
return new Promise((resolve, reject) => {
var worker = new Worker(url);
worker.addEventListener('message', function(e) {
if (e.data == "done") {
resolve();
return;
}
ok(!e.data.match(/^FAILURE/), e.data + " (WORKER = " + url + ")");
});
});
}
function chromePower() {
try {
SpecialPowers.wrap(window).localStorage.getItem("X");
ok(true, "getting localStorage didn't throw");
} catch (e) {
ok(false, "getting localStorage should not throw");
}
try {
SpecialPowers.wrap(window).sessionStorage.getItem("X");
ok(true, "getting sessionStorage didn't throw");
} catch (e) {
ok(false, "getting sessionStorage should not throw");
}
try {
SpecialPowers.wrap(window).indexedDB;
ok(true, "getting indexedDB didn't throw");
} catch (e) {
ok(false, "getting indexedDB should not throw");
}
try {
var promise = SpecialPowers.wrap(window).caches.keys();
ok(true, "getting caches didn't throw");
return new Promise((resolve, reject) => {
promise.then(function() {
ok(location.protocol == "https:", "The promise was not rejected");
resolve();
}, function(e) {
ok(location.protocol != "https:", "The promise should not have been rejected: " + e);
resolve();
});
});
} catch (e) {
ok(false, "getting caches should not have thrown");
return Promise.resolve();
}
}
function storageAllowed() {
try {
localStorage.getItem("X");
ok(true, "getting localStorage didn't throw");
} catch (e) {
ok(false, "getting localStorage should not throw");
}
try {
sessionStorage.getItem("X");
ok(true, "getting sessionStorage didn't throw");
} catch (e) {
ok(false, "getting sessionStorage should not throw");
}
try {
indexedDB;
ok(true, "getting indexedDB didn't throw");
} catch (e) {
ok(false, "getting indexedDB should not throw");
}
try {
var promise = caches.keys();
ok(true, "getting caches didn't throw");
return new Promise((resolve, reject) => {
promise.then(function() {
ok(location.protocol == "https:", "The promise was not rejected");
resolve();
}, function() {
ok(location.protocol != "https:", "The promise should not have been rejected");
resolve();
});
});
} catch (e) {
ok(false, "getting caches should not have thrown");
return Promise.resolve();
}
}
function storagePrevented() {
try {
localStorage.getItem("X");
ok(false, "getting localStorage should have thrown");
} catch (e) {
ok(true, "getting localStorage threw");
}
if (location.hash == "#thirdparty") {
// No matter what the user's preferences are, we don't block
// sessionStorage in 3rd-party iframes. We do block them everywhere
// else however.
try {
sessionStorage.getItem("X");
ok(true, "getting sessionStorage didn't throw");
} catch (e) {
ok(false, "getting sessionStorage should not have thrown");
}
} else {
try {
sessionStorage.getItem("X");
ok(false, "getting sessionStorage should have thrown");
} catch (e) {
ok(true, "getting sessionStorage threw");
}
}
try {
indexedDB;
ok(false, "getting indexedDB should have thrown");
} catch (e) {
ok(true, "getting indexedDB threw");
}
try {
var promise = caches.keys();
ok(true, "getting caches didn't throw");
return new Promise((resolve, reject) => {
promise.then(function() {
ok(false, "The promise should have rejected");
resolve();
}, function() {
ok(true, "The promise was rejected");
resolve();
});
});
} catch (e) {
ok(false, "getting caches should not have thrown");
return Promise.resolve();
}
}
function task(fn) {
if (!inFrame) {
SimpleTest.waitForExplicitFinish();
}
var gen = fn();
function next_step(val, e) {
var it;
try {
if (typeof e !== "undefined") {
it = gen.throw(e);
} else {
it = gen.next(val);
}
} catch (e) {
ok(false, "An error was thrown while stepping: " + e);
ok(false, "Stack: " + e.stack);
finishTest();
}
if (it.done) {
finishTest();
return;
}
it.value.then(next_step, (e) => next_step(null, e));
}
next_step();
}
var thirdparty = "https://example.com/tests/dom/tests/mochitest/general/";

Просмотреть файл

@ -0,0 +1,42 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Storage Permission Restrictions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="storagePermissionsUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe></iframe>
<script type="text/javascript">
task(function* () {
yield setCookieBehavior(BEHAVIOR_ACCEPT);
// We should be able to access storage
yield storageAllowed();
// Same origin iframes should be allowed, unless they redirect to a URI with the null principal
yield runIFrame("frameStorageAllowed.html");
yield runIFrame("frameStorageNullprincipal.sjs");
yield runIFrame("frameStorageChrome.html");
// Sandboxed iframes should have the null principal, and thus can't access storage
document.querySelector('iframe').setAttribute('sandbox', 'allow-scripts');
yield runIFrame("frameStoragePrevented.html#nullprincipal");
yield runIFrame("frameStorageNullprincipal.sjs");
document.querySelector('iframe').removeAttribute('sandbox');
// Thirdparty iframes should be allowed, unless they redirect to a URI with the null principal
yield runIFrame(thirdparty + "frameStorageAllowed.html");
yield runIFrame(thirdparty + "frameStorageNullprincipal.sjs");
yield runIFrame(thirdparty + "frameStorageChrome.html");
// Workers should be able to access storage
yield runWorker("workerStorageAllowed.js");
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,42 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Storage Permission Restrictions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="storagePermissionsUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe></iframe>
<script type="text/javascript">
task(function* () {
yield setCookieBehavior(BEHAVIOR_LIMIT_FOREIGN);
// We should be able to access storage
yield storageAllowed();
// Same origin iframes should be prevented, unless they have chrome privileges
yield runIFrame("frameStorageAllowed.html");
yield runIFrame("frameStorageNullprincipal.sjs");
yield runIFrame("frameStorageChrome.html");
// Sandboxed iframes should have the null principal, and thus can't access storage
document.querySelector('iframe').setAttribute('sandbox', 'allow-scripts');
yield runIFrame("frameStoragePrevented.html#nullprincipal");
yield runIFrame("frameStorageNullprincipal.sjs");
document.querySelector('iframe').removeAttribute('sandbox');
// Thirdparty iframes should be blocked, unless they have chrome privileges
yield runIFrame(thirdparty + "frameStoragePrevented.html#thirdparty");
yield runIFrame(thirdparty + "frameStorageNullprincipal.sjs");
yield runIFrame(thirdparty + "frameStorageChrome.html");
// Workers should be unable to access storage
yield runWorker("workerStorageAllowed.js");
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,41 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Storage Permission Restrictions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="storagePermissionsUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe></iframe>
<script type="text/javascript">
task(function* () {
yield setCookieBehavior(BEHAVIOR_REJECT);
// We should be unable to access storage
yield storagePrevented();
// Same origin iframes should be prevented, unless they have chrome privileges
yield runIFrame("frameStoragePrevented.html");
yield runIFrame("frameStorageNullprincipal.sjs");
yield runIFrame("frameStorageChrome.html");
// Sandboxed iframes should have the null principal, and thus can't access storage
document.querySelector('iframe').setAttribute('sandbox', 'allow-scripts');
yield runIFrame("frameStoragePrevented.html#nullprincipal");
yield runIFrame("frameStorageNullprincipal.sjs");
document.querySelector('iframe').removeAttribute('sandbox');
// thirdparty iframes should be blocked, unless they have chrome privileges
yield runIFrame(thirdparty + "frameStoragePrevented.html");
yield runIFrame(thirdparty + "frameStorageNullprincipal.sjs");
// Workers should be unable to access storage
yield runWorker("workerStoragePrevented.js");
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,42 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Storage Permission Restrictions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="storagePermissionsUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe></iframe>
<script type="text/javascript">
task(function* () {
yield setCookieBehavior(BEHAVIOR_REJECT_FOREIGN);
// We should be able to access storage
yield storageAllowed();
// Same origin iframes should be allowed, unless they redirect to a URI with the null principal
yield runIFrame("frameStorageAllowed.html");
yield runIFrame("frameStorageNullprincipal.sjs");
yield runIFrame("frameStorageChrome.html");
// Sandboxed iframes should have the null principal, and thus can't access storage
document.querySelector('iframe').setAttribute('sandbox', 'allow-scripts');
yield runIFrame("frameStoragePrevented.html#nullprincipal");
yield runIFrame("frameStorageNullprincipal.sjs");
document.querySelector('iframe').removeAttribute('sandbox');
// thirdparty iframes should be blocked, unless they have chrome privileges
yield runIFrame(thirdparty + "frameStoragePrevented.html#thirdparty");
yield runIFrame(thirdparty + "frameStorageNullprincipal.sjs");
yield runIFrame(thirdparty + "frameStorageChrome.html");
// Workers should be able to access storage
yield runWorker("workerStorageAllowed.js");
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,61 @@
// Unfortunately, workers can't share the code from storagePermissionsUtils.
// These are basic mechanisms for communicating to the test runner.
function ok(condition, text) {
if (!condition) {
self.postMessage("FAILURE: " + text);
} else {
self.postMessage(text);
}
}
function finishTest() {
self.postMessage("done");
self.close();
}
// Workers don't have access to localstorage or sessionstorage
ok(typeof self.localStorage == "undefined", "localStorage should be undefined");
ok(typeof self.sessionStorage == "undefined", "sessionStorage should be undefined");
// Make sure that we can access indexedDB
try {
indexedDB;
ok(true, "WORKER getting indexedDB didn't throw");
} catch (e) {
ok(false, "WORKER getting indexedDB should not throw");
}
// Make sure that we can access caches
try {
var promise = caches.keys();
ok(true, "WORKER getting caches didn't throw");
promise.then(function() {
ok(location.protocol == "https:", "WORKER The promise was not rejected");
workerTest();
}, function() {
ok(location.protocol != "https:", "WORKER The promise should not have been rejected");
workerTest();
});
} catch (e) {
ok(false, "WORKER getting caches should not have thrown");
}
// Try to spawn an inner worker, and make sure that it can also access storage
function workerTest() {
if (location.hash == "#inner") { // Don't recurse infinitely, if we are the inner worker, don't spawn another
finishTest();
return;
}
// Create the inner worker, and listen for test messages from it
var worker = new Worker("workerStorageAllowed.js#inner");
worker.addEventListener('message', function(e) {
if (e.data == "done") {
finishTest();
return;
}
ok(!e.data.match(/^FAILURE/), e.data + " (WORKER = workerStorageAllowed.js#inner)");
});
}

Просмотреть файл

@ -0,0 +1,61 @@
// Unfortunately, workers can't share the code from storagePermissionsUtils.
// These are basic mechanisms for communicating to the test runner.
function ok(condition, text) {
if (!condition) {
self.postMessage("FAILURE: " + text);
} else {
self.postMessage(text);
}
}
function finishTest() {
self.postMessage("done");
self.close();
}
// Workers don't have access to localstorage or sessionstorage
ok(typeof self.localStorage == "undefined", "localStorage should be undefined");
ok(typeof self.sessionStorage == "undefined", "sessionStorage should be undefined");
// Make sure that we can't access indexedDB
try {
indexedDB;
ok(false, "WORKER getting indexedDB should have thrown");
} catch (e) {
ok(true, "WORKER getting indexedDB threw");
}
// Make sure that we can't access caches
try {
var promise = caches.keys();
ok(true, "WORKER getting caches didn't throw");
promise.then(function() {
ok(false, "WORKER The promise should have rejected");
workerTest();
}, function() {
ok(true, "WORKER The promise was rejected");
workerTest();
});
} catch (e) {
ok(false, "WORKER getting caches should not have thrown");
}
// Try to spawn an inner worker, and make sure that it also can't access storage
function workerTest() {
if (location.hash == "#inner") { // Don't recurse infinitely, if we are the inner worker, don't spawn another
finishTest();
return;
}
// Create the inner worker, and listen for test messages from it
var worker = new Worker("workerStoragePrevented.js#inner");
worker.addEventListener('message', function(e) {
if (e.data == "done") {
finishTest();
return;
}
ok(!e.data.match(/^FAILURE/), e.data + " (WORKER = workerStoragePrevented.js#inner)");
});
}