tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 9b47aad215d5adec5f1180960389cffee5f610fe
parent f1ac1edc87e033d6227f27441acdb5824e1a43e1
Author: Daniel Holbert <dholbert@cs.stanford.edu>
Date:   Thu, 30 Oct 2025 18:52:40 +0000

Bug 1970490: Add WPT for cross-origin mask-image referenced from cross-origin stylesheet. r=emilio,layout-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D259869

Diffstat:
Atesting/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-frame.sub.html | 6++++++
Atesting/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-image.png | 0
Atesting/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-ref.html | 11+++++++++++
Atesting/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-styles.sub.css | 29+++++++++++++++++++++++++++++
Atesting/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001.sub.html | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 139 insertions(+), 0 deletions(-)

diff --git a/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-frame.sub.html b/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-frame.sub.html @@ -0,0 +1,6 @@ +<!doctype html> +<link rel="stylesheet" + href="https://{{domains[www1]}}:{{ports[https][0]}}/css/css-masking/mask-image/mask-image-cors-001-styles.sub.css"> +<div id="mask-allowed"></div> +<br> +<div id="mask-disallowed"></div> diff --git a/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-image.png b/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-image.png Binary files differ. diff --git a/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-ref.html b/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-ref.html @@ -0,0 +1,11 @@ +<!doctype html> +<style> +#ref { + height: 50px; + width: 50px; + background: blue; +} +</style> +<!-- The testcase's masked area should render as two 50px-wide squares, one to the lower-right of the other. --> +<div id="ref"></div> +<div id="ref" style="position:relative; left: 50px"></div> diff --git a/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-styles.sub.css b/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001-styles.sub.css @@ -0,0 +1,29 @@ +#mask-allowed { + height: 100px; + width: 100px; + /* We reference the image from "origin C" (the www2 origin); and we ensure + that it's served with a 'Access-Control-Allow-Origin' header whose value + is set to "origin A" (the "www" origin). This matches the origin of the + iframe's inner document, and hence allows the mask-image to be used + there, which should make this element render as two blue squares with + corners touching. See the main comment in mask-image-cors-001.sub.html + for more details. */ + mask-image: url("https://{{domains[www2]}}:{{ports[https][0]}}/css/css-masking/mask-image/mask-image-cors-001-image.png?pipe=header(Access-Control-Allow-Origin,https://{{domains[www]}}:{{ports[https][0]}})"); + mask-size: 100px 100px; + background: blue; +} + +#mask-disallowed { + height: 100px; + width: 100px; + /* We reference the image from "origin C" (the www2 origin); and we ensure + that it's served with a 'Access-Control-Allow-Origin' header whose value + is set to "origin B" (the "www1" origin). This happens to match this + stylesheet's origin, but it *does not match* the origin of the iframe's + inner document. So, the mask-image should be forbidden in that document, + and this element should render fully-masked, i.e. no red should be + visible. */ + mask-image: url("https://{{domains[www2]}}:{{ports[https][0]}}/css/css-masking/mask-image/mask-image-cors-001-image.png?pipe=header(Access-Control-Allow-Origin,https://{{domains[www1]}}:{{ports[https][0]}})"); + mask-size: 100px 100px; + background: red; +} diff --git a/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001.sub.html b/testing/web-platform/tests/css/css-masking/mask-image/mask-image-cors-001.sub.html @@ -0,0 +1,93 @@ +<!doctype html> +<html class="reftest-wait"> +<title>Cross-origin CSS mask-images can be referenced via cross-origin + stylesheets, iff the image allows the origin of the document.</title> +<link rel="help" href="https://www.w3.org/TR/css-masking-1/#the-mask-image"> +<link rel="help" href="https://fetch.spec.whatwg.org/#http-access-control-allow-origin"> +<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> +<link rel="author" title="Mozilla" href="https://www.mozilla.org"> +<link rel="match" href="mask-image-cors-001-ref.html"> + +<!-- This test is set up with several different resources, each referenced via + a different origin, to test a particular cross-origin scenario. The origins + are referenced symbolically, using the WPT web-server's + variable-substitution mechanism described at + https://web-platform-tests.org/writing-tests/server-features.html#tests-involving-multiple-origins + https://web-platform-tests.org/writing-tests/server-pipes.html#sub + + The various resources/origins involved here are: + + (0) The outer document - this is a shim whose origin we don't need to know + or care about. This outer document's purpose is just to load the + iframe's inner document, from a particular *known* origin. + + (1) The iframe's inner document (mask-image-cors-001-frame.sub.html), + loaded from "origin A", https://{{domains[www]}}:{{ports[https][0]}} + + (2) The stylesheet (mask-image-cors-001-styles.sub.css), loaded from + "origin B", https://{{domains[www1]}}:{{ports[https][0]}} + + (3) The mask-image (mask-image-cors-001-image.png), loaded from + "origin C", https://{{domains[www2]}}:{{ports[https][0]}} + Importantly, we reference this image URL with an added query-param: + `pipe=header(Access-Control-Allow-Origin,...)`, where "..." is + origin A for #mask-allowed. This prompts the WPT web-server to serve + that resource with the Access-Control-Allow-Origin header set to + origin A, which should allow that resource to be used in the iframe's + inner document. (We use a different header-value for #mask-disallowed + which should prevent that one from being usable.) + + The test's expectation is that: + * The iframe's inner document should successfully load the stylesheet. + * Then the iframe should make a cross-origin request to load the + mask-image for the #mask-allowed element, and the UA should allow the + document to use that mask-image, because the response's + Access-Control-Allow-Origin header matches the document. + * The iframe should *also* make a cross-origin request to load the + mask-image for the #mask-disallowed element, and the UA should *not* + allow the document to use that mask-image, because the header value + does not match the document (even though it matches the stylesheet). + * Therefore: the iframe should render with two blue squares, with corners + touching like a checkerboard (from the square solid-blue #mask-allowed + element, masked via the checkerboard-like mask-image). And no red should + be visible because #mask-disallowed should be fully masked away, with + its mask-image request having failed. +--> +<style> + /* Zero out the margin in the outer document, so that the iframe's inner + document is rendered directly at the top-left corner. (This makes the + reference case slightly simpler.) */ + body { margin: 0; } + iframe { + border: none; + height: 400px; + width: 400px; + } +</style> +<body> +<script> + // Construct the iframe URL: + // + // The iframe's origin is "origin A" described in the main explanatory + // comment above: + const frameOrigin = "https://{{domains[www]}}:{{ports[https][0]}}"; + + // The iframe's path/filename is the same as this outer document, but with + // "-frame.sub" inserted before the .html file-extension: + const framePath = window.location.pathname.replace(".sub.html", + "-frame.sub.html"); + + // The iframe's URL is those^ concatenated together: + const frameURL = `${frameOrigin}${framePath}`; + + // Create/load the iframe: + let myIframe = document.createElement("iframe"); + myIframe.src = frameURL; + + // We can take the reftest snapshot once the iframe has finished loading. + // (Its mask-image resource will block its load event.) + myIframe.addEventListener("load", ()=>{ + document.documentElement.removeAttribute("class"); + }); + document.body.appendChild(myIframe); +</script>