Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /service-workers/service-worker/fetch-canvas-tainting-double-write.https.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<meta charset="utf-8">
<title>canvas tainting when written twice</title>
<script>
function loadImage(doc, url) {
return new Promise((resolve, reject) => {
const image = doc.createElement('img');
image.onload = () => { resolve(image); }
image.onerror = () => { reject('failed to load: ' + url); };
image.src = url;
});
}
// Tests that a canvas is tainted after it's written to with both a clear image
// and opaque image from the same URL. A bad implementation might cache the
// info of the clear image and assume the opaque image is also clear because
promise_test(async (t) => {
// Set up a service worker and a controlled iframe.
const script = 'resources/fetch-canvas-tainting-double-write-worker.js';
const scope = 'resources/fetch-canvas-tainting-double-write-iframe.html';
const registration = await service_worker_unregister_and_register(
t, script, scope);
t.add_cleanup(() => registration.unregister());
await wait_for_state(t, registration.installing, 'activated');
const iframe = await with_iframe(scope);
t.add_cleanup(() => iframe.remove());
// Load the same cross-origin image URL through the controlled iframe and
// this uncontrolled frame. The service worker responds with a same-origin
// image for the controlled iframe, so it is cleartext.
const imagePath = base_path() + 'resources/fetch-access-control.py?PNGIMAGE';
const imageUrl = get_host_info()['HTTPS_REMOTE_ORIGIN'] + imagePath;
const clearImage = await loadImage(iframe.contentDocument, imageUrl);
const opaqueImage = await loadImage(document, imageUrl);
// Set up a canvas for testing tainting.
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = clearImage.width;
canvas.height = clearImage.height;
// The clear image and the opaque image have the same src URL. But...
// ... the clear image doesn't taint the canvas.
context.drawImage(clearImage, 0, 0);
assert_true(canvas.toDataURL().length > 0);
// ... the opaque image taints the canvas.
context.drawImage(opaqueImage, 0, 0);
assert_throws_dom('SecurityError', () => { canvas.toDataURL(); });
}, 'canvas is tainted after writing both a non-opaque image and an opaque image from the same URL');
</script>