diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /testing/web-platform/tests/secure-contexts | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
20 files changed, 1066 insertions, 0 deletions
diff --git a/testing/web-platform/tests/secure-contexts/META.yml b/testing/web-platform/tests/secure-contexts/META.yml new file mode 100644 index 0000000000..e653716628 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/META.yml @@ -0,0 +1,3 @@ +spec: https://w3c.github.io/webappsec-secure-contexts/ +suggested_reviewers: + - mikewest diff --git a/testing/web-platform/tests/secure-contexts/basic-dedicated-worker.html b/testing/web-platform/tests/secure-contexts/basic-dedicated-worker.html new file mode 100644 index 0000000000..043b5b8dd6 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/basic-dedicated-worker.html @@ -0,0 +1,104 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test WorkerGlobalScope.isSecureContext for HTTP creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + </head> + <body> + <script> + var t1 = async_test("HTTP worker"); + var t2 = async_test("HTTPS worker"); + var t3 = async_test("HTTP nested worker"); + var t4 = async_test("HTTPS nested worker"); + var t5 = async_test("HTTP worker from HTTPS subframe"); + var t6 = async_test("HTTPS worker from HTTPS subframe"); + var t7 = async_test("Worker from data URL"); + + var w1 = new Worker(http_dir + "support/dedicated-worker-script.js"); + w1.onmessage = t1.step_func_done(function(e) { + assert_false(e.data); + }); + w1.onerror = t1.step_func_done(function(e) { + assert_unreached("isSecureContext should be supported"); + }); + + try { + var w2 = new Worker(https_dir + "support/dedicated-worker-script.js"); + w2.onmessage = t2.step_func_done(function(e) { + assert_unreached("cross-origin workers should not be loaded"); + }); + w2.onerror = t2.step_func_done(function(e) { + e.preventDefault(); + }); + } catch (e) { + // Some browsers throw for cross-origin URLs. This violates the Worker spec, + // but isn't actually relevant to what we're testing here. + t2.done(); + } + + var w3 = new Worker(http_dir + "support/parent-dedicated-worker-script.js"); + w3.onmessage = t3.step_func_done(function(e) { + assert_false(e.data); + }); + w3.onerror = t3.step_func_done(function(e) { + assert_unreached("isSecureContext should be supported"); + }); + + try { + var w4 = new Worker(https_dir + "support/parent-dedicated-worker-script.js"); + w4.onmessage = t4.step_func_done(function(e) { + assert_unreached("cross-origin workers should not be loaded"); + }); + w4.onerror = t4.step_func_done(function(e) { + e.preventDefault(); + }); + } catch (e) { + // Some browsers throw for cross-origin URLs. This violates the Worker spec, + // but isn't actually relevant to what we're testing here. + t4.done(); + } + + onmessage = function(e) { + var data = e.data; + if (data.type == "http") { + t5.step(function() { + assert_true(data.error); + }); + t5.done(); + } else if (data.type == "https") { + t6.step(function() { + assert_false(data.error, "error"); + assert_false(data.isSecureContext, "isSecureContext"); + }); + t6.done(); + } else { + t5.step(function() { + assert_unreached("Unknown message"); + }); + t5.done(); + t6.step(function() { + assert_unreached("Unknown message"); + }); + t6.done(); + } + } + + var ifr = document.createElement("iframe"); + ifr.src = https_dir + "support/https-subframe-dedicated.html"; + document.body.appendChild(ifr); + + var w7 = new Worker("data:text/javascript,postMessage(isSecureContext);"); + w7.onmessage = t7.step_func_done(function(e) { + assert_false(e.data); + }); + w7.onerror = t7.step_func_done(function(e) { + assert_unreached("isSecureContext should be supported"); + }); + </script> + </body> +</html> + diff --git a/testing/web-platform/tests/secure-contexts/basic-dedicated-worker.https.html b/testing/web-platform/tests/secure-contexts/basic-dedicated-worker.https.html new file mode 100644 index 0000000000..17c9345146 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/basic-dedicated-worker.https.html @@ -0,0 +1,104 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test WorkerGlobalScope.isSecureContext for HTTPS creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + </head> + <body> + <script> + var t1 = async_test("HTTP worker"); + var t2 = async_test("HTTPS worker"); + var t3 = async_test("HTTP nested worker"); + var t4 = async_test("HTTPS nested worker"); + var t5 = async_test("HTTP worker from HTTPS subframe"); + var t6 = async_test("HTTPS worker from HTTPS subframe"); + var t7 = async_test("Worker from data URL"); + + try { + var w1 = new Worker(http_dir + "support/dedicated-worker-script.js"); + w1.onmessage = t1.step_func_done(function(e) { + assert_unreached("cross-origin workers should not be loaded"); + }); + w1.onerror = t1.step_func_done(function(e) { + e.preventDefault(); + }); + } catch (e) { + // Some browsers throw for cross-origin URLs. This violates the Worker spec, + // but isn't actually relevant to what we're testing here. + t1.done(); + } + + var w2 = new Worker(https_dir + "support/dedicated-worker-script.js"); + w2.onmessage = t2.step_func_done(function(e) { + assert_true(e.data); + }); + w2.onerror = t2.step_func_done(function(e) { + assert_unreached("isSecureContext should be supported"); + }); + + try { + var w3 = new Worker(http_dir + "support/parent-dedicated-worker-script.js"); + w3.onmessage = t3.step_func_done(function(e) { + assert_unreached("cross-origin workers should not be loaded"); + }); + w3.onerror = t3.step_func_done(function(e) { + e.preventDefault(); + }); + } catch (e) { + // Some browsers throw for cross-origin URLs. This violates the Worker spec, + // but isn't actually relevant to what we're testing here. + t3.done(); + } + + var w4 = new Worker(https_dir + "support/parent-dedicated-worker-script.js"); + w4.onmessage = t4.step_func_done(function(e) { + assert_true(e.data); + }); + w4.onerror = t4.step_func_done(function(e) { + assert_unreached("isSecureContext should be supported"); + }); + + onmessage = function(e) { + var data = e.data; + if (data.type == "http") { + t5.step(function() { + assert_true(data.error); + }); + t5.done(); + } else if (data.type == "https") { + t6.step(function() { + assert_false(data.error); + assert_true(data.isSecureContext); + }); + t6.done(); + } else { + t5.step(function() { + assert_unreached("Unknown message"); + }); + t5.done(); + t6.step(function() { + assert_unreached("Unknown message"); + }); + t6.done(); + } + } + + var ifr = document.createElement("iframe"); + ifr.src = https_dir + "support/https-subframe-dedicated.html"; + document.body.appendChild(ifr); + + var w7 = new Worker("data:text/javascript,postMessage(isSecureContext);"); + w7.onmessage = t7.step_func_done(function(e) { + assert_true(e.data); + }); + w7.onerror = t7.step_func_done(function(e) { + assert_unreached("isSecureContext should be supported"); + }); + </script> + </body> +</html> + diff --git a/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.html b/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.html new file mode 100644 index 0000000000..ab3c443678 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.html @@ -0,0 +1,25 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test Window.isSecureContext for HTTP creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <meta name="author" title="Jonathan Watt" href="https://jwatt.org/"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + <script> + +// This file is the equivasent of the https version, but rather than +// having a copy of its script file we figure out the URI of the script on the +// https server and load it here. +let script = document.createElement("script"); +script.setAttribute("src", https_dir + "basic-popup-and-iframe-tests.https.js"); +document.head.appendChild(script); + + </script> + </head> + <body onload="begin();"> + </body> +</html> + diff --git a/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.https.html b/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.https.html new file mode 100644 index 0000000000..a9c7f3c883 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.https.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test Window.isSecureContext for HTTPS creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <meta name="author" title="Jonathan Watt" href="https://jwatt.org/"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + <script src="basic-popup-and-iframe-tests.https.js"></script> + </head> + <body onload="begin();"> + </body> +</html> + diff --git a/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.https.js b/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.https.js new file mode 100644 index 0000000000..661595c4d9 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/basic-popup-and-iframe-tests.https.js @@ -0,0 +1,299 @@ + +/** + * This test checks the Secure Context state of documents for various + * permutations of document URI types and loading methods. + * + * The hierarchy that is tested is: + * + * creator-doc > createe-doc + * + * The creator-doc is one of: + * + * http: + * https: + * + * The createe-doc is loaded as either a: + * + * popup + * iframe + * sandboxed-iframe + * + * into which we load and test: + * + * http: + * https: + * blob: + * javascript: + * about:blank + * initial about:blank + * srcdoc + * + * TODO once web-platform-tests supports it: + * - test http://localhost + * - test file: + */ + + +setup({explicit_done:true}); + + +const host_and_dirname = location.host + + location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1); + + +// Flags to indicate where document types should be loaded for testing: +const eLoadInPopup = (1 << 0); +const eLoadInUnsandboxedIframe = (1 << 1); +const eLoadInSandboxedIframe = (1 << 2); +const eLoadInEverything = eLoadInPopup | eLoadInUnsandboxedIframe | eLoadInSandboxedIframe; + +// Flags indicating if a document type is expected to be a Secure Context: +const eSecureNo = 1; +const eSecureIfNewWindow = 2; +const eSecureIfCreatorSecure = 3; + +// Flags indicating how the result of a test is obtained: +const eResultFromPostMessage = 1; +const eResultFromExaminationOnLoad = 2; +const eResultFromExaminationSync = 3; + + +const loadTypes = [ + new LoadType("an http: URI", + eLoadInEverything, + http_dir + "postMessage-helper.html", + eSecureNo, + eResultFromPostMessage), + new LoadType("an https: URI", + eLoadInEverything, + https_dir + "postMessage-helper.https.html", + eSecureIfNewWindow, + eResultFromPostMessage), + new LoadType("a blob: URI", + eLoadInEverything, + URL.createObjectURL(new Blob(["<script>(opener||parent).postMessage(isSecureContext, '*')</script>"], {type: "text/html"})), + eSecureIfCreatorSecure, + eResultFromPostMessage), + new LoadType("a srcdoc", + // popup not relevant: + eLoadInUnsandboxedIframe | eLoadInSandboxedIframe, + "<script>(opener||parent).postMessage(isSecureContext, '*')</script>", + eSecureIfNewWindow, + eResultFromPostMessage), + new LoadType("a javascript: URI", + // can't load in sandbox: + eLoadInUnsandboxedIframe | eLoadInPopup, + "javascript:(opener||parent).postMessage(isSecureContext, '*')", + eSecureIfCreatorSecure, + eResultFromPostMessage), + new LoadType("about:blank", + // can't obtain state if sandboxed: + eLoadInUnsandboxedIframe | eLoadInPopup, + "about:blank", + eSecureIfCreatorSecure, + eResultFromExaminationOnLoad), + new LoadType("initial about:blank", + // can't obtain state if sandboxed: + eLoadInUnsandboxedIframe | eLoadInPopup, + "about:blank", // we don't wait for this to load, so whatever + eSecureIfCreatorSecure, + eResultFromExaminationSync), + new LoadType("a data: URL", + // can't load in a top-level browsing context + eLoadInUnsandboxedIframe | eLoadInSandboxedIframe, + "data:text/html,<script>parent.postMessage(isSecureContext, '*')</script>", + eSecureIfCreatorSecure, + eResultFromPostMessage), +]; + +const loadTargets = [ + new LoadTarget("an iframe", eLoadInUnsandboxedIframe), + new LoadTarget("a sandboxed iframe", eLoadInSandboxedIframe), + new LoadTarget("a popup", eLoadInPopup), +]; + + +function LoadType(description, loadInFlags, uri, expectedSecureFlag, resultFrom) { + this.desc = description; + this.loadInFlags = loadInFlags; + this.uri = uri; + this.expectedSecureFlag = expectedSecureFlag; + this.resultFrom = resultFrom; +} + + +function LoadTarget(description, loadInFlag) { + this.desc = description; + this.loadInFlag = loadInFlag; +} + +LoadTarget.prototype.open = function(loadType) { + let loadTarget = this; + this.currentTest.step(function() { + assert_true((loadTarget.loadInFlag & loadType.loadInFlags) != 0, + loadType.desc + " cannot be tested in " + loadTarget.desc); + }); + if (this.loadInFlag == eLoadInUnsandboxedIframe) { + let iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + iframe[loadType.desc == "a srcdoc" ? "srcdoc" : "src"] = loadType.uri; + return iframe; + } + if (this.loadInFlag == eLoadInSandboxedIframe) { + let iframe = document.body.appendChild(document.createElement("iframe")); + iframe.setAttribute("sandbox", "allow-scripts"); + iframe[loadType.desc == "a srcdoc" ? "srcdoc" : "src"] = loadType.uri; + return iframe; + } + if (this.loadInFlag == eLoadInPopup) { + return window.open(loadType.uri); + } + this.currentTest.step(function() { + assert_unreached("Unknown load type flag: " + loadInFlags); + }); + return null; +} + +LoadTarget.prototype.close = function(domTarget) { + if (this.loadInFlag == eLoadInUnsandboxedIframe || + this.loadInFlag == eLoadInSandboxedIframe) { + domTarget.remove(); + return; + } + if (this.loadInFlag == eLoadInPopup) { + domTarget.close(); + return; + } + this.currentTest.step(function() { + assert_unreached("Unknown load type flag: " + loadInFlags); + }); +} + +LoadTarget.prototype.load_and_get_result_for = function(loadType) { + if (!(loadType.loadInFlags & this.loadInFlag)) { + return Promise.reject("not applicable"); + } + if (!(this.loadInFlag & eLoadInPopup) && + location.protocol == "https:" && + loadType.uri.substr(0,5) == "http:") { + // Mixed content blocker will prevent this load + return Promise.reject("not applicable"); + } + this.currentTest = async_test("Test Window.isSecureContext in " + this.desc + + " loading " + loadType.desc) + if (loadType.resultFrom == eResultFromExaminationSync) { + let domTarget = this.open(loadType); + let isFrame = domTarget instanceof HTMLIFrameElement; + let result = !isFrame ? + domTarget.isSecureContext : domTarget.contentWindow.isSecureContext; + this.close(domTarget); + return Promise.resolve({ result: result, isFrame: isFrame}); + } + let target = this; + if (loadType.resultFrom == eResultFromExaminationOnLoad) { + return new Promise(function(resolve, reject) { + function handleLoad(event) { + clearTimeout(timer); + let isFrame = domTarget instanceof HTMLIFrameElement; + let result = !isFrame ? + domTarget.isSecureContext : domTarget.contentWindow.isSecureContext; + domTarget.removeEventListener("load", handleLoad); + target.close(domTarget); + resolve({ result: result, isFrame: isFrame}); + } + let domTarget = target.open(loadType); + domTarget.addEventListener("load", handleLoad, false); + + // Some browsers don't fire `load` events for `about:blank`. That's weird, but it also + // isn't what we're testing here. + let timer = setTimeout(handleLoad, 500); + }); + } + if (loadType.resultFrom == eResultFromPostMessage) { + return new Promise(function(resolve, reject) { + function handleMessage(event) { + let isFrame = domTarget instanceof HTMLIFrameElement; + window.removeEventListener("message", handleMessage); + target.close(domTarget); + resolve({ result: event.data, isFrame: isFrame}); + } + window.addEventListener("message", handleMessage, false); + let domTarget = target.open(loadType); + }); + } + return Promise.reject("unexpected 'result from' type"); +} + + +let current_type_index = -1; +let current_target_index = 0; + +function run_next_test() { + current_type_index++; + if (current_type_index >= loadTypes.length) { + current_type_index = 0; + current_target_index++; + if (current_target_index >= loadTargets.length) { + done(); + return; // all test permutations complete + } + } + let loadTarget = loadTargets[current_target_index]; + let loadType = loadTypes[current_type_index]; + loadTarget.load_and_get_result_for(loadType).then( + function(value) { + run_next_test_soon(); + loadTarget.currentTest.step(function() { + // If the new context is always non-secure, the assertion is straightforward. + if (loadType.expectedSecureFlag == eSecureNo) { + assert_false(value.result, loadType.desc + " in " + loadTarget.desc + " should not create a Secure Context"); + // If the new context is always secure if opened in a new window, and it's + // been opened in a new window, the assertion is likewise straightforward. + } else if (loadType.expectedSecureFlag == eSecureIfNewWindow && !value.isFrame) { + assert_true(value.result, loadType.desc + " in " + loadTarget.desc + " should create a secure context regardless of its creator's state."); + // Otherwise, we're either dealing with a context that's secure if and only + // if its creator context (e.g. this window) is secure. + } else if ((loadType.expectedSecureFlag == eSecureIfNewWindow && value.isFrame) || + (loadType.expectedSecureFlag == eSecureIfCreatorSecure)) { + if (!window.isSecureContext) { + assert_false(value.result, loadType.desc + " in " + loadTarget.desc + " should not create a Secure Context when its creator is not a Secure Context."); + } else { + assert_true(value.result, loadType.desc + " in " + loadTarget.desc + " should create a Secure Context when its creator is a Secure Context"); + } + } else { + assert_unreached(loadType.desc + " - unknown expected secure flag: " + expectedSecureFlag); + } + loadTarget.currentTest.done(); + }); + }, + function(failReason) { + run_next_test_soon(); + if (failReason == "not applicable") { + return; + } + loadTarget.currentTest.step(function() { + assert_unreached(loadType.desc + " - got unexpected rejected promise"); + }); + } + ); +} + +function run_next_test_soon() { + setTimeout(run_next_test, 0); +} + +function begin() { + test(function() { + if (location.protocol == "http:") { + assert_false(isSecureContext, + "http: creator should not be a Secure Context"); + } else if (location.protocol == "https:") { + assert_true(isSecureContext, + "https: creator should be a Secure Context"); + } else { + assert_unreached("Unknown location.protocol"); + } + }); + run_next_test(); +} + diff --git a/testing/web-platform/tests/secure-contexts/basic-shared-worker.html b/testing/web-platform/tests/secure-contexts/basic-shared-worker.html new file mode 100644 index 0000000000..7f421b0523 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/basic-shared-worker.html @@ -0,0 +1,84 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test SharedWorkerGlobalScope.isSecureContext for HTTP creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + </head> + <body> + <script> + var t1 = async_test("Shared worker"); + var t2 = async_test("Nested worker in shared worker"); + var t3 = async_test("Shared worker from https subframe"); + var t4 = async_test("Nested worker from shared worker from https subframe"); + var t5 = async_test("Shared worker from data URL"); + // Tests for SharedWorkers used from other workers (not supported right + // now) would go here. + + t1.step(function() { + var w = new SharedWorker("support/shared-worker-script.js"); + w.port.onmessage = t1.step_func_done(function(e) { + assert_false(e.data); + }); + w.port.start(); + }); + + t2.step(function() { + var w = new SharedWorker("support/parent-shared-worker-script.js"); + w.port.onmessage = t2.step_func_done(function(e) { + assert_false(e.data); + }); + w.port.start(); + }); + + onmessage = function(e) { + var data = e.data; + if (data.type == "shared") { + t3.step(function() { + assert_false(data.exception); + assert_false(data.error); + assert_false(data.isSecureContext); + }); + t3.done(); + } else if (data.type == "nested") { + t4.step(function() { + assert_false(data.exception); + assert_false(data.error); + assert_false(data.isSecureContext); + }); + t4.done(); + } else { + t3.step(function() { + assert_unreached("Unknown message"); + }); + t3.done(); + t4.step(function() { + assert_unreached("Unknown message"); + }); + t4.done(); + } + } + + var ifr = document.createElement("iframe"); + ifr.src = https_dir2 + "support/https-subframe-shared.html"; + document.body.appendChild(ifr); + + t5.step(function() { + var w = new SharedWorker( + `data:text/javascript,addEventListener("connect", function (e) { + var port = e.ports[0]; + port.start(); + port.postMessage(isSecureContext); + });` + ); + w.port.onmessage = t5.step_func_done(function(e) { + assert_false(e.data); + }); + w.port.start(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/secure-contexts/basic-shared-worker.https.html b/testing/web-platform/tests/secure-contexts/basic-shared-worker.https.html new file mode 100644 index 0000000000..7c43cd965f --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/basic-shared-worker.https.html @@ -0,0 +1,82 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test SharedWorkerGlobalScope.isSecureContext for HTTP creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + </head> + <body> + <script> + var t1 = async_test("Shared worker"); + var t2 = async_test("Nested worker in shared worker"); + var t3 = async_test("Shared worker from https subframe"); + var t4 = async_test("Nested worker from shared worker from https subframe"); + var t5 = async_test("Shared worker from data URL"); + + t1.step(function() { + var w = new SharedWorker("support/shared-worker-script.js"); + w.port.onmessage = t1.step_func_done(function(e) { + assert_true(e.data); + }); + w.port.start(); + }); + + t2.step(function() { + var w = new SharedWorker("support/parent-shared-worker-script.js"); + w.port.onmessage = t2.step_func_done(function(e) { + assert_true(e.data); + }); + w.port.start(); + }); + + onmessage = function(e) { + var data = e.data; + if (data.type == "shared") { + t3.step(function() { + assert_false(data.exception); + assert_false(data.error); + assert_true(data.isSecureContext); + }); + t3.done(); + } else if (data.type == "nested") { + t4.step(function() { + assert_false(data.exception); + assert_false(data.error); + assert_true(data.isSecureContext); + }); + t4.done(); + } else { + t3.step(function() { + assert_unreached("Unknown message"); + }); + t3.done(); + t4.step(function() { + assert_unreached("Unknown message"); + }); + t4.done(); + } + } + + var ifr = document.createElement("iframe"); + ifr.src = https_dir3 + "support/https-subframe-shared.html"; + document.body.appendChild(ifr); + + t5.step(function() { + var w = new SharedWorker( + `data:text/javascript,addEventListener("connect", function (e) { + var port = e.ports[0]; + port.start(); + port.postMessage(isSecureContext); + });` + ); + w.port.onmessage = t5.step_func_done(function(e) { + assert_true(e.data); + }); + w.port.start(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/secure-contexts/postMessage-helper.html b/testing/web-platform/tests/secure-contexts/postMessage-helper.html new file mode 100644 index 0000000000..8971c86b27 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/postMessage-helper.html @@ -0,0 +1 @@ +<script>(opener||parent).postMessage(isSecureContext, '*')</script> diff --git a/testing/web-platform/tests/secure-contexts/postMessage-helper.https.html b/testing/web-platform/tests/secure-contexts/postMessage-helper.https.html new file mode 100644 index 0000000000..8971c86b27 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/postMessage-helper.https.html @@ -0,0 +1 @@ +<script>(opener||parent).postMessage(isSecureContext, '*')</script> diff --git a/testing/web-platform/tests/secure-contexts/server-locations.sub.js b/testing/web-platform/tests/secure-contexts/server-locations.sub.js new file mode 100644 index 0000000000..6b29c5328c --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/server-locations.sub.js @@ -0,0 +1,17 @@ +var https_dir = "https://{{location[hostname]}}:{{ports[https][0]}}{{location[path]}}"; +https_dir = https_dir.substr(0, https_dir.lastIndexOf("/") + 1); + +var http_dir = "http://{{location[hostname]}}:{{ports[http][0]}}{{location[path]}}"; +http_dir = http_dir.substr(0, http_dir.lastIndexOf("/") + 1); + +var https_dir2 = "https://{{domains[www]}}:{{ports[https][0]}}{{location[path]}}"; +https_dir2 = https_dir2.substr(0, https_dir2.lastIndexOf("/") + 1); + +var https_dir3 = "https://{{domains[www1]}}:{{ports[https][0]}}{{location[path]}}"; +https_dir3 = https_dir3.substr(0, https_dir3.lastIndexOf("/") + 1); + +var https_dir4 = "https://{{domains[www2]}}:{{ports[https][0]}}{{location[path]}}"; +https_dir4 = https_dir4.substr(0, https_dir4.lastIndexOf("/") + 1); + +var https_dir5 = "https://{{domains[élève]}}:{{ports[https][0]}}{{location[path]}}"; +https_dir5 = https_dir5.substr(0, https_dir5.lastIndexOf("/") + 1); diff --git a/testing/web-platform/tests/secure-contexts/shared-worker-insecure-first.https.html b/testing/web-platform/tests/secure-contexts/shared-worker-insecure-first.https.html new file mode 100644 index 0000000000..00db9517d0 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/shared-worker-insecure-first.https.html @@ -0,0 +1,111 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test SharedWorkerGlobalScope.isSecureContext for HTTP creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + </head> + <body> + <script> + /* + * The goal of this test is to check that we do the right thing if the + * same SharedWorker is used first from an insecure context and then from + * a secure context. + * + * To do this, we first open an insecure (http) popup, which loads a + * subframe that is same-origin with us but not a secure context, since + * its parent is http, not https. Then this subframe loads a SharedWorker + * and communicates back to us whether that worker and a child dedicated + * worker it spawns think they are secure contexts. Async tests t3 and t4 + * track these two workers. + * + * After we have heard from both workers in the popup, we directly load + * the same exact subframe ourselves and see what the workers in it + * report. Async tests t1 and t2 track these two workers. + */ + var t1 = async_test("Shared worker in subframe"); + var t2 = async_test("Nested worker in shared worker in subframe"); + var t3 = async_test("Shared worker in popup"); + var t4 = async_test("Nested worker from shared worker in popup"); + + var messageCount = 0; + var popup = null; + onmessage = function(e) { + ++messageCount; + // Make sure to not close the popup until we've run the iframe part of + // the test! We need to keep those shared workers alive. + if (messageCount == 4 && popup) { + popup.close(); + } + var data = e.data; + if (data.type == "shared") { + // This is a message from our shared worker; check whether it's the + // one in the popup or in our subframe. + if (data.fromPopup) { + t3.step(function() { + assert_false(data.exception, "SharedWorker should not throw an exception."); + assert_false(data.error, "SharedWorker connection should not generate an error."); + assert_false(data.isSecureContext, "SharedWorker is not a secure context"); + }); + t3.done(); + } else { + t1.step(function() { + assert_false(data.exception, "SharedWorker should not throw an exception."); + assert_true(data.error, "SharedWorker connection should generate an error."); + }); + t1.done(); + } + } else if (data.type == "nested") { + // This is a message from our shared worker's nested dedicated worker; + // check whether it's the one in the popup or in our subframe. + if (data.fromPopup) { + t4.step(function() { + assert_false(data.exception, "SharedWorker should not throw an exception."); + assert_false(data.error, "SharedWorker connection should not generate an error."); + assert_false(data.isSecureContext); + }); + t4.done(); + } else { + t2.step(function() { + assert_false(data.exception, "SharedWorker should not throw an exception."); + assert_true(data.error, "SharedWorker connection should generate an error."); + }); + t2.done(); + } + } else { + if (popup) { + popup.close(); + } + t1.step(function() { + assert_unreached("Unknown message"); + }); + t1.done(); + t2.step(function() { + assert_unreached("Unknown message"); + }); + t2.done(); + t3.step(function() { + assert_unreached("Unknown message"); + }); + t3.done(); + t4.step(function() { + assert_unreached("Unknown message"); + }); + t4.done(); + } + + if (messageCount == 2) { + // Got both messages from our popup; time to create our child. + var ifr = document.createElement("iframe"); + ifr.src = https_dir5 + "support/https-subframe-shared.html"; + document.body.appendChild(ifr); + } + } + + popup = window.open(http_dir + "support/shared-worker-insecure-popup.html?https_dir5"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/secure-contexts/shared-worker-secure-first.https.html b/testing/web-platform/tests/secure-contexts/shared-worker-secure-first.https.html new file mode 100644 index 0000000000..ce97a628a0 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/shared-worker-secure-first.https.html @@ -0,0 +1,111 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Test SharedWorkerGlobalScope.isSecureContext for HTTP creator</title> + <meta name="help" href="https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object"> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="server-locations.sub.js"></script> + </head> + <body> + <script> + /* + * The goal of this test is to check that we do the right thing if the + * same SharedWorker is used first from an secure context and then from + * an insecure context. + * + * To do this, we load a subframe which loads a SharedWorker + * and communicates back to us whether that worker and a child dedicated + * worker it spawns think they are secure contexts. Async tests t1 and t2 + * track these two workers. + * + * After we have heard from both workers in the subframe, we open an + * insecure (http) popup, which loads the same exact subframe. This + * subframe is still is same-origin with + * us but not a secure context, since its parent is http, not https. Then + * we wait to hear about the status of the workers in the popup's + * subframe. Async tests t3 and t4 track these two workers. + * + */ + var t1 = async_test("Shared worker in subframe"); + var t2 = async_test("Nested worker in shared worker in subframe"); + var t3 = async_test("Shared worker in popup"); + var t4 = async_test("Nested worker from shared worker in popup"); + + var messageCount = 0; + var popup = null; + onmessage = function(e) { + ++messageCount; + if (messageCount == 4 && popup) { + popup.close(); + } + var data = e.data; + if (data.type == "shared") { + // This is a message from our shared worker; check whether it's the + // one in the popup or in our subframe. + if (data.fromPopup) { + t3.step(function() { + assert_false(data.exception, "No exception should be present."); + assert_true(data.error, "SharedWorker connection should error out."); + }); + t3.done(); + } else { + t1.step(function() { + assert_false(data.exception, "SharedWorker should not throw an exception."); + assert_false(data.error, "SharedWorker connection should not generate an error."); + assert_true(data.isSecureContext, "SharedWorker is a secure context"); + }); + t1.done(); + } + } else if (data.type == "nested") { + // This is a message from our shared worker's nested dedicated worker; + // check whether it's the one in the popup or in our subframe. + if (data.fromPopup) { + t4.step(function() { + assert_false(data.exception, "No exception should be present."); + assert_true(data.error, "SharedWorker connection should error out."); + }); + t4.done(); + } else { + t2.step(function() { + assert_false(data.exception, "SharedWorker should not throw an exception."); + assert_false(data.error, "SharedWorker connection should not generate an error."); + assert_true(data.isSecureContext, "SharedWorker is a secure context"); + }); + t2.done(); + } + } else { + if (popup) { + popup.close(); + } + t1.step(function() { + assert_unreached("Unknown message"); + }); + t1.done(); + t2.step(function() { + assert_unreached("Unknown message"); + }); + t2.done(); + t3.step(function() { + assert_unreached("Unknown message"); + }); + t3.done(); + t4.step(function() { + assert_unreached("Unknown message"); + }); + t4.done(); + } + + if (messageCount == 2) { + // Got both messages from our child; time to open our popup + popup = window.open(http_dir + "support/shared-worker-insecure-popup.html?https_dir4"); + } + } + + var ifr = document.createElement("iframe"); + ifr.src = https_dir4 + "support/https-subframe-shared.html"; + document.body.appendChild(ifr); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/secure-contexts/support/dedicated-worker-script.js b/testing/web-platform/tests/secure-contexts/support/dedicated-worker-script.js new file mode 100644 index 0000000000..69ffdf3442 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/support/dedicated-worker-script.js @@ -0,0 +1 @@ +postMessage(isSecureContext); diff --git a/testing/web-platform/tests/secure-contexts/support/https-subframe-dedicated.html b/testing/web-platform/tests/secure-contexts/support/https-subframe-dedicated.html new file mode 100644 index 0000000000..bcf27879e8 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/support/https-subframe-dedicated.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<script src="../server-locations.sub.js"></script> +<script> + try { + var w1 = new Worker(http_dir + "support/dedicated-worker-script.js"); + w1.onmessage = function(e) { + parent.postMessage({ type: "http", error: false, + isSecureContext: e.data }, "*"); + }; + w1.onerror = function(e) { + parent.postMessage({ type: "http", error: true }, "*"); + }; + } catch (e) { + // Some browsers throw for cross-origin URLs. This violates the Worker spec, + // but isn't actually relevant to what we're testing here. + parent.postMessage({ type: "http", error: true }, "*"); + } + + try { + var w2 = new Worker(https_dir + "support/dedicated-worker-script.js"); + w2.onmessage = function(e) { + parent.postMessage({ type: "https", error: false, + isSecureContext: e.data }, "*"); + }; + w2.onerror = function(e) { + parent.postMessage({ type: "https", error: true }, "*"); + } + } catch (e) { + // Some browsers throw for cross-origin URLs. This violates the Worker spec, + // but isn't actually relevant to what we're testing here. + parent.postMessage({ type: "https", error: true }, "*"); + } +</script> diff --git a/testing/web-platform/tests/secure-contexts/support/https-subframe-shared.html b/testing/web-platform/tests/secure-contexts/support/https-subframe-shared.html new file mode 100644 index 0000000000..5ae7cde5b0 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/support/https-subframe-shared.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<script> + try { + var w = new SharedWorker("shared-worker-script.js"); + w.port.onmessage = function(e) { + parent.postMessage({ type: "shared", error: false, exception: false, + isSecureContext: e.data }, "*"); + }; + w.onerror = function(e) { + parent.postMessage({ type: "shared", error: true, exception: false }, + "*"); + } + w.port.start(); + } catch (e) { + parent.postMessage({ type: "shared", exception: true }, "*"); + } + + try { + var w = new SharedWorker("parent-shared-worker-script.js"); + w.port.onmessage = function(e) { + parent.postMessage({ type: "nested", error: false, exception: false, + isSecureContext: e.data }, "*"); + }; + w.onerror = function(e) { + parent.postMessage({ type: "nested", error: true, exception: false }, + "*"); + } + w.port.start(); + } catch (e) { + parent.postMessage({ type: "nested", exception: true }, "*"); + } +</script> diff --git a/testing/web-platform/tests/secure-contexts/support/parent-dedicated-worker-script.js b/testing/web-platform/tests/secure-contexts/support/parent-dedicated-worker-script.js new file mode 100644 index 0000000000..2b67432384 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/support/parent-dedicated-worker-script.js @@ -0,0 +1,9 @@ +// If nested workers aren't supported, punt: +if (typeof Worker != "undefined") { + var w = new Worker("dedicated-worker-script.js"); + w.onmessage = function (e) { + postMessage(e.data); + } +} else { + postMessage("Nested workers not supported."); +} diff --git a/testing/web-platform/tests/secure-contexts/support/parent-shared-worker-script.js b/testing/web-platform/tests/secure-contexts/support/parent-shared-worker-script.js new file mode 100644 index 0000000000..083564a054 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/support/parent-shared-worker-script.js @@ -0,0 +1,13 @@ +addEventListener("connect", function (e) { + var port = e.ports[0]; + port.start(); + // If nested workers aren't supported, punt: + if (typeof Worker != "undefined") { + var w = new Worker("dedicated-worker-script.js"); + w.onmessage = function (e) { + port.postMessage(e.data); + } + } else { + port.postMessage("Nested workers not supported."); + } +}); diff --git a/testing/web-platform/tests/secure-contexts/support/shared-worker-insecure-popup.html b/testing/web-platform/tests/secure-contexts/support/shared-worker-insecure-popup.html new file mode 100644 index 0000000000..740679dc4f --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/support/shared-worker-insecure-popup.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<script src="../server-locations.sub.js"></script> +<body> + <script> + var url = self[location.search.substr(1)] + "support/https-subframe-shared.html"; + onmessage = function(e) { + var data = e.data; + data.fromPopup = true; + opener.postMessage(data, "*"); + } + var ifr = document.createElement("iframe"); + ifr.src = url; + document.body.appendChild(ifr); + </script> +</body> diff --git a/testing/web-platform/tests/secure-contexts/support/shared-worker-script.js b/testing/web-platform/tests/secure-contexts/support/shared-worker-script.js new file mode 100644 index 0000000000..faed70a5c8 --- /dev/null +++ b/testing/web-platform/tests/secure-contexts/support/shared-worker-script.js @@ -0,0 +1,5 @@ +addEventListener("connect", function (e) { + var port = e.ports[0]; + port.start(); + port.postMessage(isSecureContext); +}); |