diff --git a/.eslintrc.json b/.eslintrc.json index 5606883..6d48e6b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -32,7 +32,7 @@ "consistent-return": "error", "constructor-super": "warn", "eqeqeq": "error", - "eslint-comments/no-use": ["error", {"allow": ["eslint-disable-next-line"]}], + "eslint-comments/no-use": ["error", {"allow": ["eslint-disable-next-line", "globals"]}], "indent": ["error", "tab", {"SwitchCase": 1}], "max-depth": ["warn", 4], "max-len": ["warn", {"code": 120, "tabWidth": 4}], diff --git a/test/canvasAPI.js b/test/canvasAPI.js new file mode 100644 index 0000000..0979518 --- /dev/null +++ b/test/canvasAPI.js @@ -0,0 +1,79 @@ +const canvasAPI = { + draw: function draw(canvas){ + "use strict"; + + canvas.setAttribute("width", 220); + canvas.setAttribute("height", 30); + + const fingerprintText = "BrowserLeaks,com 10"; + + const context = canvas.getContext("2d"); + context.textBaseline = "top"; + context.font = "14px 'Arial'"; + context.textBaseline = "alphabetic"; + context.fillStyle = "#f60"; + context.fillRect(125, 1, 62, 20); + context.fillStyle = "#069"; + context.fillText(fingerprintText, 2, 15); + context.fillStyle = "rgba(102, 204, 0, 07)"; + context.fillText(fingerprintText, 4, 17); + + return context; + }, + getIsPointInPath: function getIsPointInPath(context){ + "use strict"; + + context.beginPath(); + context.moveTo(20, 19); + context.lineTo(40, 19); + context.lineTo(30, 30); + context.closePath(); + context.stroke(); + + return context.isPointInPath(30, 19); + }, + getFingerprintData: function getFingerprintData(canvas, context){ + "use strict"; + + return { + imageData: context.getImageData(0, 0, canvas.width, canvas.height), + url: canvas.toDataURL(), + isPointInPath: canvasAPI.getIsPointInPath(context) + }; + }, + getFingerprintFromDifferentDocument: function getFingerprintFromDifferentDocument(otherDocument){ + "use strict"; + + // create window canvas + const canvas = document.createElement("canvas"); + + // draw image in window canvas + canvasAPI.draw(canvas); + + // create other canvas and context + const otherCanvas = otherDocument.createElement("canvas"); + otherCanvas.setAttribute("width", 220); + otherCanvas.setAttribute("height", 30); + const otherContext = otherCanvas.getContext("2d"); + + // copy image from window canvas to iframe context + otherContext.drawImage(canvas, 0, 0); + + return canvasAPI.getFingerprintData(otherCanvas, otherContext); + }, + fingerprint: function fingerprint(windowToUse){ + "use strict"; + if (!windowToUse){ + windowToUse = window; + } + + const canvas = document.createElement("canvas"); + const context = canvasAPI.draw(canvas); + if (windowToUse !== window){ + return canvasAPI.getFingerprintFromDifferentDocument(windowToUse.document); + } + else { + return this.getFingerprintData(canvas, context); + } + } +}; \ No newline at end of file diff --git a/test/cspTest.js b/test/cspTest.js index b4b3983..a12ef65 100644 --- a/test/cspTest.js +++ b/test/cspTest.js @@ -1,48 +1,4 @@ - -function draw(canvas){ - "use strict"; - - canvas.setAttribute("width", 220); - canvas.setAttribute("height", 30); - - const fp_text = "BrowserLeaks,com 10"; - - const ctx = canvas.getContext("2d"); - ctx.textBaseline = "top"; - ctx.font = "14px 'Arial'"; - ctx.textBaseline = "alphabetic"; - ctx.fillStyle = "#f60"; - ctx.fillRect(125, 1, 62, 20); - ctx.fillStyle = "#069"; - ctx.fillText(fp_text, 2, 15); - ctx.fillStyle = "rgba(102, 204, 0, 07)"; - ctx.fillText(fp_text, 4, 17); - - return ctx; -} -function test(window){ - "use strict"; - - // create window canvas - const canvas = document.createElement("canvas"); - // draw image in window canvas - draw(canvas); - return window.HTMLCanvasElement.prototype.toDataURL.call(canvas); -} -async function hash(string){ - "use strict"; - - const buffer = new TextEncoder("utf-8").encode(string); - const hash = await crypto.subtle.digest("SHA-256", buffer); - const chunks = []; - (new Uint32Array(hash)).forEach(function(num){ - chunks.push(num.toString(16)); - }); - return chunks.map(function(chunk){ - return "0".repeat(8 - chunk.length) + chunk; - }).join(""); -} - +/* globals testAPI, canvasAPI*/ const addLine = function(){ "use strict"; @@ -60,6 +16,6 @@ addLine("window name after set: " + window.name); (async function(){ "use strict"; - const hashValue = await hash(test(window)); + const hashValue = await testAPI.hash(canvasAPI.fingerprint(window).url); addLine("canvas hash: " + hashValue); }()); \ No newline at end of file diff --git a/test/cspTest.php b/test/cspTest.php index f4244e4..f7f84f6 100644 --- a/test/cspTest.php +++ b/test/cspTest.php @@ -20,6 +20,8 @@ header("Content-Security-Policy: default-src 'none'; img-src 'self'; script-src

Tests

+ + \ No newline at end of file diff --git a/test/performanceTest.html b/test/performanceTest.html index cbb4a26..10e864a 100644 --- a/test/performanceTest.html +++ b/test/performanceTest.html @@ -11,5 +11,6 @@ Tests the performance of some operations that are affected by CanvasBlocker.
+ \ No newline at end of file diff --git a/test/performanceTest.js b/test/performanceTest.js index a23a452..6e12781 100644 --- a/test/performanceTest.js +++ b/test/performanceTest.js @@ -1,4 +1,4 @@ - +/* globals canvasAPI */ const createLog = function(){ "use strict"; @@ -85,28 +85,6 @@ const performTest = function(){ }; }(); -function draw(canvas){ - "use strict"; - - canvas.setAttribute("width", 220); - canvas.setAttribute("height", 30); - - const fp_text = "BrowserLeaks,com 10"; - - const ctx = canvas.getContext("2d"); - ctx.textBaseline = "top"; - ctx.font = "14px 'Arial'"; - ctx.textBaseline = "alphabetic"; - ctx.fillStyle = "#f60"; - ctx.fillRect(125, 1, 62, 20); - ctx.fillStyle = "#069"; - ctx.fillText(fp_text, 2, 15); - ctx.fillStyle = "rgba(102, 204, 0, 07)"; - ctx.fillText(fp_text, 4, 17); - - return ctx; -} - const fingerprintTest = function(){ "use strict"; @@ -116,7 +94,7 @@ const fingerprintTest = function(){ // create window canvas canvas = document.createElement("canvas"); // draw image in window canvas - draw(canvas); + canvasAPI.draw(canvas); }, test: function fingerprintTest(){ return canvas.toDataURL(); diff --git a/test/settingsLoading.php b/test/settingsLoading.php index a8eb380..e473aba 100644 --- a/test/settingsLoading.php +++ b/test/settingsLoading.php @@ -5,45 +5,16 @@ + " . file_get_contents("testAPI.js"); + echo file_get_contents("canvasAPI.js") . ""; + ?> + \ No newline at end of file diff --git a/test/test.js b/test/test.js index ec2a434..91aba09 100644 --- a/test/test.js +++ b/test/test.js @@ -1,165 +1,72 @@ +/* globals testAPI, canvasAPI */ (function(){ "use strict"; - function hashToString(hash){ - const chunks = []; - (new Uint32Array(hash)).forEach(function(num){ - chunks.push(num.toString(16)); - }); - return chunks.map(function(chunk){ - return "0".repeat(8 - chunk.length) + chunk; - }).join(""); - } - async function show(container, {url, imageData, isPointInPath}){ const display = container.querySelector(".display"); display.src = url; display.title = url; - const buffer = new TextEncoder("utf-8").encode(url); const hashes = await Promise.all([ - crypto.subtle.digest("SHA-256", buffer), - crypto.subtle.digest("SHA-256", imageData.data) + testAPI.hash(url), + testAPI.hash(imageData.data) ]); container.querySelector(".hash").textContent = - hashToString(hashes[0]) + " / " + - hashToString(hashes[1]); + hashes[0] + " / " + + hashes[1]; container.querySelector(".isPointInPath").textContent = isPointInPath; } - if (location.search !== "?notInitial"){ - try {show(document.getElementById("top"), topTest());} - catch (error){console.error(error);} - try {show(document.getElementById("iframe"), iframeTest(document.querySelector("#iframe iframe")));} - catch (error){console.error(error);} - try {show(document.getElementById("iframe2"), iframeTest(document.querySelector("#iframe2 iframe")));} - catch (error){console.error(error);} - try {show(document.getElementById("iframe3"), iframeTest(document.querySelector("#iframe3 iframe")));} - catch (error){console.error(error);} - try {show(document.getElementById("iframe4"), dynamicIframeTest1());} - catch (error){console.error(error);} - try {show(document.getElementById("iframe5"), dynamicIframeTest2());} - catch (error){console.error(error);} - try {show(document.getElementById("iframe6"), dynamicIframeTest3());} - catch (error){console.error(error);} - window.addEventListener("click", function windowOpenTest(){ - window.removeEventListener("click", windowOpenTest); - const newWindow = window.open("/"); - try{ - show(document.getElementById("windowOpen"), copyToDifferentDocumentTest(newWindow.document)); - } - catch (error){ - console.error(error); - } - newWindow.close(); - }); + function iframeTest(testNode){ + const iframe = testNode.querySelector("iframe"); + return canvasAPI.fingerprint(iframe.contentWindow); } - document.querySelector("#top button").addEventListener("click", function(){ - show(document.getElementById("top"), topTest()); - }); - document.querySelector("#iframe button").addEventListener("click", function(){ - show(document.getElementById("iframe"), iframeTest(document.querySelector("#iframe iframe"))); - }); - document.querySelector("#iframe2 button").addEventListener("click", function(){ - show(document.getElementById("iframe2"), iframeTest(document.querySelector("#iframe2 iframe"))); - }); - document.querySelector("#iframe3 button").addEventListener("click", function(){ - show(document.getElementById("iframe3"), iframeTest(document.querySelector("#iframe3 iframe"))); - }); - document.querySelector("#iframe4 button").addEventListener("click", function(){ - show(document.getElementById("iframe4"), dynamicIframeTest1()); - }); - document.querySelector("#iframe5 button").addEventListener("click", function(){ - show(document.getElementById("iframe5"), dynamicIframeTest2()); - }); - document.querySelector("#iframe6 button").addEventListener("click", function(){ - show(document.getElementById("iframe6"), dynamicIframeTest3()); - }); - document.querySelector("#windowOpen button").addEventListener("click", function(){ - const newWindow = window.open("/"); - show(document.getElementById("windowOpen"), copyToDifferentDocumentTest(newWindow.document)); - newWindow.close(); + + const tests = { + top: function(){return canvasAPI.fingerprint();}, + iframe: iframeTest, + iframe2: iframeTest, + iframe3: iframeTest, + iframe4: dynamicIframeTest1, + iframe5: dynamicIframeTest2, + iframe6: dynamicIframeTest3, + windowOpen: async function(testNode, initial){ + if (initial){ + return new Promise(function(resolve){ + window.addEventListener("click", function windowOpenTest(){ + window.removeEventListener("click", windowOpenTest); + const newWindow = window.open("/"); + try{ + resolve(canvasAPI.fingerprint(newWindow)); + } + catch (error){ + console.error(error); + } + newWindow.close(); + }); + }); + } + else { + const newWindow = window.open("/"); + const fingerprint = canvasAPI.fingerprint(newWindow); + newWindow.close(); + return fingerprint; + } + } + }; + + Object.keys(tests).forEach(async function(testName){ + const testNode = document.getElementById(testName); + const callback = tests[testName]; + if (location.search !== "?notInitial"){ + try {show(testNode, await callback(testNode, true));} + catch (error){console.error(testName, error);} + } + testNode.querySelector("button").addEventListener("click", async function(){ + show(testNode, await callback(testNode)); + }); }); }()); -function draw(canvas){ - "use strict"; - - canvas.setAttribute("width", 220); - canvas.setAttribute("height", 30); - - const fp_text = "BrowserLeaks,com 10"; - - const ctx = canvas.getContext("2d"); - ctx.textBaseline = "top"; - ctx.font = "14px 'Arial'"; - ctx.textBaseline = "alphabetic"; - ctx.fillStyle = "#f60"; - ctx.fillRect(125, 1, 62, 20); - ctx.fillStyle = "#069"; - ctx.fillText(fp_text, 2, 15); - ctx.fillStyle = "rgba(102, 204, 0, 07)"; - ctx.fillText(fp_text, 4, 17); - - return ctx; -} - -function getIsPointInPath(ctx){ - "use strict"; - ctx.beginPath(); - ctx.moveTo(20, 19); - ctx.lineTo(40, 19); - ctx.lineTo(30, 30); - ctx.closePath(); - ctx.stroke(); - - return ctx.isPointInPath(30, 19); -} - -function topTest(){ - "use strict"; - - // create window canvas - const canvas = document.createElement("canvas"); - // draw image in window canvas - const ctx = draw(canvas); - return { - imageData: ctx.getImageData(0, 0, canvas.width, canvas.height), - url: canvas.toDataURL(), - isPointInPath: getIsPointInPath(ctx) - }; -} - -function copyToDifferentDocumentTest(otherDocument){ - "use strict"; - - // create window canvas - const canvas = document.createElement("canvas"); - - // draw image in window canvas - draw(canvas); - - // create other canvas and context - const otherCanvas = otherDocument.createElement("canvas"); - otherCanvas.setAttribute("width", 220); - otherCanvas.setAttribute("height", 30); - const otherContext = otherCanvas.getContext("2d"); - - // copy image from window canvas to iframe context - otherContext.drawImage(canvas, 0, 0); - - return { - imageData: otherContext.getImageData(0, 0, otherCanvas.width, otherCanvas.height), - url: otherCanvas.toDataURL(), - isPointInPath: getIsPointInPath(otherContext) - }; -} - -function iframeTest(iframe){ - "use strict"; - - return copyToDifferentDocumentTest(iframe.contentDocument); -} - function dynamicIframeTest1(){ "use strict"; @@ -168,7 +75,7 @@ function dynamicIframeTest1(){ document.body.appendChild(iframe); const iframeWindow = frames[length]; document.body.removeChild(iframe); - return copyToDifferentDocumentTest(iframeWindow.document); + return canvasAPI.fingerprint(iframeWindow); } function dynamicIframeTest2(){ @@ -179,7 +86,7 @@ function dynamicIframeTest2(){ document.body.appendChild(iframe); const iframeWindow = window[length]; document.body.removeChild(iframe); - return copyToDifferentDocumentTest(iframeWindow.document); + return canvasAPI.fingerprint(iframeWindow); } function dynamicIframeTest3(){ @@ -191,5 +98,5 @@ function dynamicIframeTest3(){ div.innerHTML = ""; const iframeWindow = window[length]; document.body.removeChild(div); - return copyToDifferentDocumentTest(iframeWindow.document); + return canvasAPI.fingerprint(iframeWindow); } \ No newline at end of file diff --git a/test/testAPI.js b/test/testAPI.js new file mode 100644 index 0000000..e655c32 --- /dev/null +++ b/test/testAPI.js @@ -0,0 +1,25 @@ +const testAPI = function(){ + "use strict"; + + function bufferToString(hash){ + const chunks = []; + (new Uint32Array(hash)).forEach(function(num){ + chunks.push(num.toString(16)); + }); + return chunks.map(function(chunk){ + return "0".repeat(8 - chunk.length) + chunk; + }).join(""); + } + + + + return { + hash: async function(input){ + const buffer = ((typeof input) === "string")? + new TextEncoder("utf-8").encode(input): + input; + const hash = await crypto.subtle.digest("SHA-256", buffer); + return bufferToString(hash); + } + }; +}(); \ No newline at end of file