diff options
Diffstat (limited to 'LayoutTests/http')
16 files changed, 983 insertions, 0 deletions
diff --git a/LayoutTests/http/tests/canvas/webgl/origin-clean-conformance-expected.txt b/LayoutTests/http/tests/canvas/webgl/origin-clean-conformance-expected.txt new file mode 100644 index 0000000..ca9217c --- /dev/null +++ b/LayoutTests/http/tests/canvas/webgl/origin-clean-conformance-expected.txt @@ -0,0 +1,29 @@ +This test ensures WebGL implementations follow proper same-origin restrictions. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + +PASS Playable video format found +PASS img was loaded + +check that an attempt to upload an image from another origin throws an exception. +PASS texImage2D with cross-origin image should throw exception. +PASS texSubImage2D with cross-origin image should throw exception. +check that readPixels and toDataURL continue to work against this canvas. +PASS readPixels should never throw exception -- not possible to dirty origin of WebGL canvas. +PASS should not throw exception by toDataURL for WebGL canvas, which should stay origin clean. +check that an attempt to upload a tainted canvas throws an exception. +PASS should throw exception by toDataURL for NON origin clean canvas. +PASS texImage2D with NON origin clean canvas should throw exception. +PASS texSubImage2D with NON origin clean canvas should throw exception. +check that readPixels and toDataURL continue to work against this canvas. +PASS readPixels should never throw exception -- not possible to dirty origin of WebGL canvas. +PASS should not throw exception by toDataURL for WebGL canvas, which should stay origin clean. +check that an attempt to upload a video from another origin throws an exception. +PASS texImage2D with cross-origin video should throw exception. +PASS texSubImage2D with cross-origin video should throw exception. +check that readPixels and toDataURL continue to work against this canvas. +PASS readPixels should never throw exception -- not possible to dirty origin of WebGL canvas. +PASS should not throw exception by toDataURL for WebGL canvas, which should stay origin clean. + +TEST COMPLETE + diff --git a/LayoutTests/http/tests/canvas/webgl/origin-clean-conformance.html b/LayoutTests/http/tests/canvas/webgl/origin-clean-conformance.html new file mode 100644 index 0000000..e983616 --- /dev/null +++ b/LayoutTests/http/tests/canvas/webgl/origin-clean-conformance.html @@ -0,0 +1,218 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>WebGL Origin Restrictions Conformance Tests</title> +<script> +function create3DContext(canvas, attributes) +{ + if (!canvas) + canvas = document.createElement("canvas"); + var context = null; + try { + context = canvas.getContext("experimental-webgl", attributes); + } catch(e) {} + if (!context) { + try { + context = canvas.getContext("webkit-3d", attributes); + } catch(e) {} + } + if (!context) { + try { + context = canvas.getContext("moz-webgl", attributes); + } catch(e) {} + } + if (!context) { + throw "Unable to fetch WebGL rendering context for Canvas"; + } + return context; +} + +function description(msg) +{ + // For MSIE 6 compatibility + var span = document.createElement("span"); + span.innerHTML = '<p>' + msg + '</p><p>On success, you will see a series of "<span class="pass">PASS</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>'; + var description = document.getElementById("description"); + if (description.firstChild) + description.replaceChild(span, description.firstChild); + else + description.appendChild(span); +} + +function debug(msg) +{ + var span = document.createElement("span"); + document.getElementById("console").appendChild(span); // insert it first so XHTML knows the namespace + span.innerHTML = msg + '<br />'; +} + +function escapeHTML(text) +{ + return text.replace(/&/g, "&").replace(/</g, "<").replace(/\0/g, "\\0"); +} + +function testPassed(msg) +{ + debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>'); +} + +function testFailed(msg) +{ + debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>'); +} + +function assertMsg(assertion, msg) { + if (assertion) { + testPassed(msg); + } else { + testFailed(msg); + } +} + +// Checks if function throws an exception. +function causedException(func) { + var hadException = false; + try { + func(); + } catch(e) { + hadException = true; + } + return hadException; +} + +var testVideo = false; + +function init() { + var video = document.getElementById("video"); + + var base = "http://localhost:8000/resources/"; + var videos = [ + ["video/mp4", base + "test.mp4"], + ["video/ogg", base + "test.ogv"], + ]; + var videoFile = null; + for (var i = 0; i < videos.length; ++i) { + if (video.canPlayType(videos[i][0])) { + videoFile = videos[i][1]; + break; + } + } + assertMsg(videoFile, "Playable video format found"); + + if (videoFile) { + if (window.layoutTestController) { + layoutTestController.overridePreference("WebKitWebGLEnabled", "1"); + layoutTestController.dumpAsText(); + layoutTestController.waitUntilDone(); + } + video.src = videoFile; + video.addEventListener("playing", runTests); + video.play(); + testVideo = true; + } else { + // Still run the other tests, even if the video failed. + runTests(); + } +} + +function runTests() { + description("This test ensures WebGL implementations follow proper same-origin restrictions."); + var img = document.getElementById("img"); + assertMsg(img.width > 0 && img.height > 0, "img was loaded"); + + function makeTexImage2D(gl, src) { + return function() { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, src); + }; + } + + function makeTexSubImage2D(gl, src) { + return function() { + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, src); + }; + } + + function makeReadPixels(gl) { + return function() { + var buf = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); + }; + } + + function makeToDataURL(canvas) { + return function() { + var data = canvas.toDataURL(); + } + } + + var canvas1 = document.getElementById("canvas1"); + var gl = create3DContext(canvas1); + + debug(""); + debug("check that an attempt to upload an image from another origin throws an exception."); + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + assertMsg(causedException(makeTexImage2D(gl, img)), + "texImage2D with cross-origin image should throw exception."); + assertMsg(causedException(makeTexSubImage2D(gl, img)), + "texSubImage2D with cross-origin image should throw exception."); + + debug("check that readPixels and toDataURL continue to work against this canvas."); + assertMsg(!causedException(makeReadPixels(gl)), + "readPixels should never throw exception -- not possible to dirty origin of WebGL canvas."); + assertMsg(!causedException(makeToDataURL(canvas1)), + "should not throw exception by toDataURL for WebGL canvas, which should stay origin clean."); + + debug("check that an attempt to upload a tainted canvas throws an exception."); + var canvas2 = document.getElementById("canvas2"); + var ctx2d = canvas2.getContext("2d"); + ctx2d.drawImage(img, 0, 0); + assertMsg(causedException(makeToDataURL(canvas2)), + "should throw exception by toDataURL for NON origin clean canvas."); + assertMsg(causedException(makeTexImage2D(gl, canvas2)), + "texImage2D with NON origin clean canvas should throw exception."); + assertMsg(causedException(makeTexSubImage2D(gl, canvas2)), + "texSubImage2D with NON origin clean canvas should throw exception."); + + debug("check that readPixels and toDataURL continue to work against this canvas."); + assertMsg(!causedException(makeReadPixels(gl)), + "readPixels should never throw exception -- not possible to dirty origin of WebGL canvas."); + assertMsg(!causedException(makeToDataURL(canvas1)), + "should not throw exception by toDataURL for WebGL canvas, which should stay origin clean."); + + if (testVideo) { + debug("check that an attempt to upload a video from another origin throws an exception."); + var video = document.getElementById("video"); + assertMsg(causedException(makeTexImage2D(gl, video)), + "texImage2D with cross-origin video should throw exception."); + assertMsg(causedException(makeTexSubImage2D(gl, video)), + "texSubImage2D with cross-origin video should throw exception."); + + debug("check that readPixels and toDataURL continue to work against this canvas."); + assertMsg(!causedException(makeReadPixels(gl)), + "readPixels should never throw exception -- not possible to dirty origin of WebGL canvas."); + assertMsg(!causedException(makeToDataURL(canvas1)), + "should not throw exception by toDataURL for WebGL canvas, which should stay origin clean."); + } + + debug('<br /><span class="pass">TEST COMPLETE</span>'); + if (window.layoutTestController) + layoutTestController.waitUntilDone(); + if (window.layoutTestController) { + layoutTestController.notifyDone(); + } +} +</script> +</head> +<body onload="init()"> +<div id="description"></div> +<div id="console"></div> +<canvas id="canvas1"></canvas> +<canvas id="canvas2"></canvas> +<img id="img" src="http://localhost:8000/local/resources/abe.png" style="display:none;"> +<video id="video" style="display:none;"/> +</body> +</html> diff --git a/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-expected.txt b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-expected.txt new file mode 100644 index 0000000..75cf15a --- /dev/null +++ b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-expected.txt @@ -0,0 +1,15 @@ +Untainted canvas: +PASS: Calling getImageData() from an untainted canvas was allowed. +PASS: Calling toDataURL() on an untainted canvas was allowed. + + +Tainted canvas: +PASS: Calling getImageData() from a canvas tainted by a remote image was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a remote image was allowed. +PASS: Calling getImageData() from a canvas tainted by a CORS-untained canvas was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a CORS-untained canvas was allowed. +PASS: Calling getImageData() from a canvas tainted by a remote image tainted pattern was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a remote image tainted pattern was allowed. +PASS: Calling getImageData() from a canvas tainted by a CORS-untainted canvas pattern was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a CORS-untainted canvas pattern was allowed. + diff --git a/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials-expected.txt b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials-expected.txt new file mode 100644 index 0000000..75cf15a --- /dev/null +++ b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials-expected.txt @@ -0,0 +1,15 @@ +Untainted canvas: +PASS: Calling getImageData() from an untainted canvas was allowed. +PASS: Calling toDataURL() on an untainted canvas was allowed. + + +Tainted canvas: +PASS: Calling getImageData() from a canvas tainted by a remote image was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a remote image was allowed. +PASS: Calling getImageData() from a canvas tainted by a CORS-untained canvas was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a CORS-untained canvas was allowed. +PASS: Calling getImageData() from a canvas tainted by a remote image tainted pattern was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a remote image tainted pattern was allowed. +PASS: Calling getImageData() from a canvas tainted by a CORS-untainted canvas pattern was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a CORS-untainted canvas pattern was allowed. + diff --git a/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials.html b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials.html new file mode 100644 index 0000000..a64ed5e --- /dev/null +++ b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials.html @@ -0,0 +1,108 @@ +<pre id="console"></pre> +<script> +if (window.layoutTestController) { + layoutTestController.dumpAsText(); + layoutTestController.waitUntilDone(); +} + +log = function(msg) +{ + document.getElementById('console').appendChild(document.createTextNode(msg + "\n")); +} + +testGetImageData = function(context, description) +{ + description = "Calling getImageData() from a canvas tainted by a " + description; + try { + var imageData = context.getImageData(0,0,100,100); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +testToDataURL = function(canvas, description) +{ + description = "Calling toDataURL() on a canvas CORS-untainted by a " + description; + try { + var dataURL = canvas.toDataURL(); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +test = function(canvas, description) +{ + testGetImageData(canvas.getContext("2d"), description); + testToDataURL(canvas, description); +} + +var image = new Image(); +image.onload = function() { + var canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + + // Control tests + log("Untainted canvas:"); + try { + var imageData = context.getImageData(0, 0, 100, 100); + log("PASS: Calling getImageData() from an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling getImageData() from an untainted canvas was not allowed: Threw error: " + e + "."); + } + try { + var dataURL = canvas.toDataURL(); + log("PASS: Calling toDataURL() on an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling toDataURL() on an untainted canvas was not allowed: Threw error: " + e + "."); + } + + log("\n"); + log("Tainted canvas:"); + // Test reading from a canvas after drawing a remote image onto it + context.drawImage(image, 0, 0, 100, 100); + + test(canvas, "remote image"); + + var dirtyCanvas = canvas; + + // Now test reading from a canvas after drawing a tainted canvas onto it + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + context.drawImage(dirtyCanvas, 0, 0, 100, 100); + + test(canvas, "CORS-untained canvas"); + + // Test reading after using a tainted pattern + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + var remoteImagePattern = context.createPattern(image, "repeat"); + context.fillStyle = remoteImagePattern; + context.fillRect(0, 0, 100, 100); + + test(canvas, "remote image tainted pattern"); + + // Test reading after using a tainted pattern + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + var taintedCanvasPattern = context.createPattern(dirtyCanvas, "repeat"); + context.fillStyle = taintedCanvasPattern; + context.fillRect(0, 0, 100, 100); + + test(canvas, "CORS-untainted canvas pattern"); + + if (window.layoutTestController) + layoutTestController.notifyDone(); +} +image.crossOrigin = "use-credentials"; +image.src = "http://localhost:8000/security/resources/abe-allow-credentials.php"; +</script> diff --git a/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed.html b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed.html new file mode 100644 index 0000000..610605f --- /dev/null +++ b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-allowed.html @@ -0,0 +1,108 @@ +<pre id="console"></pre> +<script> +if (window.layoutTestController) { + layoutTestController.dumpAsText(); + layoutTestController.waitUntilDone(); +} + +log = function(msg) +{ + document.getElementById('console').appendChild(document.createTextNode(msg + "\n")); +} + +testGetImageData = function(context, description) +{ + description = "Calling getImageData() from a canvas tainted by a " + description; + try { + var imageData = context.getImageData(0,0,100,100); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +testToDataURL = function(canvas, description) +{ + description = "Calling toDataURL() on a canvas CORS-untainted by a " + description; + try { + var dataURL = canvas.toDataURL(); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +test = function(canvas, description) +{ + testGetImageData(canvas.getContext("2d"), description); + testToDataURL(canvas, description); +} + +var image = new Image(); +image.onload = function() { + var canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + + // Control tests + log("Untainted canvas:"); + try { + var imageData = context.getImageData(0, 0, 100, 100); + log("PASS: Calling getImageData() from an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling getImageData() from an untainted canvas was not allowed: Threw error: " + e + "."); + } + try { + var dataURL = canvas.toDataURL(); + log("PASS: Calling toDataURL() on an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling toDataURL() on an untainted canvas was not allowed: Threw error: " + e + "."); + } + + log("\n"); + log("Tainted canvas:"); + // Test reading from a canvas after drawing a remote image onto it + context.drawImage(image, 0, 0, 100, 100); + + test(canvas, "remote image"); + + var dirtyCanvas = canvas; + + // Now test reading from a canvas after drawing a tainted canvas onto it + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + context.drawImage(dirtyCanvas, 0, 0, 100, 100); + + test(canvas, "CORS-untained canvas"); + + // Test reading after using a tainted pattern + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + var remoteImagePattern = context.createPattern(image, "repeat"); + context.fillStyle = remoteImagePattern; + context.fillRect(0, 0, 100, 100); + + test(canvas, "remote image tainted pattern"); + + // Test reading after using a tainted pattern + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + var taintedCanvasPattern = context.createPattern(dirtyCanvas, "repeat"); + context.fillStyle = taintedCanvasPattern; + context.fillRect(0, 0, 100, 100); + + test(canvas, "CORS-untainted canvas pattern"); + + if (window.layoutTestController) + layoutTestController.notifyDone(); +} +image.crossOrigin = "anonymous"; +image.src = "http://localhost:8000/security/resources/abe-allow-star.php"; +</script> diff --git a/LayoutTests/http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin-expected.txt b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin-expected.txt new file mode 100644 index 0000000..aa3dde3 --- /dev/null +++ b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin-expected.txt @@ -0,0 +1,15 @@ +Untainted canvas: +PASS: Calling getImageData() from an untainted canvas was allowed. +PASS: Calling toDataURL() on an untainted canvas was allowed. + + +Tainted canvas: +PASS: Calling getImageData() from a canvas tainted by a remote image was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling toDataURL() on a canvas tainted by a remote image was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling getImageData() from a canvas tainted by a tained canvas was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling toDataURL() on a canvas tainted by a tained canvas was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling getImageData() from a canvas tainted by a remote image tainted pattern was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling toDataURL() on a canvas tainted by a remote image tainted pattern was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling getImageData() from a canvas tainted by a tainted canvas pattern was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling toDataURL() on a canvas tainted by a tainted canvas pattern was not allowed - Threw error: Error: SECURITY_ERR: DOM Exception 18. + diff --git a/LayoutTests/http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin.html b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin.html new file mode 100644 index 0000000..4815683 --- /dev/null +++ b/LayoutTests/http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin.html @@ -0,0 +1,108 @@ +<pre id="console"></pre> +<script> +if (window.layoutTestController) { + layoutTestController.dumpAsText(); + layoutTestController.waitUntilDone(); +} + +log = function(msg) +{ + document.getElementById('console').appendChild(document.createTextNode(msg + "\n")); +} + +testGetImageData = function(context, description) +{ + description = "Calling getImageData() from a canvas tainted by a " + description; + try { + var imageData = context.getImageData(0,0,100,100); + log("FAIL: " + description + " was allowed."); + } catch (e) { + log("PASS: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +testToDataURL = function(canvas, description) +{ + description = "Calling toDataURL() on a canvas tainted by a " + description; + try { + var dataURL = canvas.toDataURL(); + log("FAIL: " + description + " was allowed."); + } catch (e) { + log("PASS: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +test = function(canvas, description) +{ + testGetImageData(canvas.getContext("2d"), description); + testToDataURL(canvas, description); +} + +var image = new Image(); +image.onload = function() { + var canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + + // Control tests + log("Untainted canvas:"); + try { + var imageData = context.getImageData(0, 0, 100, 100); + log("PASS: Calling getImageData() from an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling getImageData() from an untainted canvas was not allowed: Threw error: " + e + "."); + } + try { + var dataURL = canvas.toDataURL(); + log("PASS: Calling toDataURL() on an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling toDataURL() on an untainted canvas was not allowed: Threw error: " + e + "."); + } + + log("\n"); + log("Tainted canvas:"); + // Test reading from a canvas after drawing a remote image onto it + context.drawImage(image, 0, 0, 100, 100); + + test(canvas, "remote image"); + + var dirtyCanvas = canvas; + + // Now test reading from a canvas after drawing a tainted canvas onto it + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + context.drawImage(dirtyCanvas, 0, 0, 100, 100); + + test(canvas, "tained canvas"); + + // Test reading after using a tainted pattern + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + var remoteImagePattern = context.createPattern(image, "repeat"); + context.fillStyle = remoteImagePattern; + context.fillRect(0, 0, 100, 100); + + test(canvas, "remote image tainted pattern"); + + // Test reading after using a tainted pattern + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var context = canvas.getContext("2d"); + var taintedCanvasPattern = context.createPattern(dirtyCanvas, "repeat"); + context.fillStyle = taintedCanvasPattern; + context.fillRect(0, 0, 100, 100); + + test(canvas, "tainted canvas pattern"); + + if (window.layoutTestController) + layoutTestController.notifyDone(); +} +// Notice that we forget to set the image.crossOrigin property! +image.src = "http://localhost:8000/security/resources/abe-allow-star.php"; +</script> diff --git a/LayoutTests/http/tests/security/resources/abe-allow-credentials.php b/LayoutTests/http/tests/security/resources/abe-allow-credentials.php new file mode 100644 index 0000000..2ca7408 --- /dev/null +++ b/LayoutTests/http/tests/security/resources/abe-allow-credentials.php @@ -0,0 +1,12 @@ +<?php +header("Access-Control-Allow-Origin: http://127.0.0.1:8000"); +header("Access-Control-Allow-Credentials: true"); + +$name = 'abe.png'; +$fp = fopen($name, 'rb'); +header("Content-Type: image/png"); +header("Content-Length: " . filesize($name)); + +fpassthru($fp); +exit; +?> diff --git a/LayoutTests/http/tests/security/resources/abe-allow-star.php b/LayoutTests/http/tests/security/resources/abe-allow-star.php new file mode 100644 index 0000000..d3d621d --- /dev/null +++ b/LayoutTests/http/tests/security/resources/abe-allow-star.php @@ -0,0 +1,11 @@ +<?php +header("Access-Control-Allow-Origin: *"); + +$name = 'abe.png'; +$fp = fopen($name, 'rb'); +header("Content-Type: image/png"); +header("Content-Length: " . filesize($name)); + +fpassthru($fp); +exit; +?> diff --git a/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-expected.txt b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-expected.txt new file mode 100644 index 0000000..c86861c --- /dev/null +++ b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-expected.txt @@ -0,0 +1,13 @@ +Untainted canvas: +PASS: Calling readPixels() from an untainted canvas was allowed. +PASS: Calling toDataURL() on an untainted canvas was allowed. + + +Tainted canvas: +PASS: Calling texImage2D() with an untainted image was allowed +PASS: Calling readPixels() from a canvas tainted by a remote image was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a remote image was allowed. +PASS: Calling texImage2D() with an untainted canvas was allowed +PASS: Calling readPixels() from a canvas tainted by a CORS-untained canvas was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a CORS-untained canvas was allowed. + diff --git a/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials-expected.txt b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials-expected.txt new file mode 100644 index 0000000..c86861c --- /dev/null +++ b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials-expected.txt @@ -0,0 +1,13 @@ +Untainted canvas: +PASS: Calling readPixels() from an untainted canvas was allowed. +PASS: Calling toDataURL() on an untainted canvas was allowed. + + +Tainted canvas: +PASS: Calling texImage2D() with an untainted image was allowed +PASS: Calling readPixels() from a canvas tainted by a remote image was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a remote image was allowed. +PASS: Calling texImage2D() with an untainted canvas was allowed +PASS: Calling readPixels() from a canvas tainted by a CORS-untained canvas was allowed. +PASS: Calling toDataURL() on a canvas CORS-untainted by a CORS-untained canvas was allowed. + diff --git a/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html new file mode 100644 index 0000000..c09e37b --- /dev/null +++ b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html @@ -0,0 +1,101 @@ +<pre id="console"></pre> +<script> +if (window.layoutTestController) { + layoutTestController.overridePreference("WebKitWebGLEnabled", "1"); + layoutTestController.dumpAsText(); + layoutTestController.waitUntilDone(); +} + +log = function(msg) +{ + document.getElementById('console').appendChild(document.createTextNode(msg + "\n")); +} + +testTexImage2D = function(gl, source, description) +{ + description = "Calling texImage2D() with an untainted " + description; + try { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source); + log("PASS: " + description + " was allowed"); + } catch (e) { + log("FAIL: " + description + " was not allowed: Threw error: " + e + "."); + } +} + +testReadPixels = function(gl, description) +{ + description = "Calling readPixels() from a canvas tainted by a " + description; + try { + var pixels = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +testToDataURL = function(canvas, description) +{ + description = "Calling toDataURL() on a canvas CORS-untainted by a " + description; + try { + var dataURL = canvas.toDataURL(); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +test = function(canvas, description) +{ + testReadPixels(canvas.getContext("experimental-webgl"), description); + testToDataURL(canvas, description); +} + +var image = new Image(); +image.onload = function() { + var canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var gl = canvas.getContext("experimental-webgl"); + + // Control tests + log("Untainted canvas:"); + try { + var pixels = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + log("PASS: Calling readPixels() from an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling readPixels() from an untainted canvas was not allowed: Threw error: " + e + "."); + } + try { + var dataURL = canvas.toDataURL(); + log("PASS: Calling toDataURL() on an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling toDataURL() on an untainted canvas was not allowed: Threw error: " + e + "."); + } + + log("\n"); + log("Tainted canvas:"); + // Test reading from a canvas after uploading a remote image as a texture + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + testTexImage2D(gl, image, "image"); + + test(canvas, "remote image"); + + // Now test reading from a canvas after uploading a tainted canvas onto it + var dirtyCanvas = document.createElement("canvas"); + dirtyCanvas.width = 100; + dirtyCanvas.height = 100; + var dirtyContext = dirtyCanvas.getContext("2d"); + dirtyContext.drawImage(image, 0, 0, 100, 100); + testTexImage2D(gl, dirtyCanvas, "canvas"); + + test(canvas, "CORS-untained canvas"); + + if (window.layoutTestController) + layoutTestController.notifyDone(); +} +image.crossOrigin = "use-credentials"; +image.src = "http://localhost:8000/security/resources/abe-allow-credentials.php"; +</script> diff --git a/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed.html b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed.html new file mode 100644 index 0000000..6448c2b --- /dev/null +++ b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-allowed.html @@ -0,0 +1,101 @@ +<pre id="console"></pre> +<script> +if (window.layoutTestController) { + layoutTestController.overridePreference("WebKitWebGLEnabled", "1"); + layoutTestController.dumpAsText(); + layoutTestController.waitUntilDone(); +} + +log = function(msg) +{ + document.getElementById('console').appendChild(document.createTextNode(msg + "\n")); +} + +testTexImage2D = function(gl, source, description) +{ + description = "Calling texImage2D() with an untainted " + description; + try { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source); + log("PASS: " + description + " was allowed"); + } catch (e) { + log("FAIL: " + description + " was not allowed: Threw error: " + e + "."); + } +} + +testReadPixels = function(gl, description) +{ + description = "Calling readPixels() from a canvas tainted by a " + description; + try { + var pixels = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +testToDataURL = function(canvas, description) +{ + description = "Calling toDataURL() on a canvas CORS-untainted by a " + description; + try { + var dataURL = canvas.toDataURL(); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +test = function(canvas, description) +{ + testReadPixels(canvas.getContext("experimental-webgl"), description); + testToDataURL(canvas, description); +} + +var image = new Image(); +image.onload = function() { + var canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var gl = canvas.getContext("experimental-webgl"); + + // Control tests + log("Untainted canvas:"); + try { + var pixels = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + log("PASS: Calling readPixels() from an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling readPixels() from an untainted canvas was not allowed: Threw error: " + e + "."); + } + try { + var dataURL = canvas.toDataURL(); + log("PASS: Calling toDataURL() on an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling toDataURL() on an untainted canvas was not allowed: Threw error: " + e + "."); + } + + log("\n"); + log("Tainted canvas:"); + // Test reading from a canvas after uploading a remote image as a texture + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + testTexImage2D(gl, image, "image"); + + test(canvas, "remote image"); + + // Now test reading from a canvas after uploading a tainted canvas onto it + var dirtyCanvas = document.createElement("canvas"); + dirtyCanvas.width = 100; + dirtyCanvas.height = 100; + var dirtyContext = dirtyCanvas.getContext("2d"); + dirtyContext.drawImage(image, 0, 0, 100, 100); + testTexImage2D(gl, dirtyCanvas, "canvas"); + + test(canvas, "CORS-untained canvas"); + + if (window.layoutTestController) + layoutTestController.notifyDone(); +} +image.crossOrigin = "anonymous"; +image.src = "http://localhost:8000/security/resources/abe-allow-star.php"; +</script> diff --git a/LayoutTests/http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin-expected.txt b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin-expected.txt new file mode 100644 index 0000000..ee74457 --- /dev/null +++ b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin-expected.txt @@ -0,0 +1,13 @@ +Untainted canvas: +PASS: Calling readPixels() from an untainted canvas was allowed. +PASS: Calling toDataURL() on an untainted canvas was allowed. + + +Tainted canvas: +PASS: Calling texImage2D() with a tainted image was not allowed: Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling readPixels() on a canvas where tainting was attempted by a remote image was allowed. +PASS: Calling toDataURL() on a canvas where tainting was attempted by a remote image was allowed. +PASS: Calling texImage2D() with a tainted canvas was not allowed: Threw error: Error: SECURITY_ERR: DOM Exception 18. +PASS: Calling readPixels() on a canvas where tainting was attempted by a tainted canvas was allowed. +PASS: Calling toDataURL() on a canvas where tainting was attempted by a tainted canvas was allowed. + diff --git a/LayoutTests/http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html new file mode 100644 index 0000000..f870c3e --- /dev/null +++ b/LayoutTests/http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html @@ -0,0 +1,103 @@ +<pre id="console"></pre> +<script> +if (window.layoutTestController) { + layoutTestController.overridePreference("WebKitWebGLEnabled", "1"); + layoutTestController.dumpAsText(); + layoutTestController.waitUntilDone(); +} + +log = function(msg) +{ + document.getElementById('console').appendChild(document.createTextNode(msg + "\n")); +} + +testTexImage2D = function(gl, source, description) +{ + description = "Calling texImage2D() with a tainted " + description; + try { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source); + log("FAIL: " + description + " was allowed"); + } catch (e) { + log("PASS: " + description + " was not allowed: Threw error: " + e + "."); + } +} + +testReadPixels = function(gl, description) +{ + description = "Calling readPixels() on a canvas where tainting was attempted by a " + description; + try { + var pixels = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +testToDataURL = function(canvas, description) +{ + description = "Calling toDataURL() on a canvas where tainting was attempted by a " + description; + try { + var dataURL = canvas.toDataURL(); + log("PASS: " + description + " was allowed."); + } catch (e) { + log("FAIL: " + description + " was not allowed - Threw error: " + e + "."); + } +} + +test = function(canvas, description) +{ + testReadPixels(canvas.getContext("experimental-webgl"), description); + testToDataURL(canvas, description); +} + +var image = new Image(); +image.onload = function() { + var canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + var gl = canvas.getContext("experimental-webgl"); + + // Control tests + log("Untainted canvas:"); + try { + var pixels = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + log("PASS: Calling readPixels() from an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling readPixels() from an untainted canvas was not allowed: Threw error: " + e + "."); + } + try { + var dataURL = canvas.toDataURL(); + log("PASS: Calling toDataURL() on an untainted canvas was allowed."); + } catch (e) { + log("FAIL: Calling toDataURL() on an untainted canvas was not allowed: Threw error: " + e + "."); + } + + log("\n"); + log("Tainted canvas:"); + // Test reading from a canvas after uploading a remote image as a texture + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + testTexImage2D(gl, image, "image"); + + test(canvas, "remote image"); + + var dirtyCanvas = canvas; + + // Now test reading from a canvas after drawing a tainted canvas onto it + var dirtyCanvas = document.createElement("canvas"); + dirtyCanvas.width = 100; + dirtyCanvas.height = 100; + var dirtyContext = dirtyCanvas.getContext("2d"); + dirtyContext.drawImage(image, 0, 0, 100, 100); + testTexImage2D(gl, dirtyCanvas, "canvas"); + + test(canvas, "tainted canvas"); + + if (window.layoutTestController) + layoutTestController.notifyDone(); +} +// Notice that we forget to set the image.crossOrigin property! +image.src = "http://localhost:8000/security/resources/abe-allow-star.php"; +</script> |