From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../content-security-policy/support/alert-pass.js | 1 + .../support/alertAssert.sub.js | 43 +++++++ .../support/checkReport.sub.js | 138 ++++++++++++++++++++ .../support/dedicated-worker-helper.js | 5 + .../support/document-write-alert-fail.js | 1 + .../content-security-policy/support/echo-policy.py | 3 + .../content-security-policy/support/fail.asis | 5 + .../content-security-policy/support/fail.html | 3 + .../tests/content-security-policy/support/fail.js | 1 + .../tests/content-security-policy/support/fail.png | Bin 0 -> 759 bytes .../support/file-prefetch-allowed.html | 9 ++ .../content-security-policy/support/fonts.css | 8 ++ .../support/import-scripts.js | 3 + .../support/inject-image.js | 4 + .../support/inject-image.sub.js | 3 + .../content-security-policy/support/logTest.sub.js | 41 ++++++ .../content-security-policy/support/manifest.json | 5 + .../support/nonce-should-be-blocked.js | 1 + .../tests/content-security-policy/support/pass.png | Bin 0 -> 1689 bytes .../content-security-policy/support/pass2.png | Bin 0 -> 1689 bytes .../tests/content-security-policy/support/ping.js | 12 ++ .../support/post-message.js | 1 + .../support/postmessage-fail.html | 4 + .../support/postmessage-pass-to-opener.html | 3 + .../support/postmessage-pass.html | 4 + .../support/prefetch-helper.js | 85 ++++++++++++ .../support/prefetch-subresource.css | 3 + .../support/prefetch-subresource.css.headers | 1 + .../support/prefetch-with-csp.html | 18 +++ .../content-security-policy/support/resource.py | 5 + .../support/service-worker-helper.js | 5 + .../support/shared-worker-helper.js | 5 + .../content-security-policy/support/siblingPath.js | 5 + .../support/testharness-helper.js | 142 +++++++++++++++++++++ .../tests/content-security-policy/support/var-a.js | 1 + 35 files changed, 568 insertions(+) create mode 100644 testing/web-platform/tests/content-security-policy/support/alert-pass.js create mode 100644 testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js create mode 100644 testing/web-platform/tests/content-security-policy/support/checkReport.sub.js create mode 100644 testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js create mode 100644 testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js create mode 100644 testing/web-platform/tests/content-security-policy/support/echo-policy.py create mode 100644 testing/web-platform/tests/content-security-policy/support/fail.asis create mode 100644 testing/web-platform/tests/content-security-policy/support/fail.html create mode 100644 testing/web-platform/tests/content-security-policy/support/fail.js create mode 100644 testing/web-platform/tests/content-security-policy/support/fail.png create mode 100644 testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html create mode 100644 testing/web-platform/tests/content-security-policy/support/fonts.css create mode 100644 testing/web-platform/tests/content-security-policy/support/import-scripts.js create mode 100644 testing/web-platform/tests/content-security-policy/support/inject-image.js create mode 100644 testing/web-platform/tests/content-security-policy/support/inject-image.sub.js create mode 100644 testing/web-platform/tests/content-security-policy/support/logTest.sub.js create mode 100644 testing/web-platform/tests/content-security-policy/support/manifest.json create mode 100644 testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js create mode 100644 testing/web-platform/tests/content-security-policy/support/pass.png create mode 100644 testing/web-platform/tests/content-security-policy/support/pass2.png create mode 100644 testing/web-platform/tests/content-security-policy/support/ping.js create mode 100644 testing/web-platform/tests/content-security-policy/support/post-message.js create mode 100644 testing/web-platform/tests/content-security-policy/support/postmessage-fail.html create mode 100644 testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html create mode 100644 testing/web-platform/tests/content-security-policy/support/postmessage-pass.html create mode 100644 testing/web-platform/tests/content-security-policy/support/prefetch-helper.js create mode 100644 testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css create mode 100644 testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers create mode 100644 testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html create mode 100644 testing/web-platform/tests/content-security-policy/support/resource.py create mode 100644 testing/web-platform/tests/content-security-policy/support/service-worker-helper.js create mode 100644 testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js create mode 100644 testing/web-platform/tests/content-security-policy/support/siblingPath.js create mode 100644 testing/web-platform/tests/content-security-policy/support/testharness-helper.js create mode 100644 testing/web-platform/tests/content-security-policy/support/var-a.js (limited to 'testing/web-platform/tests/content-security-policy/support') diff --git a/testing/web-platform/tests/content-security-policy/support/alert-pass.js b/testing/web-platform/tests/content-security-policy/support/alert-pass.js new file mode 100644 index 0000000000..d3f811ec1b --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/alert-pass.js @@ -0,0 +1 @@ +alert_assert("PASS"); \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js b/testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js new file mode 100644 index 0000000000..3877b2679d --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/alertAssert.sub.js @@ -0,0 +1,43 @@ +// note, this template substitution is XSS, but no way to avoid it in this framework +var expected_alerts = {{GET[alerts]}}; +var timeout= "{{GET[timeout]}}"; +if (timeout == "") { + timeout = 2; +} + +if(expected_alerts.length == 0) { + function alert_assert(msg) { + test(function () { assert_unreached(msg) }); + } +} else { + var t_alert = async_test('Expecting alerts: {{GET[alerts]}}'); + step_timeout(function() { + if(t_alert.phase != t_alert.phases.COMPLETE) { + t_alert.step(function() { assert_unreached('Alert timeout, expected alerts ' + expected_alerts + ' not fired.') }); + t_alert.done(); + } + }, timeout * 1000); + var alert_assert = function (msg) { + t_alert.step(function () { + if(msg && msg instanceof Error) { + msg = msg.message; + } + if (msg && msg.match(/^FAIL/i)) { + assert_unreached(msg); + t_alert.done(); + } + for (var i = 0; i < expected_alerts.length; i++) { + if (expected_alerts[i] == msg) { + assert_equals(expected_alerts[i], msg); + expected_alerts.splice(i, 1); + if (expected_alerts.length == 0) { + t_alert.done(); + } + return; + } + } + assert_unreached('unexpected alert: ' + msg); + t_log.done(); + }); + }.bind(this); +} diff --git a/testing/web-platform/tests/content-security-policy/support/checkReport.sub.js b/testing/web-platform/tests/content-security-policy/support/checkReport.sub.js new file mode 100644 index 0000000000..9cc242662b --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/checkReport.sub.js @@ -0,0 +1,138 @@ +(function () { + + // Get values from the substitution engine. + // We can't just pull these from the document context + // because this script is intended to be transcluded into + // another document, and we want the GET values used to request it, + // not the values for the including document + + // XXX these are unencoded, so there's an unavoidable + // injection vulnerability in constructing this file... + // need to upgrade the template engine. + var reportField = "{{GET[reportField]}}"; + var reportValue = "{{GET[reportValue]}}"; + var reportExists = "{{GET[reportExists]}}"; + var noCookies = "{{GET[noCookies]}}"; + var reportCookieName = "{{GET[reportCookieName]}}" + var testName = "{{GET[testName]}}" + var cookiePresent = "{{GET[cookiePresent]}}" + var reportCount = "{{GET[reportCount]}}" + + var location = window.location; + if (reportCookieName == "") { + // fallback on test file name if cookie name not specified + reportCookieName = location.pathname.split('/')[location.pathname.split('/').length - 1].split('.')[0]; + } + + var reportID = "{{GET[reportID]}}"; + + if (reportID == "") { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookieName = cookies[i].split('=')[0].trim(); + var cookieValue = cookies[i].split('=')[1].trim(); + + if (cookieName == reportCookieName) { + reportID = cookieValue; + var cookieToDelete = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=" + document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/') + 1); + document.cookie = cookieToDelete; + break; + } + } + } + + // There is no real way to test (in this particular layer) that a CSP report + // has *not* been sent, at least not without some major reworks and + // involvement from all the platform participants. So the current "solution" + // is to wait for some reasonable amount of time and if no report has been + // received to conclude that no report has been generated. These timeouts must + // not exceed the test timeouts set by vendors otherwise the test would fail. + var timeout = document.querySelector("meta[name=timeout][content=long]") ? 20 : 3; + var reportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_report&timeout=" + timeout + "&reportID=" + reportID; + + if (testName == "") testName = "Violation report status OK."; + var reportTest = async_test(testName); + + function assert_field_value(field, value, field_name) { + assert_true(field.indexOf(value.split(" ")[0]) != -1, + field_name + " value of \"" + field + "\" did not match " + + value.split(" ")[0] + "."); + } + + reportTest.step(function () { + + var report = new XMLHttpRequest(); + report.onload = reportTest.step_func(function () { + var data = JSON.parse(report.responseText); + + if (data.error) { + assert_equals("false", reportExists, data.error); + } else { + if (reportExists === "false") { + assert_equals(data.length, 0, + "CSP report sent, but not expecting one."); + } else { + // With the 'report-uri' directive, the report is contained in + // `data[0]["csp-report"]`. With the 'report-to' directive, the report + // is contained in `data[0]["body"]`. + const reportBody = data[0]["body"] + ? data[0]["body"] + : data[0]["csp-report"]; + + assert_true(reportBody !== undefined, + "No CSP report sent, but expecting one."); + // Firefox expands 'self' or origins in a policy to the actual origin value + // so "www.example.com" becomes "http://www.example.com:80". + // Accomodate this by just testing that the correct directive name + // is reported, not the details... + + if (reportBody[reportField] !== undefined) { + assert_field_value(reportBody[reportField], reportValue, reportField); + } else { + assert_equals(reportField, "", "Expected report field could not be found in report."); + } + } + } + + reportTest.done(); + }); + + report.open("GET", reportLocation, true); + report.send(); + }); + + if (noCookies || cookiePresent) { + var cookieTest = async_test("Test report cookies."); + var cookieReport = new XMLHttpRequest(); + cookieReport.onload = cookieTest.step_func(function () { + var data = JSON.parse(cookieReport.responseText); + if (noCookies) { + assert_equals(data.reportCookies, "None", "Report should not contain any cookies"); + } + + if (cookiePresent) { + assert_true(data.reportCookies.hasOwnProperty(cookiePresent), "Report should contain cookie: " + cookiePresent); + } + cookieTest.done(); + }); + var cReportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_cookies&timeout=" + timeout + "&reportID=" + reportID; + cookieReport.open("GET", cReportLocation, true); + cookieReport.send(); + } + + if (reportCount != "") { + var reportCountTest = async_test("Test number of sent reports."); + var reportCountReport = new XMLHttpRequest(); + reportCountReport.onload = reportCountTest.step_func(function () { + var data = JSON.parse(reportCountReport.responseText); + + assert_equals(data.report_count, +reportCount, "Report count was not what was expected."); + + reportCountTest.done(); + }); + var cReportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_count&timeout=" + timeout + "&reportID=" + reportID; + reportCountReport.open("GET", cReportLocation, true); + reportCountReport.send(); + } + +})(); diff --git a/testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js b/testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js new file mode 100644 index 0000000000..8441ab0de7 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/dedicated-worker-helper.js @@ -0,0 +1,5 @@ +var url = new URL("../support/ping.js", document.baseURI).toString(); +if (document.getElementById("foo").hasAttribute("blocked-worker")) + assert_worker_is_blocked(url, document.getElementById("foo").getAttribute("data-desc-fallback")); +else + assert_worker_is_loaded(url, document.getElementById("foo").getAttribute("data-desc-fallback")); \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js b/testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js new file mode 100644 index 0000000000..5e78ca0dac --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/document-write-alert-fail.js @@ -0,0 +1 @@ +document.write(""); diff --git a/testing/web-platform/tests/content-security-policy/support/echo-policy.py b/testing/web-platform/tests/content-security-policy/support/echo-policy.py new file mode 100644 index 0000000000..3a4b2f3d2e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/echo-policy.py @@ -0,0 +1,3 @@ +def main(request, response): + policy = request.GET.first(b"policy") + return [(b"Content-Type", b"text/html"), (b"Content-Security-Policy", policy)], b"Echo." diff --git a/testing/web-platform/tests/content-security-policy/support/fail.asis b/testing/web-platform/tests/content-security-policy/support/fail.asis new file mode 100644 index 0000000000..96196615bd --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/fail.asis @@ -0,0 +1,5 @@ +HTTP/1.1 200 OK +Content-Type: text/plain +Access-Control-Allow-Origin: * + +FAIL \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/fail.html b/testing/web-platform/tests/content-security-policy/support/fail.html new file mode 100644 index 0000000000..fedcc31bd3 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/fail.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/fail.js b/testing/web-platform/tests/content-security-policy/support/fail.js new file mode 100644 index 0000000000..9632567a6e --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/fail.js @@ -0,0 +1 @@ +test(function() { assert_unreached("FAIL")}); \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/fail.png b/testing/web-platform/tests/content-security-policy/support/fail.png new file mode 100644 index 0000000000..b593380333 Binary files /dev/null and b/testing/web-platform/tests/content-security-policy/support/fail.png differ diff --git a/testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html b/testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html new file mode 100644 index 0000000000..bd60d262ad --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/file-prefetch-allowed.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/support/fonts.css b/testing/web-platform/tests/content-security-policy/support/fonts.css new file mode 100644 index 0000000000..848961c8dc --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/fonts.css @@ -0,0 +1,8 @@ +@font-face { + font-family: 'Ahem'; + src: url('/fonts/Ahem.ttf'); +} + +body { + font-family: 'Ahem', Fallback, sans-serif; +} diff --git a/testing/web-platform/tests/content-security-policy/support/import-scripts.js b/testing/web-platform/tests/content-security-policy/support/import-scripts.js new file mode 100644 index 0000000000..8325ebb3fb --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/import-scripts.js @@ -0,0 +1,3 @@ +self.a = false; +importScripts('/content-security-policy/support/var-a.js'); +postMessage({ 'executed': self.a }); diff --git a/testing/web-platform/tests/content-security-policy/support/inject-image.js b/testing/web-platform/tests/content-security-policy/support/inject-image.js new file mode 100644 index 0000000000..a10d50a983 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/inject-image.js @@ -0,0 +1,4 @@ +// This script block will trigger a violation report. +var i = document.createElement('img'); +i.src = '/content-security-policy/support/fail.png'; +document.body.appendChild(i); diff --git a/testing/web-platform/tests/content-security-policy/support/inject-image.sub.js b/testing/web-platform/tests/content-security-policy/support/inject-image.sub.js new file mode 100644 index 0000000000..acf04f325f --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/inject-image.sub.js @@ -0,0 +1,3 @@ +var i = document.createElement('img'); +i.src = "http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/fail.png"; +document.body.appendChild(i); diff --git a/testing/web-platform/tests/content-security-policy/support/logTest.sub.js b/testing/web-platform/tests/content-security-policy/support/logTest.sub.js new file mode 100644 index 0000000000..29b8a271f5 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/logTest.sub.js @@ -0,0 +1,41 @@ +// note, this template substitution is XSS, but no way to avoid it in this framework +var expected_logs = {{GET[logs]}}; +var timeout = "{{GET[timeout]}}"; +if (timeout == "") { + timeout = 2; +} + +if (expected_logs.length == 0) { + function log_assert(msg) { + test(function () { assert_unreached(msg) }); + } +} else { + var t_log = async_test('Expecting logs: {{GET[logs]}}'); + step_timeout(function() { + if(t_log.phase != t_log.phases.COMPLETE){ + t_log.step(function () { assert_unreached('Logging timeout, expected logs ' + expected_logs + ' not sent.') }); + t_log.done(); + } + }, timeout * 1000); + function log(msg) { + //cons/**/ole.log(msg); + t_log.step(function () { + if (msg.match(/^FAIL/i)) { + assert_unreached(msg); + t_log.done(); + } + for (var i = 0; i < expected_logs.length; i++) { + if (expected_logs[i] == msg) { + assert_equals(expected_logs[i], msg); + expected_logs.splice(i, 1); + if (expected_logs.length == 0) { + t_log.done(); + } + return; + } + } + assert_unreached('unexpected log: ' + msg); + t_log.done(); + }); + } +} diff --git a/testing/web-platform/tests/content-security-policy/support/manifest.json b/testing/web-platform/tests/content-security-policy/support/manifest.json new file mode 100644 index 0000000000..97da19c5ca --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/manifest.json @@ -0,0 +1,5 @@ +{ + "name": "Dummy manifest", + "start_url": "/start.html" +} + \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js b/testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js new file mode 100644 index 0000000000..501f7a9208 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/nonce-should-be-blocked.js @@ -0,0 +1 @@ +t.unreached_func(document.currentScript.getAttribute('src') + " should not execute.")(); diff --git a/testing/web-platform/tests/content-security-policy/support/pass.png b/testing/web-platform/tests/content-security-policy/support/pass.png new file mode 100644 index 0000000000..2fa1e0ac06 Binary files /dev/null and b/testing/web-platform/tests/content-security-policy/support/pass.png differ diff --git a/testing/web-platform/tests/content-security-policy/support/pass2.png b/testing/web-platform/tests/content-security-policy/support/pass2.png new file mode 100644 index 0000000000..2fa1e0ac06 Binary files /dev/null and b/testing/web-platform/tests/content-security-policy/support/pass2.png differ diff --git a/testing/web-platform/tests/content-security-policy/support/ping.js b/testing/web-platform/tests/content-security-policy/support/ping.js new file mode 100644 index 0000000000..750ae45f96 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/ping.js @@ -0,0 +1,12 @@ +if (typeof ServiceWorkerGlobalScope === "function") { + self.onmessage = function (e) { e.source.postMessage("ping"); }; +} else if (typeof SharedWorkerGlobalScope === "function") { + onconnect = function (e) { + var port = e.ports[0]; + + port.onmessage = function () { port.postMessage("ping"); } + port.postMessage("ping"); + }; +} else if (typeof DedicatedWorkerGlobalScope === "function") { + self.postMessage("ping"); +} diff --git a/testing/web-platform/tests/content-security-policy/support/post-message.js b/testing/web-platform/tests/content-security-policy/support/post-message.js new file mode 100644 index 0000000000..69daa31d2f --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/post-message.js @@ -0,0 +1 @@ +postMessage("importScripts allowed"); diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html b/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html new file mode 100644 index 0000000000..a0308ad98b --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/postmessage-fail.html @@ -0,0 +1,4 @@ + diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html b/testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html new file mode 100644 index 0000000000..e1bdf7102f --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/postmessage-pass-to-opener.html @@ -0,0 +1,3 @@ + diff --git a/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html b/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html new file mode 100644 index 0000000000..700167b5db --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/postmessage-pass.html @@ -0,0 +1,4 @@ + diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-helper.js b/testing/web-platform/tests/content-security-policy/support/prefetch-helper.js new file mode 100644 index 0000000000..c0c0be9157 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/prefetch-helper.js @@ -0,0 +1,85 @@ +setup(_ => { + assert_implements_optional( + document.createElement('link').relList.supports('prefetch'), + "Browser supports prefetch."); + assert_implements_optional( + "PerformanceResourceTiming" in window, + "Browser supports performance APIs."); +}); + +function assert_resource_not_downloaded(test, url) { + // CSP failures generate resource timing entries, so let's make sure that + // download sizes are 0. + const entries = performance.getEntriesByName(url, 'resource'); + for (const entry of entries) { + assert_equals(entry.transferSize, 0, 'transferSize'); + assert_equals(entry.encodedBodySize, 0, 'encodedBodySize'); + assert_equals(entry.decodedBodySize, 0, 'decodedBodySize'); + } +} + +function assert_link_prefetches(test, link) { + assert_no_csp_event_for_url(test, link.href); + + link.onerror = test.unreached_func('onerror should not fire.'); + + // Test is finished when either the `load` event fires, or we get a performance + // entry showing that the resource loaded successfully. + link.onload = test.step_func(test.step_func_done()); + waitUntilResourceDownloaded(link.href).then(test.step_func_done()); + + document.head.appendChild(link); +} + +function assert_link_does_not_prefetch(test, link) { + let cspEvent = false; + let errorEvent = false; + + waitUntilCSPEventForURL(test, link.href) + .then(test.step_func(e => { + cspEvent = true; + assert_equals(e.violatedDirective, "prefetch-src"); + assert_equals(e.effectiveDirective, "prefetch-src"); + + if (errorEvent) + test.done(); + })); + + link.onerror = test.step_func(e => { + errorEvent = true; + if (cspEvent) + test.done(); + }); + link.onload = test.unreached_func('onload should not fire.'); + + document.head.appendChild(link); +} + +async function try_to_prefetch(href, test) { + const url = new URL(href, location.href); + url.searchParams.set( + 'pipe', + '|header(Cache-Control, max-age=604800)' + + '|header(Access-Control-Allow-Origin, *)' + + '|header(Timing-Allow-Origin, *)'); + url.searchParams.set('uuid', token()); + + const link = document.createElement('link'); + link.rel = 'prefetch'; + link.href = url.toString(); + link.crossOrigin = 'anonymous'; + test.add_cleanup(() => link.remove()); + + const didPrefetch = new Promise(resolve => { + const observer = new PerformanceObserver(list => { + const entries = list.getEntriesByName(link.href); + if (entries.length) { + resolve(entries[0]); + } + }); + observer.observe({entryTypes: ['resource']}) + }); + document.head.appendChild(link); + const entry = await didPrefetch; + return entry.requestStart > 0 && entry.decodedBodySize > 0; +} diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css new file mode 100644 index 0000000000..4c4fa46442 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css @@ -0,0 +1,3 @@ +/* This CSS file sends some headers: + * Link: ;rel=prefetch + */ diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers new file mode 100644 index 0000000000..eaf7b16638 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/prefetch-subresource.css.headers @@ -0,0 +1 @@ +Link: ;rel=prefetch diff --git a/testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html b/testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html new file mode 100644 index 0000000000..8185a3abee --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/prefetch-with-csp.html @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/testing/web-platform/tests/content-security-policy/support/resource.py b/testing/web-platform/tests/content-security-policy/support/resource.py new file mode 100644 index 0000000000..4d73d5bf76 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/resource.py @@ -0,0 +1,5 @@ +def main(request, response): + headers = [] + headers.append((b"Access-Control-Allow-Origin", b"*")) + + return headers, b"{ \"result\": \"success\" }" diff --git a/testing/web-platform/tests/content-security-policy/support/service-worker-helper.js b/testing/web-platform/tests/content-security-policy/support/service-worker-helper.js new file mode 100644 index 0000000000..b5f65c96a0 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/service-worker-helper.js @@ -0,0 +1,5 @@ +var url = new URL("../support/ping.js", document.baseURI).toString(); +if (document.getElementById("foo").hasAttribute("blocked-worker")) + assert_service_worker_is_blocked(url, document.getElementById("foo").getAttribute("data-desc-fallback")); +else + assert_service_worker_is_loaded(url, document.getElementById("foo").getAttribute("data-desc-fallback")); \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js b/testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js new file mode 100644 index 0000000000..2a3873873f --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/shared-worker-helper.js @@ -0,0 +1,5 @@ +var url = new URL("../support/ping.js", document.baseURI).toString(); +if (document.getElementById("foo").hasAttribute("blocked-worker")) + assert_shared_worker_is_blocked(url, document.getElementById("foo").getAttribute("data-desc-fallback")); +else + assert_shared_worker_is_loaded(url, document.getElementById("foo").getAttribute("data-desc-fallback")); \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/siblingPath.js b/testing/web-platform/tests/content-security-policy/support/siblingPath.js new file mode 100644 index 0000000000..f4012f04dd --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/siblingPath.js @@ -0,0 +1,5 @@ + buildSiblingPath = function(hostPrefix, relativePath, newPort) { + var port = newPort ? newPort : document.location.port; + var path = document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/') + 1); + return (document.location.protocol + '//' + hostPrefix + "." + document.location.hostname + ':' + port + path + relativePath); +}; \ No newline at end of file diff --git a/testing/web-platform/tests/content-security-policy/support/testharness-helper.js b/testing/web-platform/tests/content-security-policy/support/testharness-helper.js new file mode 100644 index 0000000000..5c36e286da --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/testharness-helper.js @@ -0,0 +1,142 @@ +function assert_no_csp_event_for_url(test, url) { + self.addEventListener("securitypolicyviolation", test.step_func(e => { + if (e.blockedURI !== url) + return; + assert_unreached("SecurityPolicyViolation event fired for " + url); + })); +} + +function assert_no_event(test, obj, name) { + obj.addEventListener(name, test.unreached_func("The '" + name + "' event should not have fired.")); +} + +function waitUntilCSPEventForURLOrLine(test, url, line) { + return new Promise((resolve, reject) => { + self.addEventListener("securitypolicyviolation", test.step_func(e => { + if (e.blockedURI == url && (!line || line == e.lineNumber)) + resolve(e); + })); + }); +} + +function waitUntilCSPEventForURL(test, url) { + return waitUntilCSPEventForURLOrLine(test, url); +} + +function waitUntilCSPEventForEval(test, line) { + return waitUntilCSPEventForURLOrLine(test, "eval", line); +} + +function waitUntilCSPEventForTrustedTypes(test) { + return waitUntilCSPEventForURLOrLine(test, "trusted-types-sink"); +} + +function waitUntilEvent(obj, name) { + return new Promise((resolve, reject) => { + obj.addEventListener(name, resolve); + }); +} + +// Given the URL of a worker that pings its opener upon load, this +// function builds a test that asserts that the ping is received, +// and that no CSP event fires. +function assert_worker_is_loaded(url, description, expected_message = "ping") { + async_test(t => { + assert_no_csp_event_for_url(t, url); + var w = new Worker(url); + assert_no_event(t, w, "error"); + waitUntilEvent(w, "message") + .then(t.step_func_done(e => { + assert_equals(e.data, expected_message); + })); + }, description); +} + +function assert_shared_worker_is_loaded(url, description, expected_message = "ping") { + async_test(t => { + assert_no_csp_event_for_url(t, url); + var w = new SharedWorker(url); + assert_no_event(t, w, "error"); + waitUntilEvent(w.port, "message") + .then(t.step_func_done(e => { + assert_equals(e.data, expected_message); + })); + w.port.start(); + }, description); +} + +function assert_service_worker_is_loaded(url, description) { + promise_test(t => { + assert_no_csp_event_for_url(t, url); + return Promise.all([ + waitUntilEvent(navigator.serviceWorker, "message") + .then(e => { + assert_equals(e.data, "ping"); + }), + navigator.serviceWorker.register(url, { scope: url }) + .then(r => { + var sw = r.active || r.installing || r.waiting; + t.add_cleanup(_ => r.unregister()); + sw.postMessage("pong?"); + }) + ]); + }, description); +} + +// Given the URL of a worker that pings its opener upon load, this +// function builds a test that asserts that the constructor throws +// a SecurityError, and that a CSP event fires. +function assert_worker_is_blocked(url, description) { + async_test(t => { + // If |url| is a blob, it will be stripped down to "blob" for reporting. + var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url; + waitUntilCSPEventForURL(t, reportedURL) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, reportedURL); + assert_equals(e.violatedDirective, "worker-src"); + assert_equals(e.effectiveDirective, "worker-src"); + })); + + // TODO(mkwst): We shouldn't be throwing here. We should be firing an + // `error` event on the Worker. https://crbug.com/663298 + assert_throws_dom("SecurityError", function () { + var w = new Worker(url); + }); + }, description); +} + +function assert_shared_worker_is_blocked(url, description) { + async_test(t => { + // If |url| is a blob, it will be stripped down to "blob" for reporting. + var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url; + waitUntilCSPEventForURL(t, reportedURL) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, reportedURL); + assert_equals(e.violatedDirective, "worker-src"); + assert_equals(e.effectiveDirective, "worker-src"); + })); + + // TODO(mkwst): We shouldn't be throwing here. We should be firing an + // `error` event on the SharedWorker. https://crbug.com/663298 + assert_throws_dom("SecurityError", function () { + var w = new SharedWorker(url); + }); + }, description); +} + +function assert_service_worker_is_blocked(url, description) { + promise_test(t => { + assert_no_event(t, navigator.serviceWorker, "message"); + // If |url| is a blob, it will be stripped down to "blob" for reporting. + var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url; + return Promise.all([ + waitUntilCSPEventForURL(t, reportedURL) + .then(t.step_func_done(e => { + assert_equals(e.blockedURI, reportedURL); + assert_equals(e.violatedDirective, "worker-src"); + assert_equals(e.effectiveDirective, "worker-src"); + })), + promise_rejects_dom(t, "SecurityError", navigator.serviceWorker.register(url, { scope: url })) + ]); + }, description); +} diff --git a/testing/web-platform/tests/content-security-policy/support/var-a.js b/testing/web-platform/tests/content-security-policy/support/var-a.js new file mode 100644 index 0000000000..5fc5fde204 --- /dev/null +++ b/testing/web-platform/tests/content-security-policy/support/var-a.js @@ -0,0 +1 @@ +self.a = true; -- cgit v1.2.3