diff options
Diffstat (limited to 'caps/tests')
21 files changed, 1812 insertions, 0 deletions
diff --git a/caps/tests/gtest/TestOriginAttributes.cpp b/caps/tests/gtest/TestOriginAttributes.cpp new file mode 100644 index 000000000..e11bf28eb --- /dev/null +++ b/caps/tests/gtest/TestOriginAttributes.cpp @@ -0,0 +1,38 @@ +/* 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/. */ +#include "gtest/gtest.h" +#include "mozilla/BasePrincipal.h" + +using mozilla::PrincipalOriginAttributes; + +static void +TestSuffix(const PrincipalOriginAttributes& attrs) +{ + nsAutoCString suffix; + attrs.CreateSuffix(suffix); + + PrincipalOriginAttributes attrsFromSuffix; + bool success = attrsFromSuffix.PopulateFromSuffix(suffix); + EXPECT_TRUE(success); + + EXPECT_EQ(attrs, attrsFromSuffix); +} + +TEST(PrincipalOriginAttributes, Suffix_default) +{ + PrincipalOriginAttributes attrs; + TestSuffix(attrs); +} + +TEST(PrincipalOriginAttributes, Suffix_appId_inIsolatedMozBrowser) +{ + PrincipalOriginAttributes attrs(1, true); + TestSuffix(attrs); +} + +TEST(PrincipalOriginAttributes, Suffix_maxAppId_inIsolatedMozBrowser) +{ + PrincipalOriginAttributes attrs(4294967295, true); + TestSuffix(attrs); +} diff --git a/caps/tests/gtest/moz.build b/caps/tests/gtest/moz.build new file mode 100644 index 000000000..26447f54c --- /dev/null +++ b/caps/tests/gtest/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +UNIFIED_SOURCES += [ + 'TestOriginAttributes.cpp' +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul-gtest' diff --git a/caps/tests/mochitest/browser.ini b/caps/tests/mochitest/browser.ini new file mode 100644 index 000000000..d8a1278f9 --- /dev/null +++ b/caps/tests/mochitest/browser.ini @@ -0,0 +1 @@ +[browser_checkloaduri.js] diff --git a/caps/tests/mochitest/browser_checkloaduri.js b/caps/tests/mochitest/browser_checkloaduri.js new file mode 100644 index 000000000..24a97c1c4 --- /dev/null +++ b/caps/tests/mochitest/browser_checkloaduri.js @@ -0,0 +1,292 @@ +"use strict"; + +let ssm = Services.scriptSecurityManager; +// This will show a directory listing, but we never actually load these so that's OK. +const kDummyPage = getRootDirectory(gTestPath); + +const kAboutPagesRegistered = Promise.all([ + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-chrome-privs", kDummyPage, + Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-chrome-privs2", kDummyPage, + Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-unknown-linkable", kDummyPage, + Ci.nsIAboutModule.MAKE_LINKABLE | Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-unknown-linkable2", kDummyPage, + Ci.nsIAboutModule.MAKE_LINKABLE | Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-unknown-unlinkable", kDummyPage, + Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-unknown-unlinkable2", kDummyPage, + Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-content-unlinkable", kDummyPage, + Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-content-unlinkable2", kDummyPage, + Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-content-linkable", kDummyPage, + Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | Ci.nsIAboutModule.MAKE_LINKABLE | + Ci.nsIAboutModule.ALLOW_SCRIPT), + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, "test-content-linkable2", kDummyPage, + Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | Ci.nsIAboutModule.MAKE_LINKABLE | + Ci.nsIAboutModule.ALLOW_SCRIPT), +]); + +const URLs = new Map([ + ["http://www.example.com", [ + // For each of these entries, the booleans represent whether the parent URI can: + // - load them + // - load them without principal inheritance + // - whether the URI can be created at all (some protocol handlers will + // refuse to create certain variants) + ["http://www.example2.com", true, true, true], + ["feed:http://www.example2.com", false, false, true], + ["https://www.example2.com", true, true, true], + ["chrome://foo/content/bar.xul", false, false, true], + ["feed:chrome://foo/content/bar.xul", false, false, false], + ["view-source:http://www.example2.com", false, false, true], + ["view-source:https://www.example2.com", false, false, true], + ["view-source:feed:http://www.example2.com", false, false, true], + ["feed:view-source:http://www.example2.com", false, false, false], + ["data:text/html,Hi", true, false, true], + ["view-source:data:text/html,Hi", false, false, true], + ["javascript:alert('hi')", true, false, true], + ["moz://a", false, false, true], + ["about:test-chrome-privs", false, false, true], + ["about:test-unknown-unlinkable", false, false, true], + ["about:test-content-unlinkable", false, false, true], + ["about:test-content-linkable", true, true, true], + // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: + ["about:test-unknown-linkable", false, false, true], + ]], + ["feed:http://www.example.com", [ + ["http://www.example2.com", true, true, true], + ["feed:http://www.example2.com", true, true, true], + ["https://www.example2.com", true, true, true], + ["feed:https://www.example2.com", true, true, true], + ["chrome://foo/content/bar.xul", false, false, true], + ["feed:chrome://foo/content/bar.xul", false, false, false], + ["view-source:http://www.example2.com", false, false, true], + ["view-source:https://www.example2.com", false, false, true], + ["view-source:feed:http://www.example2.com", false, false, true], + ["feed:view-source:http://www.example2.com", false, false, false], + ["data:text/html,Hi", true, false, true], + ["view-source:data:text/html,Hi", false, false, true], + ["javascript:alert('hi')", true, false, true], + ["moz://a", false, false, true], + ["about:test-chrome-privs", false, false, true], + ["about:test-unknown-unlinkable", false, false, true], + ["about:test-content-unlinkable", false, false, true], + ["about:test-content-linkable", true, true, true], + // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: + ["about:test-unknown-linkable", false, false, true], + ]], + ["view-source:http://www.example.com", [ + ["http://www.example2.com", true, true, true], + ["feed:http://www.example2.com", false, false, true], + ["https://www.example2.com", true, true, true], + ["feed:https://www.example2.com", false, false, true], + ["chrome://foo/content/bar.xul", false, false, true], + ["feed:chrome://foo/content/bar.xul", false, false, false], + ["view-source:http://www.example2.com", true, true, true], + ["view-source:https://www.example2.com", true, true, true], + ["view-source:feed:http://www.example2.com", false, false, true], + ["feed:view-source:http://www.example2.com", false, false, false], + ["data:text/html,Hi", true, false, true], + ["view-source:data:text/html,Hi", true, false, true], + ["javascript:alert('hi')", true, false, true], + ["moz://a", false, false, true], + ["about:test-chrome-privs", false, false, true], + ["about:test-unknown-unlinkable", false, false, true], + ["about:test-content-unlinkable", false, false, true], + ["about:test-content-linkable", true, true, true], + // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: + ["about:test-unknown-linkable", false, false, true], + ]], + // about: related tests. + ["about:test-chrome-privs", [ + ["about:test-chrome-privs", true, true, true], + ["about:test-chrome-privs2", true, true, true], + ["about:test-chrome-privs2?foo#bar", true, true, true], + ["about:test-chrome-privs2?foo", true, true, true], + ["about:test-chrome-privs2#bar", true, true, true], + + ["about:test-unknown-unlinkable", true, true, true], + + ["about:test-content-unlinkable", true, true, true], + ["about:test-content-unlinkable?foo", true, true, true], + ["about:test-content-unlinkable?foo#bar", true, true, true], + ["about:test-content-unlinkable#bar", true, true, true], + + ["about:test-content-linkable", true, true, true], + + ["about:test-unknown-linkable", true, true, true], + ]], + ["about:test-unknown-unlinkable", [ + ["about:test-chrome-privs", false, false, true], + + // Can link to ourselves: + ["about:test-unknown-unlinkable", true, true, true], + // Can't link to unlinkable content if we're not sure it's privileged: + ["about:test-unknown-unlinkable2", false, false, true], + + ["about:test-content-unlinkable", true, true, true], + ["about:test-content-unlinkable2", true, true, true], + ["about:test-content-unlinkable2?foo", true, true, true], + ["about:test-content-unlinkable2?foo#bar", true, true, true], + ["about:test-content-unlinkable2#bar", true, true, true], + + ["about:test-content-linkable", true, true, true], + + // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: + ["about:test-unknown-linkable", false, false, true], + ]], + ["about:test-content-unlinkable", [ + ["about:test-chrome-privs", false, false, true], + + // Can't link to unlinkable content if we're not sure it's privileged: + ["about:test-unknown-unlinkable", false, false, true], + + ["about:test-content-unlinkable", true, true, true], + ["about:test-content-unlinkable2", true, true, true], + ["about:test-content-unlinkable2?foo", true, true, true], + ["about:test-content-unlinkable2?foo#bar", true, true, true], + ["about:test-content-unlinkable2#bar", true, true, true], + + ["about:test-content-linkable", true, true, true], + ["about:test-unknown-linkable", false, false, true], + ]], + ["about:test-unknown-linkable", [ + ["about:test-chrome-privs", false, false, true], + + // Linkable content can't link to unlinkable content. + ["about:test-unknown-unlinkable", false, false, true], + + ["about:test-content-unlinkable", false, false, true], + ["about:test-content-unlinkable2", false, false, true], + ["about:test-content-unlinkable2?foo", false, false, true], + ["about:test-content-unlinkable2?foo#bar", false, false, true], + ["about:test-content-unlinkable2#bar", false, false, true], + + // ... but it can link to other linkable content. + ["about:test-content-linkable", true, true, true], + + // Can link to ourselves: + ["about:test-unknown-linkable", true, true, true], + + // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: + ["about:test-unknown-linkable2", false, false, true], + ]], + ["about:test-content-linkable", [ + ["about:test-chrome-privs", false, false, true], + + // Linkable content can't link to unlinkable content. + ["about:test-unknown-unlinkable", false, false, true], + + ["about:test-content-unlinkable", false, false, true], + + // ... but it can link to itself and other linkable content. + ["about:test-content-linkable", true, true, true], + ["about:test-content-linkable2", true, true, true], + + // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: + ["about:test-unknown-linkable", false, false, true], + ]], +]); + +function testURL(source, target, canLoad, canLoadWithoutInherit, canCreate, flags) { + function getPrincipalDesc(principal) { + if (principal.URI) { + return principal.URI.spec; + } + if (principal.isSystemPrincipal) { + return "system principal"; + } + if (principal.isNullPrincipal) { + return "null principal"; + } + return "unknown principal"; + } + let threw = false; + let targetURI; + try { + targetURI = makeURI(target); + } catch (ex) { + ok(!canCreate, "Shouldn't be passing URIs that we can't create. Failed to create: " + target); + return; + } + ok(canCreate, "Created a URI for " + target + " which should " + + (canCreate ? "" : "not ") + "be possible."); + try { + ssm.checkLoadURIWithPrincipal(source, targetURI, flags); + } catch (ex) { + info(ex.message); + threw = true; + } + let inheritDisallowed = flags & ssm.DISALLOW_INHERIT_PRINCIPAL; + let shouldThrow = inheritDisallowed ? !canLoadWithoutInherit : !canLoad; + ok(threw == shouldThrow, + "Should " + (shouldThrow ? "" : "not ") + "throw an error when loading " + + target + " from " + getPrincipalDesc(source) + + (inheritDisallowed ? " without" : " with") + " principal inheritance."); +} + +add_task(function* () { + yield kAboutPagesRegistered; + let baseFlags = ssm.STANDARD | ssm.DONT_REPORT_ERRORS; + for (let [sourceString, targetsAndExpectations] of URLs) { + let source; + if (sourceString.startsWith("about:test-chrome-privs")) { + source = ssm.getSystemPrincipal(); + } else { + source = ssm.createCodebasePrincipal(makeURI(sourceString), {}); + } + for (let [target, canLoad, canLoadWithoutInherit, canCreate] of targetsAndExpectations) { + testURL(source, target, canLoad, canLoadWithoutInherit, canCreate, baseFlags); + testURL(source, target, canLoad, canLoadWithoutInherit, canCreate, + baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL); + } + } + + // Now test blob URIs, which we need to do in-content. + yield BrowserTestUtils.withNewTab("http://www.example.com/", function* (browser) { + yield ContentTask.spawn( + browser, + testURL.toString(), + function* (testURLFn) { + let testURL = eval("(" + testURLFn + ")"); + let ssm = Services.scriptSecurityManager; + let baseFlags = ssm.STANDARD | ssm.DONT_REPORT_ERRORS; + let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI; + let b = new content.Blob(["I am a blob"]); + let contentBlobURI = content.URL.createObjectURL(b); + let contentPrincipal = content.document.nodePrincipal; + // Loading this blob URI from the content page should work: + testURL(contentPrincipal, contentBlobURI, true, true, true, baseFlags); + testURL(contentPrincipal, contentBlobURI, true, true, true, + baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL); + + testURL(contentPrincipal, "view-source:" + contentBlobURI, false, false, true, + baseFlags); + testURL(contentPrincipal, "view-source:" + contentBlobURI, false, false, true, + baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL); + + // Feed URIs for blobs can't be created, so need to pass false as the fourth param. + for (let prefix of ["feed:", "view-source:feed:", "feed:view-source:"]) { + testURL(contentPrincipal, prefix + contentBlobURI, false, false, false, + baseFlags); + testURL(contentPrincipal, prefix + contentBlobURI, false, false, false, + baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL); + } + } + ); + + }); +}); diff --git a/caps/tests/mochitest/chrome.ini b/caps/tests/mochitest/chrome.ini new file mode 100644 index 000000000..ee71ad30b --- /dev/null +++ b/caps/tests/mochitest/chrome.ini @@ -0,0 +1,9 @@ +[DEFAULT] +skip-if = os == 'android' +support-files = + file_disableScript.html + !/caps/tests/mochitest/file_disableScript.html + +[test_bug995943.xul] +[test_addonMayLoad.html] +[test_disableScript.xul] diff --git a/caps/tests/mochitest/file_data.txt b/caps/tests/mochitest/file_data.txt new file mode 100644 index 000000000..26d7bd848 --- /dev/null +++ b/caps/tests/mochitest/file_data.txt @@ -0,0 +1 @@ +server data fetched over XHR diff --git a/caps/tests/mochitest/file_disableScript.html b/caps/tests/mochitest/file_disableScript.html new file mode 100644 index 000000000..f4888cd58 --- /dev/null +++ b/caps/tests/mochitest/file_disableScript.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> +<script> +var gFiredOnload = false; +var gFiredOnclick = false; +</script> +</head> +<body onload="gFiredOnload = true;" onclick="gFiredOnclick = true;"> +</body> +</html> diff --git a/caps/tests/mochitest/mochitest.ini b/caps/tests/mochitest/mochitest.ini new file mode 100644 index 000000000..866553ea2 --- /dev/null +++ b/caps/tests/mochitest/mochitest.ini @@ -0,0 +1,13 @@ +[DEFAULT] +support-files = + file_data.txt + file_disableScript.html + !/js/xpconnect/tests/mochitest/file_empty.html + +[test_app_principal_equality.html] +[test_bug246699.html] +[test_bug292789.html] +[test_bug423375.html] +[test_bug470804.html] +[test_disallowInheritPrincipal.html] +[test_extensionURL.html] diff --git a/caps/tests/mochitest/resource_test_file.html b/caps/tests/mochitest/resource_test_file.html new file mode 100644 index 000000000..8201bd70e --- /dev/null +++ b/caps/tests/mochitest/resource_test_file.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<html><head><title>resource test file</title></head><body></body></html> diff --git a/caps/tests/mochitest/test_addonMayLoad.html b/caps/tests/mochitest/test_addonMayLoad.html new file mode 100644 index 000000000..286284bfe --- /dev/null +++ b/caps/tests/mochitest/test_addonMayLoad.html @@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1180921 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1180921</title> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://global/skin"/> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> + <script type="application/javascript;version=1.8"> + + /** Test for Bug 1180921 **/ + const Cc = Components.classes; + const Ci = Components.interfaces; + const Cu = Components.utils; + Cu.import("resource://gre/modules/Services.jsm"); + let ssm = Services.scriptSecurityManager; + let aps = Cc["@mozilla.org/addons/policy-service;1"].getService(Ci.nsIAddonPolicyService).wrappedJSObject; + + SimpleTest.waitForExplicitFinish(); + SimpleTest.registerCleanupFunction(function() { + aps.setAddonLoadURICallback('addonA', null); + aps.setAddonLoadURICallback('addonB', null); + }); + + function tryLoad(sb, uri) { + let p = new Promise(function(resolve, reject) { + Cu.exportFunction(resolve, sb, { defineAs: "finish" }); + Cu.exportFunction(reject, sb, { defineAs: "error" }); + sb.eval("try { (function () { " + + " var xhr = new XMLHttpRequest();" + + " xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE) { finish(xhr.status == 200); } };" + + " xhr.open('GET', '" + uri + "', true);" + + " xhr.send();" + + "})() } catch (e) { error(e); }"); + }); + return p; + } + + let exampleCom_addonA = new Cu.Sandbox(ssm.createCodebasePrincipal(Services.io.newURI('http://example.com', null, null), {addonId: 'addonA'}), + {wantGlobalProperties: ['XMLHttpRequest']}); + let nullPrin_addonA = new Cu.Sandbox(ssm.createNullPrincipal({addonId: 'addonA'}), + {wantGlobalProperties: ['XMLHttpRequest']}); + let exampleCom_addonB = new Cu.Sandbox(ssm.createCodebasePrincipal(Services.io.newURI('http://example.com', null, null), {addonId: 'addonB'}), + {wantGlobalProperties: ['XMLHttpRequest']}); + + function uriForDomain(d) { return d + '/tests/caps/tests/mochitest/file_data.txt' } + + tryLoad(exampleCom_addonA, uriForDomain('http://example.com')) + .then(function(success) { + ok(success, "same-origin load should succeed for addon A"); + return tryLoad(nullPrin_addonA, uriForDomain('http://example.com')); + }).then(function(success) { + ok(!success, "null-principal load should fail for addon A"); + return tryLoad(exampleCom_addonB, uriForDomain('http://example.com')); + }).then(function(success) { + ok(success, "same-origin load should succeed for addon B"); + return tryLoad(exampleCom_addonA, uriForDomain('http://test1.example.org')); + }).then(function(success) { + ok(!success, "cross-origin load should fail for addon A"); + aps.setAddonLoadURICallback('addonA', function(uri) { return /test1/.test(uri.host); }); + aps.setAddonLoadURICallback('addonB', function(uri) { return /test2/.test(uri.host); }); + return tryLoad(exampleCom_addonA, uriForDomain('http://test1.example.org')); + }).then(function(success) { + ok(success, "whitelisted cross-origin load of test1 should succeed for addon A"); + return tryLoad(nullPrin_addonA, uriForDomain('http://test1.example.org')); + }).then(function(success) { + ok(!success, "whitelisted null principal load of test1 should still fail for addon A"); + return tryLoad(exampleCom_addonB, uriForDomain('http://test1.example.org')); + }).then(function(success) { + ok(!success, "non-whitelisted cross-origin load of test1 should fail for addon B"); + return tryLoad(exampleCom_addonB, uriForDomain('http://test2.example.org')); + }).then(function(success) { + ok(success, "whitelisted cross-origin load of test2 should succeed for addon B"); + return tryLoad(exampleCom_addonA, uriForDomain('http://test2.example.org')); + }).then(function(success) { + ok(!success, "non-whitelisted cross-origin load of test2 should fail for addon A"); + SimpleTest.finish(); + }, function(e) { + ok(false, "Rejected promise chain: " + e); + SimpleTest.finish(); + }); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1180921">Mozilla Bug 1180921</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/caps/tests/mochitest/test_app_principal_equality.html b/caps/tests/mochitest/test_app_principal_equality.html new file mode 100644 index 000000000..f59f1f789 --- /dev/null +++ b/caps/tests/mochitest/test_app_principal_equality.html @@ -0,0 +1,88 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=777467 +--> +<head> + <meta charset="utf-8"> + <title>Test app principal's equality</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777467">Mozilla Bug 777467</a> +<p id="display"></p> +<script> + +/** Test for app principal's equality **/ + +SimpleTest.waitForExplicitFinish(); + +var permissions = new Promise(resolve => { + SpecialPowers.pushPermissions( + [{ type: "browser", allow: true, context: document }, + { type: "embed-apps", allow: true, context: document }], + resolve); +}); + +permissions.then(() => { + $('content').innerHTML = + '<iframe src="error404"></iframe>\n' + + '<iframe mozbrowser src="error404"></iframe>\n' + + '<iframe mozapp="http://example.org/manifest.webapp" mozbrowser src="error404"></iframe>'; + + var iframes = document.getElementsByTagName("iframe"); + var promises = [] + for (var i = 0; i < promises.length; ++i) { + promises.push(new Promise(resolve => { + iframes[i].addEventListener("load", resolve); + })); + } + + return Promise.all(promises); +}); + +var prefs = new Promise(resolve => { + SpecialPowers.pushPrefEnv( + { set: [[ "dom.mozBrowserFramesEnabled", true ], + [ "dom.ipc.browser_frames.oop_by_default", false ]] }, + resolve); +}); +</script> +<div id="content" style="display: none;"> +</div> +<pre id="test"> +<script type="application/javascript"> + +function canAccessDocument(win) { + var result = true; + try { + win.document; + } catch(e) { + result = false; + } + return result; +} + +var loaded = new Promise(resolve => addLoadEvent(resolve)); + +Promise.all([ permissions, prefs, loaded ]).then(runTest); + +function runTest() { + // Test the witness frame (we can access same-origin frame). + is(canAccessDocument(frames[0]), true, + "should be able to access the first frame"); + + // Test different app/browserElement frames. + for (var i=1; i<frames.length; ++i) { + is(canAccessDocument(frames[i]), false, + "should not be able to access the other frames"); + } + + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/caps/tests/mochitest/test_bug246699.html b/caps/tests/mochitest/test_bug246699.html new file mode 100644 index 000000000..bb733e5df --- /dev/null +++ b/caps/tests/mochitest/test_bug246699.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=246699 +--> +<head> + <title>Test for Bug 246699</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=246699">Mozilla Bug 246699</a> +<p id="display"></p> +<div id="content" style="display: none"> +<iframe id="load-frame"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** + ** Test for Bug 246699 + ** (should produce stack information for caps errors) + **/ +function isError(e) +{ + return e.constructor.name === "Error" || e.constructor.name === "TypeError"; +} + +function hasStack(e) +{ + return isError(e) && /inciteCaps/.test(e.stack); +} + +function inciteCaps(f) +{ + try { + f(); + return "operation succeeded"; + } catch (e if hasStack(e)) { + return "denied-stack"; + } catch (e) { + return "unexpected: " + e; + } +} + +function tryChromeLoad() +{ + window.frames[0].location = "chrome://global/content/mozilla.xhtml"; +} + +function tryComponentsClasses() +{ + return SpecialPowers.Components.classes["@mozilla.org/dummy;1"]; +} + + +is(inciteCaps(tryChromeLoad), "denied-stack", + "should get stack for content-loading-chrome rejection"); +is(inciteCaps(tryComponentsClasses), "denied-stack", + "should get stack for SpecialPowers.Components.classes rejection"); +</script> +</pre> +</body> +</html> + diff --git a/caps/tests/mochitest/test_bug292789.html b/caps/tests/mochitest/test_bug292789.html new file mode 100644 index 000000000..291ba00c1 --- /dev/null +++ b/caps/tests/mochitest/test_bug292789.html @@ -0,0 +1,105 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=292789 +--> +<head> + <title>Test for Bug 292789</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=292789">Mozilla Bug 292789</a> +<p id="display"></p> +<div id="content" style="display: none"> + <script src="chrome://global/content/treeUtils.js"></script> + <script type="application/javascript;version=1.8" src="chrome://mozapps/content/xpinstall/xpinstallConfirm.js"></script> + <script id="resjs" type="application/javascript;version=1.8"></script> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 292789 + ** + ** Selectively allow access to whitelisted chrome packages + ** even for ALLOW_CHROME mechanisms (<script>, <img> etc) + **/ + +SimpleTest.waitForExplicitFinish(); + +/** <script src=""> test **/ +function testScriptSrc(aCallback) { + is(typeof gTreeUtils.sort, "function", + "content can still load <script> from chrome://global"); + is(typeof XPInstallConfirm, "undefined", + "content should not be able to load <script> from chrome://mozapps"); + + /** make sure the last one didn't pass because someone + ** moved the resource + **/ + var resjs = document.getElementById("resjs"); + resjs.onload = scriptOnload; + resjs.src = "resource://gre/chrome/toolkit/content/mozapps/xpinstall/xpinstallConfirm.js"; + document.getElementById("content").appendChild(resjs); + + function scriptOnload() { + is(typeof XPInstallConfirm, "object", + "xpinstallConfirm.js has not moved unexpectedly"); + + // trigger the callback + if (aCallback) + aCallback(); + } +} + +/** <img src=""> tests **/ +var img_global = "chrome://global/skin/icons/Error.png"; +var img_mozapps = "chrome://mozapps/skin/plugins/contentPluginClose.png"; +var res_mozapps = "resource://gre/chrome/toolkit/skin/classic/mozapps/plugins/contentPluginClose.png"; + +var imgTests = [[img_global, "success"], + [img_mozapps, "fail"], + [res_mozapps, "success"]]; + +var curImgTest = 0; + +function runImgTest() { + var test = imgTests[curImgTest++]; + var callback = curImgTest == imgTests.length ? finishTest : runImgTest; + loadImage(test[0], test[1], callback); +} + +function finishTest() { + SimpleTest.finish(); +} + +function fail(event) { + is("fail", event.target.expected, + "content should not be allowed to load "+event.target.src); + if (event.target.callback) + event.target.callback(); +} + +function success(event) { + is("success", event.target.expected, + "content should be able to load "+event.target.src); + if (event.target.callback) + event.target.callback(); +} + +function loadImage(uri, expect, callback) { + var img = document.createElement("img"); + img.onerror = fail; + img.onload = success; + img.expected = expect; + img.callback = callback; + img.src = uri; + //document.getElementById("content").appendChild(img); +} + +// Start off the script src test, and have it start the img tests when complete. +testScriptSrc(runImgTest); +</script> +</pre> +</body> +</html> diff --git a/caps/tests/mochitest/test_bug423375.html b/caps/tests/mochitest/test_bug423375.html new file mode 100644 index 000000000..1cd2a7a82 --- /dev/null +++ b/caps/tests/mochitest/test_bug423375.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=423375 +--> +<head> + <title>Test for Bug 423375</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=423375">Mozilla Bug 423375</a> +<p id="display"></p> +<div id="content" style="display: none"> +<iframe id="load-frame"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** + ** Test for Bug 423375 + ** (content shouldn't be able to load chrome: or resource:) + **/ +function tryLoad(url) +{ + try { + window.frames[0].location = url; + return "loaded"; + } catch (e if /Access.*denied/.test(String(e))) { + return "denied"; + } catch (e) { + return "unexpected: " + e; + } +} + +is(tryLoad("chrome://global/content/mozilla.xhtml"), "denied", + "content should have been prevented from loading chrome: URL"); +is(tryLoad("resource://gre-resources/html.css"), "denied", + "content should have been prevented from loading resource: URL"); +</script> +</pre> +</body> +</html> + diff --git a/caps/tests/mochitest/test_bug470804.html b/caps/tests/mochitest/test_bug470804.html new file mode 100644 index 000000000..9ac88c8d7 --- /dev/null +++ b/caps/tests/mochitest/test_bug470804.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=470804 +--> +<head> + <title>Test for Bug 470804</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=470804">Mozilla Bug 470804</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 470804 + Passing a null targetURL to checkLoadURIWithPrincipal shouldn't crash + **/ + +const nsIScriptSecurityManager = SpecialPowers.Ci.nsIScriptSecurityManager; +var secMan = SpecialPowers.Services.scriptSecurityManager; +var principal = SpecialPowers.wrap(document).nodePrincipal; +isnot(principal, undefined, "Should have a principal"); +isnot(principal, null, "Should have a non-null principal"); +is(secMan.isSystemPrincipal(principal), false, + "Shouldn't have system principal here"); +try { + secMan.checkLoadURIWithPrincipal(principal, null, + nsIScriptSecurityManager.STANDARD); +} catch (e) { + // throwing is fine, it's just crashing that's bad +} +ok(true, "Survival", "We should get here without crashing"); +</script> +</pre> +</body> +</html> diff --git a/caps/tests/mochitest/test_bug995943.xul b/caps/tests/mochitest/test_bug995943.xul new file mode 100644 index 000000000..e9eebb736 --- /dev/null +++ b/caps/tests/mochitest/test_bug995943.xul @@ -0,0 +1,115 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=995943 +--> +<window title="Mozilla Bug 995943" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + + <!-- test results are displayed in the html:body --> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=995943" + target="_blank">Mozilla Bug 995943</a> + </body> + + <!-- test code goes here --> + <script type="application/javascript"> + <![CDATA[ + const Cu = Components.utils; + const Cc = Components.classes; + const Ci = Components.interfaces; + Cu.import("resource://gre/modules/Services.jsm"); + function debug(msg) { info(msg); } + + /** Test for CAPS file:// URI prefs. **/ + SimpleTest.waitForExplicitFinish(); + SimpleTest.requestCompleteLog(); + if (navigator.userAgent.indexOf("Mac OS X 10.10") != -1) + SimpleTest.expectAssertions(5, 11); // See bug 1067022, 1307988 + else if (Services.appinfo.OS == "WINNT") + SimpleTest.expectAssertions(0, 1); // See bug 1067022 + else + SimpleTest.expectAssertions(0, 2); // See bug 1305241 + + var rootdir = Services.appinfo.OS == "WINNT" ? "file:///C:" : "file:///"; + + function checkLoadFileURI(domain, shouldLoad) { + debug("Invoking checkLoadFileURI with domain: " + domain + ", shouldLoad: " + shouldLoad); + return new Promise(function(resolve, reject) { + $('ifr').addEventListener('load', function l1() { + debug("Invoked l1 for " + domain); + $('ifr').removeEventListener('load', l1); + function l2() { + debug("Invoked l2 for " + domain); + $('ifr').removeEventListener('load', l2); + ok(shouldLoad, "Successfully loaded file:// URI for domain: " + domain); + resolve(); + } + $('ifr').addEventListener('load', l2); + try { + window[0].wrappedJSObject.location = rootdir; + debug("Successfully navigated for " + domain); + } catch (e) { + ok(!shouldLoad && /denied|insecure/.test(e), + "Prevented loading of file:// URI for domain: " + domain + " - " + e); + $('ifr').removeEventListener('load', l2); + resolve(); + } + }); + let targetURI = domain + '/tests/js/xpconnect/tests/mochitest/file_empty.html'; + debug("Navigating iframe to " + targetURI); + $('ifr').contentWindow.location = targetURI; + }); + } + + function pushPrefs(prefs) { + return new Promise(function(resolve) { SpecialPowers.pushPrefEnv({ set: prefs }, resolve); }); + } + + function popPrefs() { + return new Promise(function(resolve) { SpecialPowers.popPrefEnv(resolve); }); + } + + var gGoCount = 0; + function go() { + debug("Invoking go for window with id: " + window.getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID); + is(++gGoCount, 1, "Should only call go once!"); + checkLoadFileURI('http://example.com', false).then( + pushPrefs.bind(null, [['capability.policy.policynames', ' somepolicy '], + ['capability.policy.somepolicy.checkloaduri.enabled', 'AlLAcCeSs'], + ['capability.policy.somepolicy.sites', 'http://example.com']])) + .then(checkLoadFileURI.bind(null, 'http://example.com', true)) + .then(popPrefs) + .then(checkLoadFileURI.bind(null, 'http://example.com', false)) + .then( + pushPrefs.bind(null, [['capability.policy.policynames', ',somepolicy, someotherpolicy, '], + ['capability.policy.somepolicy.checkloaduri.enabled', 'allaccess'], + ['capability.policy.someotherpolicy.checkloaduri.enabled', 'nope'], + ['capability.policy.somepolicy.sites', ' http://example.org test1.example.com https://test2.example.com '], + ['capability.policy.someotherpolicy.sites', 'http://example.net ']])) + .then(checkLoadFileURI.bind(null, 'http://example.org', true)) + .then(checkLoadFileURI.bind(null, 'http://test2.example.com', false)) + .then(checkLoadFileURI.bind(null, 'https://test2.example.com', true)) + .then(checkLoadFileURI.bind(null, 'http://sub1.test2.example.com', false)) + .then(checkLoadFileURI.bind(null, 'https://sub1.test2.example.com', true)) + .then(checkLoadFileURI.bind(null, 'http://example.net', false)) + .then(checkLoadFileURI.bind(null, 'http://test1.example.com', true)) + .then(checkLoadFileURI.bind(null, 'https://test1.example.com', true)) + .then(checkLoadFileURI.bind(null, 'http://sub1.test1.example.com', true)) + .then(checkLoadFileURI.bind(null, 'https://sub1.test1.example.com', true)) + .then(pushPrefs.bind(null, [['capability.policy.someotherpolicy.checkloaduri.enabled', 'allAccess']])) + .then(checkLoadFileURI.bind(null, 'http://example.net', true)) + .then(popPrefs) + .then(popPrefs) + .then(checkLoadFileURI.bind(null, 'http://example.net', false)) + .then(SimpleTest.finish.bind(SimpleTest)); + + } + addLoadEvent(go); + + ]]> + </script> + <iframe id="ifr" type="content" /> +</window> diff --git a/caps/tests/mochitest/test_disableScript.xul b/caps/tests/mochitest/test_disableScript.xul new file mode 100644 index 000000000..cef5f401a --- /dev/null +++ b/caps/tests/mochitest/test_disableScript.xul @@ -0,0 +1,339 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=840488 +--> +<window title="Mozilla Bug 840488" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + + <!-- test results are displayed in the html:body --> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=840488" + target="_blank">Mozilla Bug 840488</a> + </body> + + <iframe id="root" name="root" type="content"/> + <iframe id="chromeFrame" name="chromeFrame" type="content"/> + + <!-- test code goes here --> + <script type="application/javascript"> + <![CDATA[ + + /** Test for all the different ways that script can be disabled for a given global. **/ + + SimpleTest.waitForExplicitFinish(); + const Cu = Components.utils; + const Ci = Components.interfaces; + Cu.import("resource://gre/modules/Promise.jsm"); + Cu.import("resource://gre/modules/Services.jsm"); + const ssm = Services.scriptSecurityManager; + function makeURI(uri) { return Services.io.newURI(uri, null, null); } + const path = "/tests/caps/tests/mochitest/file_disableScript.html"; + const uri = "http://www.example.com" + path; + var rootFrame = document.getElementById('root'); + var chromeFrame = document.getElementById('chromeFrame'); + navigateFrame(rootFrame, uri + "?name=rootframe").then(function() { + navigateFrame(chromeFrame, "file_disableScript.html").then(go); + }); + + function navigateFrame(ifr, src) { + let deferred = Promise.defer(); + function onload() { + ifr.removeEventListener('load', onload); + deferred.resolve(); + } + ifr.addEventListener('load', onload, false); + ifr.setAttribute('src', src); + return deferred.promise; + } + + function navigateBack(ifr) { + let deferred = Promise.defer(); + + // pageshow events don't fire on the iframe element, so we need to use the + // chrome event handler for the docshell. + var browser = ifr.contentWindow + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler; + function onpageshow(evt) { + info("Navigated back. Persisted: " + evt.persisted); + browser.removeEventListener('pageshow', onpageshow); + deferred.resolve(); + } + browser.addEventListener('pageshow', onpageshow, false); + ifr.contentWindow.history.back(); + return deferred.promise; + } + + function addFrame(parentWin, name, expectOnload) { + let ifr = parentWin.document.createElement('iframe'); + parentWin.document.body.appendChild(ifr); + ifr.setAttribute('name', name); + let deferred = Promise.defer(); + // We need to append 'name' to avoid running afoul of recursive frame detection. + let frameURI = uri + "?name=" + name; + navigateFrame(ifr, frameURI).then(function() { + is(String(ifr.contentWindow.location), frameURI, "Successful load"); + is(!!ifr.contentWindow.wrappedJSObject.gFiredOnload, expectOnload, + "onload should only fire when scripts are enabled"); + deferred.resolve(); + }); + return deferred.promise; + } + + function checkScriptEnabled(win, expectEnabled) { + win.wrappedJSObject.gFiredOnclick = false; + win.document.body.dispatchEvent(new win.Event('click')); + is(win.wrappedJSObject.gFiredOnclick, expectEnabled, "Checking script-enabled for " + win.name + " (" + win.location + ")"); + } + + function setScriptEnabledForDocShell(win, enabled) { + win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell) + .allowJavascript = enabled; + } + + function testList(expectEnabled, win, list, idx) { + idx = idx || 0; + let deferred = Promise.defer(); + let target = list[idx] + path; + info("Testing scriptability for: " + target + ". expecting " + expectEnabled); + navigateFrame(win.frameElement, target).then(function() { + checkScriptEnabled(win, expectEnabled); + if (idx == list.length - 1) + deferred.resolve(); + else + testList(expectEnabled, win, list, idx + 1).then(function() { deferred.resolve(); }); + }); + return deferred.promise; + } + + function testDomainPolicy(defaultScriptability, exceptions, superExceptions, + exempt, notExempt, set, superSet, win) { + // Populate our sets. + for (var e of exceptions) + set.add(makeURI(e)); + for (var e of superExceptions) + superSet.add(makeURI(e)); + + return testList(defaultScriptability, win, notExempt).then(function() { + return testList(!defaultScriptability, win, exempt); + }); + } + + function setScriptEnabledForBrowser(enabled) { + var prefname = "javascript.enabled"; + Services.prefs.setBoolPref(prefname, enabled); + } + + function reloadFrame(frame) { + let deferred = Promise.defer(); + frame.addEventListener('load', function onload() { + deferred.resolve(); + frame.removeEventListener('load', onload); + }, false); + frame.contentWindow.location.reload(true); + return deferred.promise; + } + + function go() { + var rootWin = rootFrame.contentWindow; + var chromeWin = chromeFrame.contentWindow; + + // Test simple docshell enable/disable. + checkScriptEnabled(rootWin, true); + setScriptEnabledForDocShell(rootWin, false); + checkScriptEnabled(rootWin, false); + setScriptEnabledForDocShell(rootWin, true); + checkScriptEnabled(rootWin, true); + + // Privileged frames are immune to docshell flags. + ok(ssm.isSystemPrincipal(chromeWin.document.nodePrincipal), "Sanity check for System Principal"); + setScriptEnabledForDocShell(chromeWin, false); + checkScriptEnabled(chromeWin, true); + setScriptEnabledForDocShell(chromeWin, true); + + // Play around with the docshell tree and make sure everything works as + // we expect. + addFrame(rootWin, 'parent', true).then(function() { + checkScriptEnabled(rootWin[0], true); + return addFrame(rootWin[0], 'childA', true); + }).then(function() { + checkScriptEnabled(rootWin[0][0], true); + setScriptEnabledForDocShell(rootWin[0], false); + checkScriptEnabled(rootWin, true); + checkScriptEnabled(rootWin[0], false); + checkScriptEnabled(rootWin[0][0], false); + return addFrame(rootWin[0], 'childB', false); + }).then(function() { + checkScriptEnabled(rootWin[0][1], false); + setScriptEnabledForDocShell(rootWin[0][0], false); + setScriptEnabledForDocShell(rootWin[0], true); + checkScriptEnabled(rootWin[0], true); + checkScriptEnabled(rootWin[0][0], false); + setScriptEnabledForDocShell(rootWin[0][0], true); + + // Flags are inherited from the parent docshell at attach time. Note that + // the flag itself is inherited, regardless of whether or not scripts are + // currently allowed on the parent (which could depend on the parent's + // parent). Check that. + checkScriptEnabled(rootWin[0][1], false); + setScriptEnabledForDocShell(rootWin[0], false); + setScriptEnabledForDocShell(rootWin[0][1], true); + return addFrame(rootWin[0][1], 'grandchild', false); + }).then(function() { + checkScriptEnabled(rootWin[0], false); + checkScriptEnabled(rootWin[0][1], false); + checkScriptEnabled(rootWin[0][1][0], false); + setScriptEnabledForDocShell(rootWin[0], true); + checkScriptEnabled(rootWin[0], true); + checkScriptEnabled(rootWin[0][1], true); + checkScriptEnabled(rootWin[0][1][0], true); + + // Try navigating two frames, then munging docshell scriptability, then + // pulling the frames out of the bfcache to make sure that flags are + // properly propagated to inactive inner windows. We do this both for an + // 'own' docshell, as well as for an ancestor docshell. + return navigateFrame(rootWin[0][0].frameElement, rootWin[0][0].location + '-navigated'); + }).then(function() { return navigateFrame(rootWin[0][1][0].frameElement, rootWin[0][1][0].location + '-navigated'); }) + .then(function() { + checkScriptEnabled(rootWin[0][0], true); + checkScriptEnabled(rootWin[0][1][0], true); + setScriptEnabledForDocShell(rootWin[0][0], false); + setScriptEnabledForDocShell(rootWin[0][1], false); + checkScriptEnabled(rootWin[0][0], false); + checkScriptEnabled(rootWin[0][1][0], false); + return navigateBack(rootWin[0][0].frameElement); + }).then(function() { return navigateBack(rootWin[0][1][0].frameElement); }) + .then(function() { + checkScriptEnabled(rootWin[0][0], false); + checkScriptEnabled(rootWin[0][1][0], false); + + // Disable JS via the global pref pref. This is only guaranteed to have an effect + // for subsequent loads. + setScriptEnabledForBrowser(false); + return reloadFrame(rootFrame); + }).then(function() { + checkScriptEnabled(rootWin, false); + checkScriptEnabled(chromeWin, true); + setScriptEnabledForBrowser(true); + return reloadFrame(rootFrame); + }).then(function() { + checkScriptEnabled(rootWin, true); + + // Play around with dynamically blocking script for a given global. + // This takes effect immediately. + Cu.blockScriptForGlobal(rootWin); + Cu.blockScriptForGlobal(rootWin); + Cu.unblockScriptForGlobal(rootWin); + checkScriptEnabled(rootWin, false); + Cu.unblockScriptForGlobal(rootWin); + checkScriptEnabled(rootWin, true); + Cu.blockScriptForGlobal(rootWin); + try { + Cu.blockScriptForGlobal(chromeWin); + ok(false, "Should have thrown"); + } catch (e) { + ok(/may not be disabled/.test(e), + "Shouldn't be able to programmatically block script for system globals"); + } + return reloadFrame(rootFrame); + }).then(function() { + checkScriptEnabled(rootWin, true); + + // Test system-wide domain policy. This only takes effect for subsequently- + // loaded globals. + + // Check the basic semantics of the sets. + is(ssm.domainPolicyActive, false, "not enabled"); + window.policy = ssm.activateDomainPolicy(); + ok(policy instanceof Ci.nsIDomainPolicy, "Got a policy"); + try { + ssm.activateDomainPolicy(); + ok(false, "Should have thrown"); + } catch (e) { + ok(true, "can't have two live domain policies"); + } + var sbRef = policy.superBlacklist; + isnot(sbRef, null, "superBlacklist non-null"); + ok(!sbRef.contains(makeURI('http://www.example.com'))); + sbRef.add(makeURI('http://www.example.com/foopy')); + ok(sbRef.contains(makeURI('http://www.example.com'))); + sbRef.remove(makeURI('http://www.example.com')); + ok(!sbRef.contains(makeURI('http://www.example.com'))); + sbRef.add(makeURI('http://www.example.com/foopy/this.that/')); + ok(sbRef.contains(makeURI('http://www.example.com/baz'))); + ok(!sbRef.contains(makeURI('https://www.example.com'))); + ok(!sbRef.contains(makeURI('https://www.example.com:88'))); + ok(!sbRef.contains(makeURI('http://foo.www.example.com'))); + ok(sbRef.containsSuperDomain(makeURI('http://foo.www.example.com'))); + ok(sbRef.containsSuperDomain(makeURI('http://foo.bar.www.example.com'))); + ok(!sbRef.containsSuperDomain(makeURI('http://foo.bar.www.exxample.com'))); + ok(!sbRef.containsSuperDomain(makeURI('http://example.com'))); + ok(!sbRef.containsSuperDomain(makeURI('http://com/this.that/'))); + ok(!sbRef.containsSuperDomain(makeURI('https://foo.www.example.com'))); + ok(sbRef.contains(makeURI('http://www.example.com'))); + policy.deactivate(); + is(ssm.domainPolicyActive, false, "back to inactive"); + ok(!sbRef.contains(makeURI('http://www.example.com')), + "Disabling domain policy clears the set"); + policy = ssm.activateDomainPolicy(); + ok(policy.superBlacklist); + isnot(sbRef, policy.superBlacklist, "Mint new sets each time!"); + policy.deactivate(); + is(policy.blacklist, null, "blacklist nulled out"); + policy = ssm.activateDomainPolicy(); + isnot(policy.blacklist, null, "non-null again"); + isnot(policy.blacklist, sbRef, "freshly minted"); + policy.deactivate(); + + // + // Now, create and apply a mock-policy. We check the same policy both as + // a blacklist and as a whitelist. + // + + window.testPolicy = { + // The policy. + exceptions: ['http://test1.example.com', 'http://example.com'], + superExceptions: ['http://test2.example.org', 'https://test1.example.com'], + + // The testcases. + exempt: ['http://test1.example.com', 'http://example.com', + 'http://test2.example.org', 'http://sub1.test2.example.org', + 'https://sub1.test1.example.com'], + + notExempt: ['http://test2.example.com', 'http://sub1.test1.example.com', + 'http://www.example.com', 'https://test2.example.com', + 'https://example.com', 'http://test1.example.org'], + }; + + policy = ssm.activateDomainPolicy(); + info("Testing Blacklist-style Domain Policy"); + return testDomainPolicy(true, testPolicy.exceptions, + testPolicy.superExceptions, testPolicy.exempt, + testPolicy.notExempt, policy.blacklist, + policy.superBlacklist, rootWin); + }).then(function() { + policy.deactivate(); + policy = ssm.activateDomainPolicy(); + info("Testing Whitelist-style Domain Policy"); + setScriptEnabledForBrowser(false); + return testDomainPolicy(false, testPolicy.exceptions, + testPolicy.superExceptions, testPolicy.exempt, + testPolicy.notExempt, policy.whitelist, + policy.superWhitelist, rootWin); + }).then(function() { + setScriptEnabledForBrowser(true); + policy.deactivate(); + + SimpleTest.finish(); + }); + } + + ]]> + </script> +</window> diff --git a/caps/tests/mochitest/test_disallowInheritPrincipal.html b/caps/tests/mochitest/test_disallowInheritPrincipal.html new file mode 100644 index 000000000..ec59bec3c --- /dev/null +++ b/caps/tests/mochitest/test_disallowInheritPrincipal.html @@ -0,0 +1,60 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=732413 +--> +<head> + <title>Test for Bug 732413</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=732413">Mozilla Bug 732413</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 732413 + Passing DISALLOW_INHERIT_PRINCIPAL flag should be effective even if + aPrincipal is the system principal. + **/ + +const nsIScriptSecurityManager = SpecialPowers.Ci.nsIScriptSecurityManager; +var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(nsIScriptSecurityManager); +var sysPrincipal = secMan.getSystemPrincipal(); +isnot(sysPrincipal, undefined, "Should have a principal"); +isnot(sysPrincipal, null, "Should have a non-null principal"); +is(secMan.isSystemPrincipal(sysPrincipal), true, + "Should have system principal here"); + + +var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]. + getService(SpecialPowers.Ci.nsIIOService); +var inheritingURI = ioService.newURI("javascript:1+1", null, null); + +// First try a normal call to checkLoadURIWithPrincipal +try { + secMan.checkLoadURIWithPrincipal(sysPrincipal, inheritingURI, + nsIScriptSecurityManager.STANDARD); + ok(true, "checkLoadURI allowed the load"); +} catch (e) { + ok(false, "checkLoadURI failed unexpectedly: " + e); +} + +// Now call checkLoadURIWithPrincipal with DISALLOW_INHERIT_PRINCIPAL +try { + secMan.checkLoadURIWithPrincipal(sysPrincipal, inheritingURI, + nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL); + ok(false, "checkLoadURI allowed the load unexpectedly"); +} catch (e) { + ok(true, "checkLoadURI prevented load of principal-inheriting URI"); +} + +</script> +</pre> +</body> +</html> diff --git a/caps/tests/mochitest/test_extensionURL.html b/caps/tests/mochitest/test_extensionURL.html new file mode 100644 index 000000000..315c47321 --- /dev/null +++ b/caps/tests/mochitest/test_extensionURL.html @@ -0,0 +1,166 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1161831 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1161831</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1161831 **/ + SimpleTest.waitForExplicitFinish(); + + var aps = SpecialPowers.Cc["@mozilla.org/addons/policy-service;1"] + .getService(SpecialPowers.Ci.nsIAddonPolicyService).wrappedJSObject; + var oldLoadCallback = aps.setExtensionURILoadCallback(null); + var oldMapCallback = aps.setExtensionURIToAddonIdCallback(null); + var resourceHandler = SpecialPowers.Services.io.getProtocolHandler("resource") + .QueryInterface(SpecialPowers.Ci.nsISubstitutingProtocolHandler); + var extensionHandler = SpecialPowers.Services.io.getProtocolHandler("moz-extension") + .QueryInterface(SpecialPowers.Ci.nsISubstitutingProtocolHandler); + + SimpleTest.registerCleanupFunction(function() { + extensionHandler.setSubstitution('cherise', null); + extensionHandler.setSubstitution('liebchen', null); + aps.setExtensionURILoadCallback(oldLoadCallback); + aps.setExtensionURIToAddonIdCallback(oldMapCallback); + }); + + addLoadEvent(function() { + + // First, get a file:// URI to something - open to suggestions on how to do + // this more easily. + var resURI = SpecialPowers.Services.io.newURI('resource://testing-common/resource_test_file.html', null, null); + var filePath = resourceHandler.resolveURI(resURI); + ok(filePath.startsWith('file://'), 'resource:// URI resolves where we expect: ' + filePath); + var fileURI = SpecialPowers.Services.io.newURI(filePath, null, null); + + // Register a moz-extension:// URI. + extensionHandler.setSubstitution('cherise', fileURI); + + // Alias the above. + extensionHandler.setSubstitution('liebchen', SpecialPowers.Services.io.newURI('moz-extension://cherise', null, null)); + + // + // Make sure that non-file:// URIs don't work. + // + + // resource:// + try { + extensionHandler.setSubstitution('interdit', resURI); + ok(false, "Should have thrown for mapping moz-extension to resource"); + } catch (e) { + ok(true, "Threw correctly: " + e); + } + + // chrome:// + try { + var chromeURI = SpecialPowers.Services.io.newURI('chrome://global/content/mozilla.xhtml', null, null); + extensionHandler.setSubstitution('verboten', chromeURI); + ok(false, "Should have thrown for mapping moz-extension to chrome"); + } catch (e) { + ok(true, "Threw correctly: " + e); + } + + function navigateWithLocation(ifr, url) { ifr.contentWindow.location = url; } + function navigateWithSrc(ifr, url) { ifr.setAttribute('src', url); } + function navigateFromChromeWithLocation(ifr, url) { SpecialPowers.wrap(ifr).contentWindow.location = url; } + function navigateFromChromeWithWebNav(ifr, url) { + SpecialPowers.wrap(ifr).contentWindow + .QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor) + .getInterface(SpecialPowers.Ci.nsIWebNavigation) + .loadURI(url, 0, null, null, null); + } + + + function setWhitelistCallback(rgxp) { + var cb = SpecialPowers.wrapCallback(function(uri) { return rgxp.test(uri.spec); }); + aps.setExtensionURILoadCallback(cb); + } + + aps.setExtensionURIToAddonIdCallback(SpecialPowers.wrapCallback(function (uri) { return 'imaginaryaddon-' + uri.host[0]; })); + + function testLoad(url, navigate, shouldThrow) { + var ifr = document.createElement('iframe'); + var p = new Promise(function(resolve, reject) { + ifr.onload = function() { + ok(true, 'Loaded ' + url); + var prin = SpecialPowers.wrap(ifr.contentWindow).document.nodePrincipal; + function stripTrailingSlash(s) { return s.replace(/\/$/, ''); }; + is(stripTrailingSlash(prin.URI.spec), url, 'Principal uri is correct: ' + url); + function stripPath(s) { return s.replace(/(.*\/\/.+)\/.*/, '$1'); }; + is(prin.originNoSuffix, stripPath(url), 'Principal origin is correct: ' + prin.originNoSuffix); + is(prin.originAttributes.addonId, 'imaginaryaddon-' + url[url.indexOf('/') + 2], 'addonId is correct'); + if (/_blank/.test(url)) { + is(SpecialPowers.wrap(ifr.contentWindow).document.documentElement.innerHTML, + '<head></head><body></body>', 'blank document looks right'); + } else { + is(SpecialPowers.wrap(ifr.contentWindow).document.title, 'resource test file', + 'document looks right'); + } + ifr.remove(); + resolve(); + }; + document.body.appendChild(ifr); + + var threw = false; + try { + navigate(ifr, url); + } catch (e) { + ifr.remove(); + threw = true; + ok(/denied|insecure/.test(e), "exception correct: " + e); + } + is(threw, !!shouldThrow, "Correct throwing behavior for: " + url); + !threw || resolve(); + }); + + return p; + } + + function testXHR(url, shouldError) { + return new Promise(function(resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.addEventListener("load", () => { ok(!shouldError, `XHR to ${url} should succeed`); resolve(); }); + xhr.addEventListener("error", () => { ok(shouldError, `XHR to ${url} should fail`); resolve(); }); + xhr.open("GET", url, true); + xhr.send(); + }); + } + + // + // Perform some loads and make sure they work correctly. + // + testLoad.bind(null, 'moz-extension://cherise', navigateFromChromeWithLocation)() + .then(testLoad.bind(null, 'moz-extension://cherise', navigateFromChromeWithWebNav)) + .then(testLoad.bind(null, 'moz-extension://cherise', navigateWithLocation, /* shouldThrow = */ true)) + .then(testXHR.bind(null, 'moz-extension://cherise', /* shouldError = */ true)) + .then(setWhitelistCallback.bind(null, /cherise/)) + .then(testLoad.bind(null, 'moz-extension://cherise', navigateWithLocation)) + .then(testXHR.bind(null, 'moz-extension://cherise')) + .then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithLocation, /* shouldThrow = */ true)) + .then(testXHR.bind(null, 'moz-extension://liebchen', /* shouldError = */ true)) + .then(setWhitelistCallback.bind(null, /cherise|liebchen/)) + .then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithLocation)) + .then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithSrc)) + .then(testLoad.bind(null, 'moz-extension://cherise', navigateWithSrc)) + .then(testLoad.bind(null, 'moz-extension://cherise/_blank.html', navigateWithSrc)) + .then(SimpleTest.finish.bind(SimpleTest), + function(e) { ok(false, "rejected promise: " + e); SimpleTest.finish() } + ); + }); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1161831">Mozilla Bug 1161831</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/caps/tests/unit/test_origin.js b/caps/tests/unit/test_origin.js new file mode 100644 index 000000000..0fa125b61 --- /dev/null +++ b/caps/tests/unit/test_origin.js @@ -0,0 +1,307 @@ +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); +var ssm = Services.scriptSecurityManager; +function makeURI(uri) { return Services.io.newURI(uri, null, null); } + +function checkThrows(f) { + var threw = false; + try { f(); } catch (e) { threw = true } + do_check_true(threw); +} + +function checkCrossOrigin(a, b) { + do_check_false(a.equals(b)); + do_check_false(a.equalsConsideringDomain(b)); + do_check_false(a.subsumes(b)); + do_check_false(a.subsumesConsideringDomain(b)); + do_check_false(b.subsumes(a)); + do_check_false(b.subsumesConsideringDomain(a)); +} + +function checkOriginAttributes(prin, attrs, suffix) { + attrs = attrs || {}; + do_check_eq(prin.originAttributes.appId, attrs.appId || 0); + do_check_eq(prin.originAttributes.inIsolatedMozBrowser, attrs.inIsolatedMozBrowser || false); + do_check_eq(prin.originSuffix, suffix || ''); + do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), suffix || ''); + do_check_true(ChromeUtils.originAttributesMatchPattern(prin.originAttributes, attrs)); + if (!prin.isNullPrincipal && !prin.origin.startsWith('[')) { + do_check_true(ssm.createCodebasePrincipalFromOrigin(prin.origin).equals(prin)); + } else { + checkThrows(() => ssm.createCodebasePrincipalFromOrigin(prin.origin)); + } +} + +function checkSandboxOriginAttributes(arr, attrs, options) { + options = options || {}; + var sandbox = Cu.Sandbox(arr, options); + checkOriginAttributes(Cu.getObjectPrincipal(sandbox), attrs, + ChromeUtils.originAttributesToSuffix(attrs)); +} + +// utility function useful for debugging +function printAttrs(name, attrs) { + do_print(name + " {\n" + + "\tappId: " + attrs.appId + ",\n" + + "\tuserContextId: " + attrs.userContextId + ",\n" + + "\tinIsolatedMozBrowser: " + attrs.inIsolatedMozBrowser + ",\n" + + "\taddonId: '" + attrs.addonId + "',\n" + + "\tprivateBrowsingId: '" + attrs.privateBrowsingId + "',\n" + + "\tfirstPartyDomain: '" + attrs.firstPartyDomain + "'\n}"); +} + + +function checkValues(attrs, values) { + values = values || {}; + //printAttrs("attrs", attrs); + //printAttrs("values", values); + do_check_eq(attrs.appId, values.appId || 0); + do_check_eq(attrs.userContextId, values.userContextId || 0); + do_check_eq(attrs.inIsolatedMozBrowser, values.inIsolatedMozBrowser || false); + do_check_eq(attrs.addonId, values.addonId || ''); + do_check_eq(attrs.privateBrowsingId, values.privateBrowsingId || ''); + do_check_eq(attrs.firstPartyDomain, values.firstPartyDomain || ''); +} + +function run_test() { + // Attributeless origins. + do_check_eq(ssm.getSystemPrincipal().origin, '[System Principal]'); + checkOriginAttributes(ssm.getSystemPrincipal()); + var exampleOrg = ssm.createCodebasePrincipal(makeURI('http://example.org'), {}); + do_check_eq(exampleOrg.origin, 'http://example.org'); + checkOriginAttributes(exampleOrg); + var exampleCom = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {}); + do_check_eq(exampleCom.origin, 'https://www.example.com:123'); + checkOriginAttributes(exampleCom); + var nullPrin = Cu.getObjectPrincipal(new Cu.Sandbox(null)); + do_check_true(/^moz-nullprincipal:\{([0-9]|[a-z]|\-){36}\}$/.test(nullPrin.origin)); + checkOriginAttributes(nullPrin); + var ipv6Prin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]:123'), {}); + do_check_eq(ipv6Prin.origin, 'https://[2001:db8::ff00:42:8329]:123'); + checkOriginAttributes(ipv6Prin); + var ipv6NPPrin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]'), {}); + do_check_eq(ipv6NPPrin.origin, 'https://[2001:db8::ff00:42:8329]'); + checkOriginAttributes(ipv6NPPrin); + var ep = Cu.getObjectPrincipal(Cu.Sandbox([exampleCom, nullPrin, exampleOrg])); + checkOriginAttributes(ep); + checkCrossOrigin(exampleCom, exampleOrg); + checkCrossOrigin(exampleOrg, nullPrin); + + // nsEP origins should be in lexical order. + do_check_eq(ep.origin, `[Expanded Principal [${exampleOrg.origin}, ${exampleCom.origin}, ${nullPrin.origin}]]`); + + // Make sure createCodebasePrincipal does what the rest of gecko does. + do_check_true(exampleOrg.equals(Cu.getObjectPrincipal(new Cu.Sandbox('http://example.org')))); + + // + // Test origin attributes. + // + + // Just app. + var exampleOrg_app = ssm.createCodebasePrincipal(makeURI('http://example.org'), {appId: 42}); + var nullPrin_app = ssm.createNullPrincipal({appId: 42}); + checkOriginAttributes(exampleOrg_app, {appId: 42}, '^appId=42'); + checkOriginAttributes(nullPrin_app, {appId: 42}, '^appId=42'); + do_check_eq(exampleOrg_app.origin, 'http://example.org^appId=42'); + + // Just browser. + var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true}); + var nullPrin_browser = ssm.createNullPrincipal({inIsolatedMozBrowser: true}); + checkOriginAttributes(exampleOrg_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1'); + checkOriginAttributes(nullPrin_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1'); + do_check_eq(exampleOrg_browser.origin, 'http://example.org^inBrowser=1'); + + // App and browser. + var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true, appId: 42}); + var nullPrin_appBrowser = ssm.createNullPrincipal({inIsolatedMozBrowser: true, appId: 42}); + checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1'); + checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1'); + do_check_eq(exampleOrg_appBrowser.origin, 'http://example.org^appId=42&inBrowser=1'); + + // App and browser, different domain. + var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inIsolatedMozBrowser: true}); + checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1'); + do_check_eq(exampleCom_appBrowser.origin, 'https://www.example.com:123^appId=42&inBrowser=1'); + + // Addon. + var exampleOrg_addon = ssm.createCodebasePrincipal(makeURI('http://example.org'), {addonId: 'dummy'}); + checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '^addonId=dummy'); + do_check_eq(exampleOrg_addon.origin, 'http://example.org^addonId=dummy'); + + // First party Uri + var exampleOrg_firstPartyDomain = ssm.createCodebasePrincipal(makeURI('http://example.org'), {firstPartyDomain: 'example.org'}); + checkOriginAttributes(exampleOrg_firstPartyDomain, { firstPartyDomain: "example.org" }, '^firstPartyDomain=example.org'); + do_check_eq(exampleOrg_firstPartyDomain.origin, 'http://example.org^firstPartyDomain=example.org'); + + // Make sure we don't crash when serializing principals with UNKNOWN_APP_ID. + try { + let binaryStream = Cc["@mozilla.org/binaryoutputstream;1"]. + createInstance(Ci.nsIObjectOutputStream); + let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe); + pipe.init(false, false, 0, 0xffffffff, null); + binaryStream.setOutputStream(pipe.outputStream); + binaryStream.writeCompoundObject(simplePrin, Ci.nsISupports, true); + binaryStream.close(); + } catch (e) { + do_check_true(true); + } + + + // Just userContext. + var exampleOrg_userContext = ssm.createCodebasePrincipal(makeURI('http://example.org'), {userContextId: 42}); + checkOriginAttributes(exampleOrg_userContext, { userContextId: 42 }, '^userContextId=42'); + do_check_eq(exampleOrg_userContext.origin, 'http://example.org^userContextId=42'); + + // UserContext and Addon. + var exampleOrg_userContextAddon = ssm.createCodebasePrincipal(makeURI('http://example.org'), {addonId: 'dummy', userContextId: 42}); + var nullPrin_userContextAddon = ssm.createNullPrincipal({addonId: 'dummy', userContextId: 42}); + checkOriginAttributes(exampleOrg_userContextAddon, {addonId: 'dummy', userContextId: 42}, '^addonId=dummy&userContextId=42'); + checkOriginAttributes(nullPrin_userContextAddon, {addonId: 'dummy', userContextId: 42}, '^addonId=dummy&userContextId=42'); + do_check_eq(exampleOrg_userContextAddon.origin, 'http://example.org^addonId=dummy&userContextId=42'); + + // UserContext and App. + var exampleOrg_userContextApp = ssm.createCodebasePrincipal(makeURI('http://example.org'), {appId: 24, userContextId: 42}); + var nullPrin_userContextApp = ssm.createNullPrincipal({appId: 24, userContextId: 42}); + checkOriginAttributes(exampleOrg_userContextApp, {appId: 24, userContextId: 42}, '^appId=24&userContextId=42'); + checkOriginAttributes(nullPrin_userContextApp, {appId: 24, userContextId: 42}, '^appId=24&userContextId=42'); + do_check_eq(exampleOrg_userContextApp.origin, 'http://example.org^appId=24&userContextId=42'); + + checkSandboxOriginAttributes(null, {}); + checkSandboxOriginAttributes('http://example.org', {}); + checkSandboxOriginAttributes('http://example.org', {}, {originAttributes: {}}); + checkSandboxOriginAttributes('http://example.org', {appId: 42}, {originAttributes: {appId: 42}}); + checkSandboxOriginAttributes(['http://example.org'], {}); + checkSandboxOriginAttributes(['http://example.org'], {}, {originAttributes: {}}); + checkSandboxOriginAttributes(['http://example.org'], {appId: 42}, {originAttributes: {appId: 42}}); + + // Check that all of the above are cross-origin. + checkCrossOrigin(exampleOrg_app, exampleOrg); + checkCrossOrigin(exampleOrg_app, nullPrin_app); + checkCrossOrigin(exampleOrg_browser, exampleOrg_app); + checkCrossOrigin(exampleOrg_browser, nullPrin_browser); + checkCrossOrigin(exampleOrg_appBrowser, exampleOrg_app); + checkCrossOrigin(exampleOrg_appBrowser, nullPrin_appBrowser); + checkCrossOrigin(exampleOrg_appBrowser, exampleCom_appBrowser); + checkCrossOrigin(exampleOrg_addon, exampleOrg); + checkCrossOrigin(exampleOrg_firstPartyDomain, exampleOrg); + checkCrossOrigin(exampleOrg_userContext, exampleOrg); + checkCrossOrigin(exampleOrg_userContextAddon, exampleOrg); + checkCrossOrigin(exampleOrg_userContext, exampleOrg_userContextAddon); + checkCrossOrigin(exampleOrg_userContext, exampleOrg_userContextApp); + + // Check Principal kinds. + function checkKind(prin, kind) { + do_check_eq(prin.isNullPrincipal, kind == 'nullPrincipal'); + do_check_eq(prin.isCodebasePrincipal, kind == 'codebasePrincipal'); + do_check_eq(prin.isExpandedPrincipal, kind == 'expandedPrincipal'); + do_check_eq(prin.isSystemPrincipal, kind == 'systemPrincipal'); + } + checkKind(ssm.createNullPrincipal({}), 'nullPrincipal'); + checkKind(ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {}), 'codebasePrincipal'); + checkKind(Cu.getObjectPrincipal(Cu.Sandbox([ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {})])), 'expandedPrincipal'); + checkKind(ssm.getSystemPrincipal(), 'systemPrincipal'); + + // + // Test Origin Attribute Manipulation + // + + // check that we can create an empty origin attributes dict with default + // members and values. + var emptyAttrs = ChromeUtils.fillNonDefaultOriginAttributes({}); + checkValues(emptyAttrs); + + var uri = "http://example.org"; + var tests = [ + [ "", {} ], + [ "^appId=5", {appId: 5} ], + [ "^userContextId=3", {userContextId: 3} ], + [ "^addonId=fooBar", {addonId: "fooBar"} ], + [ "^inBrowser=1", {inIsolatedMozBrowser: true} ], + [ "^firstPartyDomain=example.org", {firstPartyDomain: "example.org"} ], + [ "^appId=3&inBrowser=1&userContextId=6", + {appId: 3, userContextId: 6, inIsolatedMozBrowser: true} ] ]; + + // check that we can create an origin attributes from an origin properly + tests.forEach(t => { + let attrs = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]); + checkValues(attrs, t[1]); + do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]); + }); + + // check that we can create an origin attributes from a dict properly + tests.forEach(t => { + let attrs = ChromeUtils.fillNonDefaultOriginAttributes(t[1]); + checkValues(attrs, t[1]); + do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]); + }); + + // each row in the set_tests array has these values: + // [0] - the suffix used to create an origin attribute from + // [1] - the expected result of creating an origin attribute from [0] + // [2] - the pattern to set on the origin attributes + // [3] - the expected result of setting [2] values on [1] + // [4] - the expected result of creating a suffix from [3] + var set_tests = [ + [ "", {}, {appId: 5}, {appId: 5}, "^appId=5" ], + [ "^appId=5", {appId: 5}, {appId: 3}, {appId: 3}, "^appId=3" ], + [ "^appId=5", {appId: 5}, {userContextId: 3}, {appId: 5, userContextId: 3}, "^appId=5&userContextId=3" ], + [ "^appId=5", {appId: 5}, {appId: 3, userContextId: 7}, {appId: 3, userContextId: 7}, "^appId=3&userContextId=7" ] ]; + + // check that we can set origin attributes values properly + set_tests.forEach(t => { + let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]); + checkValues(orig, t[1]); + let mod = orig; + for (var key in t[2]) { + mod[key] = t[2][key]; + } + checkValues(mod, t[3]); + do_check_eq(ChromeUtils.originAttributesToSuffix(mod), t[4]); + }); + + // each row in the dflt_tests array has these values: + // [0] - the suffix used to create an origin attribute from + // [1] - the expected result of creating an origin attributes from [0] + // [2] - the expected result after setting userContextId to the default + // [3] - the expected result of creating a suffix from [2] + var dflt_tests = [ + [ "", {}, {}, "" ], + [ "^userContextId=3", {userContextId: 3}, {}, "" ], + [ "^appId=5", {appId: 5}, {appId: 5}, "^appId=5" ], + [ "^appId=5&userContextId=3", {appId: 5, userContextId: 3}, {appId: 5}, "^appId=5" ] ]; + + // check that we can set the userContextId to default properly + dflt_tests.forEach(t => { + let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]); + checkValues(orig, t[1]); + let mod = orig; + mod['userContextId'] = 0; + checkValues(mod, t[2]); + do_check_eq(ChromeUtils.originAttributesToSuffix(mod), t[3]); + }); + + // each row in the dflt2_tests array has these values: + // [0] - the suffix used to create an origin attribute from + // [1] - the expected result of creating an origin attributes from [0] + // [2] - the expected result after setting firstPartyUri to the default + // [3] - the expected result of creating a suffix from [2] + var dflt2_tests = [ + [ "", {}, {}, "" ], + [ "^firstPartyDomain=foo.com", {firstPartyDomain: "foo.com"}, {}, "" ], + [ "^appId=5", {appId: 5}, {appId: 5}, "^appId=5" ], + [ "^appId=5&firstPartyDomain=foo.com", {appId: 5, firstPartyDomain: "foo.com"}, {appId: 5}, "^appId=5" ] ]; + + // check that we can set the userContextId to default properly + dflt2_tests.forEach(t => { + let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]); + checkValues(orig, t[1]); + let mod = orig; + mod['firstPartyDomain'] = ""; + checkValues(mod, t[2]); + do_check_eq(ChromeUtils.originAttributesToSuffix(mod), t[3]); + }); + +} diff --git a/caps/tests/unit/xpcshell.ini b/caps/tests/unit/xpcshell.ini new file mode 100644 index 000000000..c06a6b4e9 --- /dev/null +++ b/caps/tests/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = +tail = + +[test_origin.js] |