зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1564656 [wpt PR 17426] - Add Preload + SRI web platform tests for script + style destinations, a=testonly
Automatic update from web-platform-tests Add Preload + SRI web platform tests for script + style destinations More preload destinations will be added after this CL, as well as the main Preload + SRI implementation, to keep the changes here minimal. R=kouhei@chromium.org, yhirano@chromium.org, yoavweiss@chromium.org Bug: 677022 Change-Id: I596ac006874fb02bcd330422bd6496a05d388d45 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1669954 Commit-Queue: Dominic Farolino <dom@chromium.org> Reviewed-by: Yutaka Hirano <yhirano@chromium.org> Reviewed-by: Mike West <mkwst@chromium.org> Cr-Commit-Position: refs/heads/master@{#672808} -- wpt-commits: f0c2701197a8dc5682b0361698b73a0be9fd983c wpt-pr: 17426
This commit is contained in:
Родитель
2a662aaffe
Коммит
681c329519
|
@ -0,0 +1,284 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Subresource Integrity</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/sriharness.js"></script>
|
||||
<script src="/common/utils.js"></script>
|
||||
<script src="/subresource-integrity/sri-test-helpers.sub.js"></script>
|
||||
|
||||
<div id="log"></div>
|
||||
|
||||
<div id="container"></div>
|
||||
<script>
|
||||
// This is a list of information for each preload destination. The information
|
||||
// is used in a loop iterating over the below tests, so that each test is run
|
||||
// for each destination.
|
||||
const preload_destination_info = [
|
||||
{
|
||||
destination: 'script', ext: '.js', supports_sri: true,
|
||||
sha256: 'sha256-Bu681KMnQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA=',
|
||||
sha384: 'sha384-cINXh+nCzEHPWzXS7eoT+vYMBpyqczOybRLNU3XAButFWCRhHT5hLByIbPRqIm2f',
|
||||
sha512: 'sha512-KZdenhzBd7X7Q/vmaOSyvFz1CGdoVt26xzCZjlkU9lfBEK+V/ougGys7iYDi0+tOHIQSQa87bIqx95R7GU7I9Q=='
|
||||
},
|
||||
{
|
||||
destination: 'style', ext: '.css', supports_sri: true,
|
||||
sha256: 'sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=',
|
||||
sha384: 'sha384-wDAWxH4tOWBwAwHfBn9B7XuNmFxHTMeigAMwn0iVQ0zq3FtmYMLxihcGnU64CwcX',
|
||||
sha512: 'sha512-9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2HSZX4l6w=='
|
||||
},
|
||||
// TODO(domfarolino): Add more destinations.
|
||||
];
|
||||
|
||||
for (const info of preload_destination_info) {
|
||||
const {destination, ext, supports_sri, sha256, sha384, sha512} = info;
|
||||
|
||||
// Preload + Subresource Integrity tests. These tests work by passing some
|
||||
// destination-specific information (defined in |preload_destination_info|)
|
||||
// to the below tests, which do the following:
|
||||
// Create a <link rel="preload"> for the given destination, with the
|
||||
// specified `integrity`. After this has either loaded or failed to load,
|
||||
// the subresource element corresponding to |destination| will be created,
|
||||
// attempting to re-use the preloaded resource. `integrity` may be specified
|
||||
// on the subresource elements that support SRI as well. The subresource
|
||||
// will either load or fail to load, and the result will be compared with an
|
||||
// expectation passed to the test.
|
||||
SRIPreloadTest(
|
||||
true, /* preload_sri_success */
|
||||
true, /* subresource_sri_success */
|
||||
`Same-origin ${destination} with correct sha256 hash.`, /* name */
|
||||
destination, /* destination */
|
||||
same_origin_prefix + destination + ext + `?${token()}`, /* resource_url (for preload + subresource) */
|
||||
{integrity: sha256}, /* link_attrs */
|
||||
{} /* subresource_attrs */
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with correct sha384 hash.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: sha384},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with correct sha512 hash.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: sha512},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with empty integrity.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`Same-origin ${destination} with incorrect hash.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with multiple sha256 hashes, including correct.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: `${sha256} sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead`},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with multiple sha256 hashes, including unknown algorithm.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: `${sha256} foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead`},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with sha256 mismatch, sha512 match`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: `${sha512} sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead`},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`Same-origin ${destination} with sha256 match, sha512 mismatch`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: `sha512-deadbeefspbnUnwooKGNNCb39nvg+EW0O9hDScTXeo/9pVZztLSUYU3LNV6H0lZapo8bCJUpyPPLAzE9fDzpxg== ${sha256}`},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`<crossorigin='anonymous'> ${destination} with correct hash, ACAO: *`,
|
||||
destination,
|
||||
xorigin_prefix + destination + ext + `?${token()}` + anonymous,
|
||||
{integrity: sha256, crossOrigin: 'anonymous'},
|
||||
{crossOrigin: "anonymous"}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`<crossorigin='anonymous'> ${destination} with incorrect hash, ACAO: *`,
|
||||
destination,
|
||||
xorigin_prefix + destination + ext + `?${token()}` + anonymous,
|
||||
{integrity: "sha256-sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead", crossOrigin: "anonymous"},
|
||||
{crossOrigin: "anonymous"}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`<crossorigin='use-credentials'> ${destination} with correct hash, CORS-eligible`,
|
||||
destination,
|
||||
xorigin_prefix + destination + ext + `?${token()}` + use_credentials,
|
||||
{integrity: sha256, crossOrigin: "use-credentials"},
|
||||
{crossOrigin: "use-credentials"}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`<crossorigin='use-credentials'> ${destination} with incorrect hash CORS-eligible`,
|
||||
destination,
|
||||
xorigin_prefix + destination + ext + `?${token()}` + use_credentials,
|
||||
{integrity: "sha256-deadbeef2S+pTRZgiw3DWrhC6JLDlt2zRyGpwH7unU8=", crossOrigin: "use-credentials"},
|
||||
{crossOrigin: "use-credentials"}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`<crossorigin='anonymous'> ${destination} with CORS-ineligible resource`,
|
||||
destination,
|
||||
// not piping ACAO header makes this CORS-ineligible
|
||||
xorigin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: sha256, crossOrigin: "anonymous"},
|
||||
{crossOrigin: "anonymous"}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`Cross-origin ${destination}, not CORS request, with correct hash`,
|
||||
destination,
|
||||
xorigin_prefix + destination + ext + `?${token()}` + anonymous,
|
||||
{integrity: sha256},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`Cross-origin ${destination}, not CORS request, with hash mismatch`,
|
||||
destination,
|
||||
xorigin_prefix + destination + ext + `?${token()}` + anonymous,
|
||||
{integrity: "sha256-deadbeef01Y0yKSx3/UoIKtIY2UQ9+H8WGyyMuOWOC0="},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Cross-origin ${destination}, empty integrity`,
|
||||
destination,
|
||||
xorigin_prefix + destination + ext + `?${token()}` + anonymous,
|
||||
{},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with correct hash, options.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: `${sha256}?foo=bar?spam=eggs`},
|
||||
{}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with unknown algorithm only.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: "foo666-8aBiAJl3ukQwSJ6eTs5wl6hGjnOtyXjcTRdAf89uIfY="},
|
||||
{}
|
||||
)
|
||||
|
||||
// The below tests are specific to subresource destinations that support
|
||||
// SRI. See |supports_sri|.
|
||||
if (supports_sri) {
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
true,
|
||||
`Same-origin ${destination} with matching digest re-uses preload with matching digest.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: sha256},
|
||||
{integrity: sha256}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
true,
|
||||
false,
|
||||
`Same-origin ${destination} with non-matching digest does not re-use preload with matching digest.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: sha256},
|
||||
{integrity: "sha256-deadbeefQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
true,
|
||||
`Same-origin ${destination} with matching digest does not re-use preload with non-matching digest.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: "sha256-deadbeefQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="},
|
||||
{integrity: sha256}
|
||||
)
|
||||
|
||||
SRIPreloadTest(
|
||||
false,
|
||||
false,
|
||||
`Same-origin ${destination} with non-matching digest does not re-use preload with non-matching digest.`,
|
||||
destination,
|
||||
same_origin_prefix + destination + ext + `?${token()}`,
|
||||
{integrity: "sha256-deadbeefQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="},
|
||||
{integrity: "sha256-deaddeadbeefYHFvsYdWumweeFAw0hJDTFt9seErghA="}
|
||||
)
|
||||
|
||||
} // if.
|
||||
|
||||
} // for-of.
|
||||
</script>
|
|
@ -1,3 +1,5 @@
|
|||
// TODO(domfarolino): Refactor SRIScriptTest to just be a function instead of a
|
||||
// constructor, since there is no need to produce another object.
|
||||
var SRIScriptTest = function(pass, name, src, integrityValue, crossoriginValue, nonce) {
|
||||
this.pass = pass;
|
||||
this.name = "Script: " + name;
|
||||
|
@ -32,6 +34,98 @@ SRIScriptTest.prototype.execute = function() {
|
|||
document.body.appendChild(e);
|
||||
};
|
||||
|
||||
function buildElementFromDestination(resource_url, destination, attrs) {
|
||||
// Assert: |destination| is a valid destination.
|
||||
let element;
|
||||
|
||||
// The below switch is responsible for:
|
||||
// 1. Creating the correct subresource element
|
||||
// 2. Setting said element's href, src, or fetch-instigating property
|
||||
// appropriately.
|
||||
switch (destination) {
|
||||
case "script":
|
||||
element = document.createElement(destination);
|
||||
element.src = resource_url;
|
||||
break;
|
||||
case "style":
|
||||
element = document.createElement('link');
|
||||
element.rel = 'stylesheet';
|
||||
element.href = resource_url;
|
||||
break;
|
||||
case "image":
|
||||
element = document.createElement('img');
|
||||
element.src = resource_url;
|
||||
break;
|
||||
default:
|
||||
assert_unreached("INVALID DESTINATION");
|
||||
}
|
||||
|
||||
// Apply the rest of the attributes, if any.
|
||||
for (const [attr_name, attr_val] of Object.entries(attrs)) {
|
||||
element[attr_name] = attr_val;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
const SRIPreloadTest = (preload_sri_success, subresource_sri_success, name,
|
||||
destination, resource_url, link_attrs,
|
||||
subresource_attrs) => {
|
||||
const test = async_test(name);
|
||||
const link = document.createElement('link');
|
||||
|
||||
// Early-fail in UAs that do not support `preload` links.
|
||||
test.step_func(() => {
|
||||
assert_true(link.relList.supports('preload'), "Clever message here.");
|
||||
})();
|
||||
|
||||
// Build up the link.
|
||||
link.rel = 'preload';
|
||||
link.as = destination;
|
||||
link.href = resource_url;
|
||||
for (const [attr_name, attr_val] of Object.entries(link_attrs)) {
|
||||
link[attr_name] = attr_val; // This may override `rel` to modulepreload.
|
||||
}
|
||||
|
||||
// Preload + subresource success and failure loading functions.
|
||||
const valid_preload_failed = test.step_func(() =>
|
||||
{ assert_unreached("Valid preload fired error handler.") });
|
||||
const invalid_preload_succeeded = test.step_func(() =>
|
||||
{ assert_unreached("Invalid preload load succeeded.") });
|
||||
const valid_subresource_failed = test.step_func(() =>
|
||||
{ assert_unreached("Valid subresource fired error handler.") });
|
||||
const invalid_subresource_succeeded = test.step_func(() =>
|
||||
{ assert_unreached("Invalid subresource load succeeded.") });
|
||||
const subresource_pass = test.step_func(() => { test.done(); });
|
||||
const preload_pass = test.step_func(() => {
|
||||
const subresource_element = buildElementFromDestination(
|
||||
resource_url,
|
||||
destination,
|
||||
subresource_attrs
|
||||
);
|
||||
|
||||
if (subresource_sri_success) {
|
||||
subresource_element.onload = subresource_pass;
|
||||
subresource_element.onerror = valid_subresource_failed;
|
||||
} else {
|
||||
subresource_element.onload = invalid_subresource_succeeded;
|
||||
subresource_element.onerror = subresource_pass;
|
||||
}
|
||||
|
||||
document.body.append(subresource_element);
|
||||
});
|
||||
|
||||
if (preload_sri_success) {
|
||||
link.onload = preload_pass;
|
||||
link.onerror = valid_preload_failed;
|
||||
} else {
|
||||
link.onload = invalid_preload_succeeded;
|
||||
link.onerror = preload_pass;
|
||||
}
|
||||
|
||||
document.head.append(link);
|
||||
}
|
||||
|
||||
// <link> tests
|
||||
// Style tests must be done synchronously because they rely on the presence
|
||||
// and absence of global style, which can affect later tests. Thus, instead
|
||||
|
@ -63,6 +157,8 @@ SRIStyleTest.prototype.execute = function() {
|
|||
var div = document.createElement("div");
|
||||
div.className = "testdiv";
|
||||
var e = document.createElement("link");
|
||||
|
||||
// The link relation is guaranteed to not be "preload" or "modulepreload".
|
||||
this.attrs.rel = this.attrs.rel || "stylesheet";
|
||||
for (var key in this.attrs) {
|
||||
if (this.attrs.hasOwnProperty(key)) {
|
||||
|
|
|
@ -9,19 +9,24 @@
|
|||
// Thus, we only want the Access-Control-Allow-Origin header to have
|
||||
// the port if it's not port 80 or 443, since the user agent will elide the
|
||||
// ports in those cases.
|
||||
const main_domain = "{{domains[]}}";
|
||||
const www_domain = "{{domains[www]}}";
|
||||
const default_port = (location.protocol === "https:") ? "{{ports[https][0]}}" :
|
||||
"{{ports[http][0]}}";
|
||||
const main_domain = '{{domains[]}}';
|
||||
const www_domain = '{{domains[www]}}';
|
||||
const default_port = (location.protocol === 'https:') ? '{{ports[https][0]}}' :
|
||||
'{{ports[http][0]}}';
|
||||
|
||||
const port_string = (default_port !== "80" && default_port !== "443") ?
|
||||
`:${default_port}` : "";
|
||||
const port_string = (default_port !== '80' && default_port !== '443') ?
|
||||
`:${default_port}` : '';
|
||||
const www_host_and_port = www_domain + port_string;
|
||||
|
||||
// General resource prefixes.
|
||||
const same_origin_prefix = '/subresource-integrity/';
|
||||
const xorigin_prefix = `${location.protocol}//${www_host_and_port}/subresource-integrity/`;
|
||||
|
||||
// General resource suffixes, for piping CORS headers.
|
||||
const anonymous = '&pipe=header(Access-Control-Allow-Origin,*)';
|
||||
const use_credentials = "&pipe=header(Access-Control-Allow-Credentials,true)|" +
|
||||
"header(Access-Control-Allow-Origin," + location.origin + ")";
|
||||
|
||||
// Note that all of these style URLs have query parameters started, so any
|
||||
// additional parameters should be appended starting with '&'.
|
||||
const xorigin_anon_style = location.protocol
|
||||
|
|
Загрузка…
Ссылка в новой задаче