mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2025-03-13 11:44:12 +01:00
test updates
This commit is contained in:
parent
717e1d3e3a
commit
0d0e3e30ec
@ -53,6 +53,7 @@
|
|||||||
"no-useless-rename": "warn",
|
"no-useless-rename": "warn",
|
||||||
"no-var": "error",
|
"no-var": "error",
|
||||||
"quotes": ["error", "double"],
|
"quotes": ["error", "double"],
|
||||||
|
"require-atomic-updates": "off",
|
||||||
"semi": ["error", "always"],
|
"semi": ["error", "always"],
|
||||||
"space-in-parens": ["error", "never"],
|
"space-in-parens": ["error", "never"],
|
||||||
"strict": ["error", "function"],
|
"strict": ["error", "function"],
|
||||||
@ -68,7 +69,6 @@
|
|||||||
{
|
{
|
||||||
"files": ["test/*"],
|
"files": ["test/*"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-var": "off",
|
|
||||||
"no-console": "off"
|
"no-console": "off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function byteArrayToHex(arrayBuffer){
|
function byteArrayToHex(arrayBuffer){
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(arrayBuffer)).forEach(function(num){
|
(new Uint32Array(arrayBuffer)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
});
|
||||||
@ -11,17 +11,17 @@
|
|||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
var container = document.getElementById("test");
|
const container = document.getElementById("test");
|
||||||
var hashContainer = container.querySelector(".hashes");
|
const hashContainer = container.querySelector(".hashes");
|
||||||
var hashSets = Object.create(null);
|
let hashSets = Object.create(null);
|
||||||
|
|
||||||
function createSet(set){
|
function createSet(set){
|
||||||
if (!hashSets[set]){
|
if (!hashSets[set]){
|
||||||
var setContainer = document.createElement("tbody");
|
const setContainer = document.createElement("tbody");
|
||||||
hashContainer.appendChild(setContainer);
|
hashContainer.appendChild(setContainer);
|
||||||
var nameRow = document.createElement("tr");
|
const nameRow = document.createElement("tr");
|
||||||
setContainer.appendChild(nameRow);
|
setContainer.appendChild(nameRow);
|
||||||
var nameContainer = document.createElement("th");
|
const nameContainer = document.createElement("th");
|
||||||
nameRow.appendChild(nameContainer);
|
nameRow.appendChild(nameContainer);
|
||||||
nameContainer.colSpan = 2;
|
nameContainer.colSpan = 2;
|
||||||
nameContainer.textContent = set;
|
nameContainer.textContent = set;
|
||||||
@ -29,37 +29,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayData(data, set, title){
|
async function displayData(data, set, title){
|
||||||
createSet(set);
|
createSet(set);
|
||||||
var container = document.createElement("tr");
|
const container = document.createElement("tr");
|
||||||
|
|
||||||
var titleNode = document.createElement("td");
|
const titleNode = document.createElement("td");
|
||||||
titleNode.textContent = title;
|
titleNode.textContent = title;
|
||||||
container.appendChild(titleNode);
|
container.appendChild(titleNode);
|
||||||
|
|
||||||
var hashNode = document.createElement("td");
|
const hashNode = document.createElement("td");
|
||||||
hashNode.textContent = "calculating hash";
|
hashNode.textContent = "calculating hash";
|
||||||
container.appendChild(hashNode);
|
container.appendChild(hashNode);
|
||||||
|
|
||||||
crypto.subtle.digest("SHA-256", data).then(function(hash){
|
|
||||||
hashNode.textContent = byteArrayToHex(hash);
|
|
||||||
return;
|
|
||||||
}).catch(function(error){
|
|
||||||
hashNode.textContent = error;
|
|
||||||
});
|
|
||||||
hashSets[set].appendChild(container);
|
hashSets[set].appendChild(container);
|
||||||
|
|
||||||
|
const hash = await crypto.subtle.digest("SHA-256", data);
|
||||||
|
hashNode.textContent = byteArrayToHex(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAudioContext(frequency = 1e4){
|
function getAudioContext(frequency = 1e4){
|
||||||
var context = new window.OfflineAudioContext(2, 44100, 44100);
|
const context = new window.OfflineAudioContext(2, 44100, 44100);
|
||||||
|
|
||||||
// Create oscillator
|
// Create oscillator
|
||||||
var pxi_oscillator = context.createOscillator();
|
const pxi_oscillator = context.createOscillator();
|
||||||
pxi_oscillator.type = "triangle";
|
pxi_oscillator.type = "triangle";
|
||||||
pxi_oscillator.frequency.value = frequency;
|
pxi_oscillator.frequency.value = frequency;
|
||||||
|
|
||||||
// Create and configure compressor
|
// Create and configure compressor
|
||||||
var pxi_compressor = context.createDynamicsCompressor();
|
const pxi_compressor = context.createDynamicsCompressor();
|
||||||
pxi_compressor.threshold && (pxi_compressor.threshold.value = -50);
|
pxi_compressor.threshold && (pxi_compressor.threshold.value = -50);
|
||||||
pxi_compressor.knee && (pxi_compressor.knee.value = 40);
|
pxi_compressor.knee && (pxi_compressor.knee.value = 40);
|
||||||
pxi_compressor.ratio && (pxi_compressor.ratio.value = 12);
|
pxi_compressor.ratio && (pxi_compressor.ratio.value = 12);
|
||||||
@ -77,28 +74,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createEmptyData(){
|
function createEmptyData(){
|
||||||
var emptyArray = new Float32Array(44100);
|
const emptyArray = new Float32Array(44100);
|
||||||
displayData(emptyArray, "empty buffer", "no API involved");
|
displayData(emptyArray, "empty buffer", "no API involved");
|
||||||
|
|
||||||
var emptyContext = new OfflineAudioContext(1, 44100, 44100);
|
const emptyContext = new OfflineAudioContext(1, 44100, 44100);
|
||||||
var emptyBuffer = emptyContext.createBuffer(1, 44100, 44100);
|
const emptyBuffer = emptyContext.createBuffer(1, 44100, 44100);
|
||||||
|
|
||||||
var emptyCopy = new Float32Array(44100);
|
const emptyCopy = new Float32Array(44100);
|
||||||
emptyBuffer.copyFromChannel(emptyCopy, 0);
|
emptyBuffer.copyFromChannel(emptyCopy, 0);
|
||||||
displayData(emptyCopy, "empty buffer", "copyFromChannel - first");
|
displayData(emptyCopy, "empty buffer", "copyFromChannel - first");
|
||||||
|
|
||||||
var emptyData = emptyBuffer.getChannelData(0);
|
const emptyData = emptyBuffer.getChannelData(0);
|
||||||
displayData(emptyData, "empty buffer", "getChannelData - first");
|
displayData(emptyData, "empty buffer", "getChannelData - first");
|
||||||
displayData(emptyBuffer.getChannelData(0), "empty buffer", "getChannelData - second");
|
displayData(emptyBuffer.getChannelData(0), "empty buffer", "getChannelData - second");
|
||||||
|
|
||||||
var emptyCopy2 = new Float32Array(44100);
|
const emptyCopy2 = new Float32Array(44100);
|
||||||
emptyBuffer.copyFromChannel(emptyCopy2, 0);
|
emptyBuffer.copyFromChannel(emptyCopy2, 0);
|
||||||
displayData(emptyCopy2, "empty buffer", "copyFromChannel - second");
|
displayData(emptyCopy2, "empty buffer", "copyFromChannel - second");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIframeWindow(){
|
function getIframeWindow(){
|
||||||
var l = window.length;
|
const l = window.length;
|
||||||
var iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
const iframeWindow = window[l];
|
const iframeWindow = window[l];
|
||||||
document.body.removeChild(iframe);
|
document.body.removeChild(iframe);
|
||||||
@ -107,43 +104,43 @@
|
|||||||
|
|
||||||
function createHashData(frequency = 1e4){
|
function createHashData(frequency = 1e4){
|
||||||
|
|
||||||
var context = getAudioContext(frequency);
|
const context = getAudioContext(frequency);
|
||||||
|
|
||||||
var setName = " (" + frequency + " Hz)";
|
const setName = " (" + frequency + " Hz)";
|
||||||
createSet(setName);
|
createSet(setName);
|
||||||
|
|
||||||
// Start audio processing
|
// Start audio processing
|
||||||
context.startRendering();
|
context.startRendering();
|
||||||
context.oncomplete = function(event){
|
context.oncomplete = function(event){
|
||||||
var copyTestIframe = new (getIframeWindow().Float32Array)(44100);
|
const copyTestIframe = new (getIframeWindow().Float32Array)(44100);
|
||||||
getIframeWindow().AudioBuffer.prototype.copyFromChannel.call(event.renderedBuffer, copyTestIframe, 0);
|
getIframeWindow().AudioBuffer.prototype.copyFromChannel.call(event.renderedBuffer, copyTestIframe, 0);
|
||||||
displayData(copyTestIframe, setName, "copyFromChannel - iframe");
|
displayData(copyTestIframe, setName, "copyFromChannel - iframe");
|
||||||
|
|
||||||
var chunkTest = new Float32Array(44100);
|
const chunkTest = new Float32Array(44100);
|
||||||
var number = new Float32Array(100);
|
const number = new Float32Array(100);
|
||||||
for (var chunkI = 0; chunkI < 44100; chunkI += number.length){
|
for (let chunkI = 0; chunkI < 44100; chunkI += number.length){
|
||||||
event.renderedBuffer.copyFromChannel(number, 0, chunkI);
|
event.renderedBuffer.copyFromChannel(number, 0, chunkI);
|
||||||
chunkTest.set(number, chunkI);
|
chunkTest.set(number, chunkI);
|
||||||
}
|
}
|
||||||
displayData(chunkTest, setName, "copyFromChannel - chunks");
|
displayData(chunkTest, setName, "copyFromChannel - chunks");
|
||||||
|
|
||||||
var copyTest = new Float32Array(44100);
|
const copyTest = new Float32Array(44100);
|
||||||
event.renderedBuffer.copyFromChannel(copyTest, 0);
|
event.renderedBuffer.copyFromChannel(copyTest, 0);
|
||||||
displayData(copyTest, setName, "copyFromChannel - first");
|
displayData(copyTest, setName, "copyFromChannel - first");
|
||||||
|
|
||||||
|
|
||||||
var getTest = event.renderedBuffer.getChannelData(0);
|
const getTest = event.renderedBuffer.getChannelData(0);
|
||||||
displayData(getTest, setName, "getChannelData - first");
|
displayData(getTest, setName, "getChannelData - first");
|
||||||
displayData(event.renderedBuffer.getChannelData(0), setName, "getChannelData - second readout");
|
displayData(event.renderedBuffer.getChannelData(0), setName, "getChannelData - second readout");
|
||||||
displayData(event.renderedBuffer.getChannelData(1), setName, "getChannelData - second channel");
|
displayData(event.renderedBuffer.getChannelData(1), setName, "getChannelData - second channel");
|
||||||
|
|
||||||
var copyTest2 = new Float32Array(44100);
|
const copyTest2 = new Float32Array(44100);
|
||||||
event.renderedBuffer.copyFromChannel(copyTest2, 0);
|
event.renderedBuffer.copyFromChannel(copyTest2, 0);
|
||||||
displayData(copyTest2, setName, "copyFromChannel - second");
|
displayData(copyTest2, setName, "copyFromChannel - second");
|
||||||
|
|
||||||
if (frequency === 1e4){
|
if (frequency === 1e4){
|
||||||
var sum = 0;
|
let sum = 0;
|
||||||
for (var i = 4500; i < 5000; i += 1) {
|
for (let i = 4500; i < 5000; i += 1) {
|
||||||
sum += Math.abs(getTest[i]);
|
sum += Math.abs(getTest[i]);
|
||||||
}
|
}
|
||||||
container.querySelector(".sum").textContent = sum;
|
container.querySelector(".sum").textContent = sum;
|
||||||
|
@ -5,9 +5,9 @@ function draw(canvas){
|
|||||||
canvas.setAttribute("width", 220);
|
canvas.setAttribute("width", 220);
|
||||||
canvas.setAttribute("height", 30);
|
canvas.setAttribute("height", 30);
|
||||||
|
|
||||||
var fp_text = "BrowserLeaks,com <canvas> 10";
|
const fp_text = "BrowserLeaks,com <canvas> 10";
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.font = "14px 'Arial'";
|
ctx.font = "14px 'Arial'";
|
||||||
ctx.textBaseline = "alphabetic";
|
ctx.textBaseline = "alphabetic";
|
||||||
@ -24,33 +24,31 @@ function test(window){
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// create window canvas
|
// create window canvas
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
// draw image in window canvas
|
// draw image in window canvas
|
||||||
draw(canvas);
|
draw(canvas);
|
||||||
return window.HTMLCanvasElement.prototype.toDataURL.call(canvas);
|
return window.HTMLCanvasElement.prototype.toDataURL.call(canvas);
|
||||||
}
|
}
|
||||||
function hash(string){
|
async function hash(string){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var buffer = new TextEncoder("utf-8").encode(string);
|
const buffer = new TextEncoder("utf-8").encode(string);
|
||||||
return crypto.subtle.digest("SHA-256", buffer).then(function(hash){
|
const hash = await crypto.subtle.digest("SHA-256", buffer);
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(hash)).forEach(function(num){
|
(new Uint32Array(hash)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
|
||||||
return chunks.map(function(chunk){
|
|
||||||
return "0".repeat(8 - chunk.length) + chunk;
|
|
||||||
}).join("");
|
|
||||||
});
|
});
|
||||||
|
return chunks.map(function(chunk){
|
||||||
|
return "0".repeat(8 - chunk.length) + chunk;
|
||||||
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
var addLine = function(){
|
const addLine = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var output = document.getElementById("results");
|
const output = document.getElementById("results");
|
||||||
return function(text){
|
return function(text){
|
||||||
var line = document.createElement("div");
|
const line = document.createElement("div");
|
||||||
line.textContent = text;
|
line.textContent = text;
|
||||||
output.appendChild(line);
|
output.appendChild(line);
|
||||||
};
|
};
|
||||||
@ -59,13 +57,9 @@ var addLine = function(){
|
|||||||
addLine("window name at start: " + window.name);
|
addLine("window name at start: " + window.name);
|
||||||
window.name = "CanvasBlocker CSP test";
|
window.name = "CanvasBlocker CSP test";
|
||||||
addLine("window name after set: " + window.name);
|
addLine("window name after set: " + window.name);
|
||||||
hash(test(window)).then(function(hash){
|
(async function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
addLine("canvas hash: " + hash);
|
const hashValue = await hash(test(window));
|
||||||
return;
|
addLine("canvas hash: " + hashValue);
|
||||||
}).catch(function(error){
|
}());
|
||||||
"use strict";
|
|
||||||
|
|
||||||
addLine("error while creating canvas hash: " + error);
|
|
||||||
});
|
|
@ -1,13 +1,13 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var iframeCode = atob(
|
const iframeCode = atob(
|
||||||
document.getElementById("iframe").src.replace(/^.+base64,/, "")
|
document.getElementById("iframe").src.replace(/^.+base64,/, "")
|
||||||
);
|
);
|
||||||
|
|
||||||
document.getElementById("code").textContent = iframeCode;
|
document.getElementById("code").textContent = iframeCode;
|
||||||
|
|
||||||
var blob = new Blob([iframeCode], {type: "text/html"});
|
const blob = new Blob([iframeCode], {type: "text/html"});
|
||||||
var newurl = window.URL.createObjectURL(blob);
|
const newurl = window.URL.createObjectURL(blob);
|
||||||
document.getElementById("blobIframe").src = newurl;
|
document.getElementById("blobIframe").src = newurl;
|
||||||
}());
|
}());
|
@ -82,9 +82,9 @@
|
|||||||
canvas.setAttribute("width", 220);
|
canvas.setAttribute("width", 220);
|
||||||
canvas.setAttribute("height", 30);
|
canvas.setAttribute("height", 30);
|
||||||
|
|
||||||
var fp_text = "BrowserLeaks,com <canvas> 10";
|
const fp_text = "BrowserLeaks,com <canvas> 10";
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.font = "14px 'Arial'";
|
ctx.font = "14px 'Arial'";
|
||||||
ctx.textBaseline = "alphabetic";
|
ctx.textBaseline = "alphabetic";
|
||||||
@ -101,9 +101,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// create window canvas
|
// create window canvas
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
// draw image in window canvas
|
// draw image in window canvas
|
||||||
var ctx = draw(canvas);
|
const ctx = draw(canvas);
|
||||||
return {
|
return {
|
||||||
imageData: ctx.getImageData(0, 0, canvas.width, canvas.height),
|
imageData: ctx.getImageData(0, 0, canvas.width, canvas.height),
|
||||||
url: canvas.toDataURL(),
|
url: canvas.toDataURL(),
|
||||||
@ -125,7 +125,7 @@
|
|||||||
function hashToString(hash){
|
function hashToString(hash){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(hash)).forEach(function(num){
|
(new Uint32Array(hash)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
});
|
||||||
@ -134,38 +134,34 @@
|
|||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
var send = function(){
|
const send = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
return function send(form, {url, imageData, isPointInPath}){
|
return async function send(form, {url, imageData, isPointInPath}){
|
||||||
var buffer = new TextEncoder("utf-8").encode(url);
|
const buffer = new TextEncoder("utf-8").encode(url);
|
||||||
Promise.all([
|
const hashes = await Promise.all([
|
||||||
crypto.subtle.digest("SHA-256", buffer),
|
crypto.subtle.digest("SHA-256", buffer),
|
||||||
crypto.subtle.digest("SHA-256", imageData.data)
|
crypto.subtle.digest("SHA-256", imageData.data)
|
||||||
]).then(function(hashes){
|
]);
|
||||||
var data = JSON.stringify({
|
const data = JSON.stringify({
|
||||||
urlHash: hashToString(hashes[0]),
|
urlHash: hashToString(hashes[0]),
|
||||||
imageDataHash: hashToString(hashes[1]),
|
imageDataHash: hashToString(hashes[1]),
|
||||||
isPointInPath
|
isPointInPath
|
||||||
}, null, "\t");
|
}, null, "\t");
|
||||||
form.fingerprint.value = data;
|
form.fingerprint.value = data;
|
||||||
var xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open("POST", form.action + "?main", true);
|
xhr.open("POST", form.action + "?main", true);
|
||||||
xhr.onreadystatechange = function(){
|
xhr.onreadystatechange = function(){
|
||||||
if (this.readyState === 4){
|
if (this.readyState === 4){
|
||||||
const status = this.status;
|
const status = this.status;
|
||||||
if (status === 200 || status === 304) {
|
if (status === 200 || status === 304) {
|
||||||
console.log("Sending xhr successful from main page:", data);
|
console.log("Sending xhr successful from main page:", data);
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log("Sending xhr failed:", this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
else {
|
||||||
xhr.send(new FormData(form));
|
console.log("Sending xhr failed:", this);
|
||||||
return;
|
}
|
||||||
}).catch(function(error){
|
}
|
||||||
console.error(error);
|
};
|
||||||
});
|
xhr.send(new FormData(form));
|
||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
var addTest = (function(){
|
const addTest = (function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var statusDefinitions = [
|
const statusDefinitions = [
|
||||||
{className: "notRun", text: "not run"},
|
{className: "notRun", text: "not run"},
|
||||||
{className: "loud", text: "API tampering detected"},
|
{className: "loud", text: "API tampering detected"},
|
||||||
{className: "stealthy", text: "no API tampering detected"},
|
{className: "stealthy", text: "no API tampering detected"},
|
||||||
{className: "failed", text: "test failed"}
|
{className: "failed", text: "test failed"}
|
||||||
];
|
];
|
||||||
var ul = document.getElementById("tests");
|
const ul = document.getElementById("tests");
|
||||||
return function addTest(name, func){
|
return function addTest(name, func){
|
||||||
var logs = [];
|
const logs = [];
|
||||||
function log(){
|
function log(){
|
||||||
logs.push(Array.prototype.slice.call(arguments).join(" "));
|
logs.push(Array.prototype.slice.call(arguments).join(" "));
|
||||||
}
|
}
|
||||||
var status = 0;
|
let status = 0;
|
||||||
try {
|
try {
|
||||||
status = func(log)? 1: 2;
|
status = func(log)? 1: 2;
|
||||||
}
|
}
|
||||||
@ -21,15 +21,15 @@ var addTest = (function(){
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
status = 3;
|
status = 3;
|
||||||
}
|
}
|
||||||
var li = document.createElement("li");
|
const li = document.createElement("li");
|
||||||
li.className = statusDefinitions[status].className;
|
li.className = statusDefinitions[status].className;
|
||||||
var nameNode = document.createElement("span");
|
const nameNode = document.createElement("span");
|
||||||
nameNode.className = "name";
|
nameNode.className = "name";
|
||||||
nameNode.textContent = name;
|
nameNode.textContent = name;
|
||||||
nameNode.title = func.toString();
|
nameNode.title = func.toString();
|
||||||
li.appendChild(nameNode);
|
li.appendChild(nameNode);
|
||||||
li.appendChild(document.createTextNode(": "));
|
li.appendChild(document.createTextNode(": "));
|
||||||
var statusNode = document.createElement("span");
|
const statusNode = document.createElement("span");
|
||||||
statusNode.className = "status";
|
statusNode.className = "status";
|
||||||
statusNode.textContent = statusDefinitions[status].text;
|
statusNode.textContent = statusDefinitions[status].text;
|
||||||
statusNode.title = logs.join("\n");
|
statusNode.title = logs.join("\n");
|
||||||
@ -41,15 +41,15 @@ var addTest = (function(){
|
|||||||
|
|
||||||
function checkPropertyDescriptor(object, name, expectedDescriptor, log){
|
function checkPropertyDescriptor(object, name, expectedDescriptor, log){
|
||||||
"use strict";
|
"use strict";
|
||||||
var descriptor = Object.getOwnPropertyDescriptor(object, name);
|
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||||
var detected = false;
|
let detected = false;
|
||||||
|
|
||||||
function logProperty(desc, got, expected){
|
function logProperty(desc, got, expected){
|
||||||
log("Wrong", desc, "for", name, "- got:", got, "- expected: ", expected);
|
log("Wrong", desc, "for", name, "- got:", got, "- expected: ", expected);
|
||||||
}
|
}
|
||||||
function compare(desc, getter){
|
function compare(desc, getter){
|
||||||
var got = getter(descriptor);
|
const got = getter(descriptor);
|
||||||
var expected = getter(expectedDescriptor);
|
const expected = getter(expectedDescriptor);
|
||||||
|
|
||||||
if ((typeof expected) === "function"){
|
if ((typeof expected) === "function"){
|
||||||
if (got.name !== expected.name){
|
if (got.name !== expected.name){
|
||||||
@ -94,7 +94,7 @@ addTest("function length", function(log){
|
|||||||
});
|
});
|
||||||
addTest("function code", function(log){
|
addTest("function code", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
var codeDetected = false;
|
let codeDetected = false;
|
||||||
function checkFunctionCode(func, expectedName){
|
function checkFunctionCode(func, expectedName){
|
||||||
log("checking", expectedName);
|
log("checking", expectedName);
|
||||||
if (!func.toString().match(
|
if (!func.toString().match(
|
||||||
@ -228,7 +228,6 @@ addTest("property descriptor", function(log){
|
|||||||
object: CanvasRenderingContext2D.prototype,
|
object: CanvasRenderingContext2D.prototype,
|
||||||
name: "getImageData",
|
name: "getImageData",
|
||||||
descriptor: {
|
descriptor: {
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
value: function getImageData(x, y, w, h){},
|
value: function getImageData(x, y, w, h){},
|
||||||
writable: true,
|
writable: true,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
@ -264,9 +263,9 @@ addTest("property descriptor", function(log){
|
|||||||
addTest("error provocation 1", function(log){
|
addTest("error provocation 1", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
var canvasBlocker = false;
|
let canvasBlocker = false;
|
||||||
try{
|
try{
|
||||||
ctx.getImageData(0, 0, 0, 0);
|
ctx.getImageData(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
@ -284,10 +283,10 @@ addTest("error provocation 1", function(log){
|
|||||||
addTest("error provocation 2", function(log){
|
addTest("error provocation 2", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.width = 0;
|
canvas.width = 0;
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
var canvasBlocker = false;
|
let canvasBlocker = false;
|
||||||
try{
|
try{
|
||||||
ctx.getImageData(0, 0, 1, 1);
|
ctx.getImageData(0, 0, 1, 1);
|
||||||
log("no error provoked");
|
log("no error provoked");
|
||||||
@ -306,7 +305,7 @@ addTest("error provocation 2", function(log){
|
|||||||
addTest("error provocation 3", function(log){
|
addTest("error provocation 3", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvasBlocker = false;
|
let canvasBlocker = false;
|
||||||
try{
|
try{
|
||||||
CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]);
|
CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]);
|
||||||
}
|
}
|
||||||
@ -324,23 +323,23 @@ addTest("error provocation 3", function(log){
|
|||||||
addTest("error properties", function(log){
|
addTest("error properties", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvasBlocker = false;
|
let canvasBlocker = false;
|
||||||
try{
|
try{
|
||||||
CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]);
|
CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]);
|
||||||
}
|
}
|
||||||
catch (error){
|
catch (error){
|
||||||
try {
|
try {
|
||||||
var name = "TypeError";
|
const name = "TypeError";
|
||||||
if (error.name !== name && error instanceof TypeError){
|
if (error.name !== name && error instanceof TypeError){
|
||||||
log("Error name wrong. Expected: ", name, "- got:", error.name);
|
log("Error name wrong. Expected: ", name, "- got:", error.name);
|
||||||
canvasBlocker = true;
|
canvasBlocker = true;
|
||||||
}
|
}
|
||||||
var start = "@" + location.href.replace(/\.html$/, ".js");
|
const start = "@" + location.href.replace(/\.html$/, ".js");
|
||||||
if (!error.stack.startsWith(start)){
|
if (!error.stack.startsWith(start)){
|
||||||
log("Error stack starts wrong. Expected:", start, "- got :", error.stack.split(/\n/g, 2)[0]);
|
log("Error stack starts wrong. Expected:", start, "- got :", error.stack.split(/\n/g, 2)[0]);
|
||||||
canvasBlocker = true;
|
canvasBlocker = true;
|
||||||
}
|
}
|
||||||
var message = "'getImageData' called on an object that " +
|
const message = "'getImageData' called on an object that " +
|
||||||
"does not implement interface CanvasRenderingContext2D.";
|
"does not implement interface CanvasRenderingContext2D.";
|
||||||
if (error.message !== message){
|
if (error.message !== message){
|
||||||
log("Error message wrong. Expected: ", message, "- got:", error.message);
|
log("Error message wrong. Expected: ", message, "- got:", error.message);
|
||||||
@ -356,12 +355,12 @@ addTest("error properties", function(log){
|
|||||||
function testKnownPixelValue(size, log){
|
function testKnownPixelValue(size, log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.height = size;
|
canvas.height = size;
|
||||||
canvas.width = size;
|
canvas.width = size;
|
||||||
var context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
var imageData = new ImageData(canvas.width, canvas.height);
|
const imageData = new ImageData(canvas.width, canvas.height);
|
||||||
var pixelValues = imageData.data;
|
const pixelValues = imageData.data;
|
||||||
for (let i = 0; i < imageData.data.length; i += 1){
|
for (let i = 0; i < imageData.data.length; i += 1){
|
||||||
if (i % 4 !== 3){
|
if (i % 4 !== 3){
|
||||||
pixelValues[i] = Math.floor(256 * Math.random());
|
pixelValues[i] = Math.floor(256 * Math.random());
|
||||||
@ -371,8 +370,8 @@ function testKnownPixelValue(size, log){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.putImageData(imageData, 0, 0);
|
context.putImageData(imageData, 0, 0);
|
||||||
var p = context.getImageData(0, 0, canvas.width, canvas.height).data;
|
const p = context.getImageData(0, 0, canvas.width, canvas.height).data;
|
||||||
for (var i = 0; i < p.length; i += 1){
|
for (let i = 0; i < p.length; i += 1){
|
||||||
if (p[i] !== pixelValues[i]){
|
if (p[i] !== pixelValues[i]){
|
||||||
log("wrong value", p[i], "at", i, "expected", pixelValues[i]);
|
log("wrong value", p[i], "at", i, "expected", pixelValues[i]);
|
||||||
return true;
|
return true;
|
||||||
@ -393,9 +392,9 @@ addTest("known pixel value test 10", function(log){
|
|||||||
addTest("double readout test", function(log){
|
addTest("double readout test", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
var context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
for (let i = 0; i < imageData.data.length; i += 1){
|
for (let i = 0; i < imageData.data.length; i += 1){
|
||||||
if (i % 4 !== 3){
|
if (i % 4 !== 3){
|
||||||
imageData.data[i] = Math.floor(256 * Math.random());
|
imageData.data[i] = Math.floor(256 * Math.random());
|
||||||
@ -406,8 +405,8 @@ addTest("double readout test", function(log){
|
|||||||
}
|
}
|
||||||
context.putImageData(imageData, 0, 0);
|
context.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
var imageData1 = context.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData1 = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
var imageData2 = context.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData2 = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
for (let i = 0; i < imageData2.data.length; i += 1){
|
for (let i = 0; i < imageData2.data.length; i += 1){
|
||||||
if (imageData1.data[i] !== imageData2.data[i]){
|
if (imageData1.data[i] !== imageData2.data[i]){
|
||||||
log("mismatch at", i, ":",
|
log("mismatch at", i, ":",
|
||||||
@ -424,9 +423,9 @@ addTest("double readout test", function(log){
|
|||||||
addTest("double readout test (toDataURL)", function(log){
|
addTest("double readout test (toDataURL)", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
var context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
for (let i = 0; i < imageData.data.length; i += 1){
|
for (let i = 0; i < imageData.data.length; i += 1){
|
||||||
if (i % 4 !== 3){
|
if (i % 4 !== 3){
|
||||||
imageData.data[i] = Math.floor(256 * Math.random());
|
imageData.data[i] = Math.floor(256 * Math.random());
|
||||||
@ -437,8 +436,8 @@ addTest("double readout test (toDataURL)", function(log){
|
|||||||
}
|
}
|
||||||
context.putImageData(imageData, 0, 0);
|
context.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
var dataURL1 = canvas.toDataURL();
|
const dataURL1 = canvas.toDataURL();
|
||||||
var dataURL2 = canvas.toDataURL();
|
const dataURL2 = canvas.toDataURL();
|
||||||
if (dataURL1 !== dataURL2){
|
if (dataURL1 !== dataURL2){
|
||||||
log("data URL missmatch:",
|
log("data URL missmatch:",
|
||||||
dataURL1,
|
dataURL1,
|
||||||
@ -452,9 +451,9 @@ addTest("double readout test (toDataURL)", function(log){
|
|||||||
addTest("readout - in - out test", function(log){
|
addTest("readout - in - out test", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
var context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
for (let i = 0; i < imageData.data.length; i += 1){
|
for (let i = 0; i < imageData.data.length; i += 1){
|
||||||
if (i % 4 !== 3){
|
if (i % 4 !== 3){
|
||||||
imageData.data[i] = Math.floor(256 * Math.random());
|
imageData.data[i] = Math.floor(256 * Math.random());
|
||||||
@ -465,11 +464,11 @@ addTest("readout - in - out test", function(log){
|
|||||||
}
|
}
|
||||||
context.putImageData(imageData, 0, 0);
|
context.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
var imageData1 = context.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData1 = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
var canvas2 = document.createElement("canvas");
|
const canvas2 = document.createElement("canvas");
|
||||||
var context2 = canvas2.getContext("2d");
|
const context2 = canvas2.getContext("2d");
|
||||||
context2.putImageData(imageData1, 0, 0);
|
context2.putImageData(imageData1, 0, 0);
|
||||||
var imageData2 = context2.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData2 = context2.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
for (let i = 0; i < imageData2.data.length; i += 1){
|
for (let i = 0; i < imageData2.data.length; i += 1){
|
||||||
if (imageData1.data[i] !== imageData2.data[i]){
|
if (imageData1.data[i] !== imageData2.data[i]){
|
||||||
log("mismatch at", i, ":",
|
log("mismatch at", i, ":",
|
||||||
@ -486,9 +485,9 @@ addTest("readout - in - out test", function(log){
|
|||||||
addTest("window name change", function(log){
|
addTest("window name change", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var oldName = window.name;
|
const oldName = window.name;
|
||||||
log("old name:", oldName);
|
log("old name:", oldName);
|
||||||
var newName = oldName + " added";
|
const newName = oldName + " added";
|
||||||
log("new name:", newName);
|
log("new name:", newName);
|
||||||
window.name = newName;
|
window.name = newName;
|
||||||
|
|
||||||
@ -502,7 +501,7 @@ addTest("window name change", function(log){
|
|||||||
function checkDOMRectData(rect, data, log){
|
function checkDOMRectData(rect, data, log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var detected = false;
|
let detected = false;
|
||||||
["x", "y", "width", "height"].forEach(function(property){
|
["x", "y", "width", "height"].forEach(function(property){
|
||||||
if (data[property] !== rect[property]){
|
if (data[property] !== rect[property]){
|
||||||
log("Wrong value for", property, ":", data[property], "!=", rect[property]);
|
log("Wrong value for", property, ":", data[property], "!=", rect[property]);
|
||||||
@ -515,7 +514,7 @@ function checkDOMRectData(rect, data, log){
|
|||||||
function getRectByData(data){
|
function getRectByData(data){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var el = document.createElement("div");
|
const el = document.createElement("div");
|
||||||
el.style.cssText = "position: fixed;" +
|
el.style.cssText = "position: fixed;" +
|
||||||
"left: " + data.x + "px; " +
|
"left: " + data.x + "px; " +
|
||||||
"top: " + data.y + "px; " +
|
"top: " + data.y + "px; " +
|
||||||
@ -523,7 +522,7 @@ function getRectByData(data){
|
|||||||
"height: " + data.height + "px;";
|
"height: " + data.height + "px;";
|
||||||
|
|
||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
var rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
document.body.removeChild(el);
|
document.body.removeChild(el);
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
@ -531,41 +530,41 @@ function getRectByData(data){
|
|||||||
addTest("self created DOMRect", function(log){
|
addTest("self created DOMRect", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var data = {
|
const data = {
|
||||||
x: Math.PI,
|
x: Math.PI,
|
||||||
y: Math.E,
|
y: Math.E,
|
||||||
width: Math.LOG10E,
|
width: Math.LOG10E,
|
||||||
height: Math.LOG2E
|
height: Math.LOG2E
|
||||||
};
|
};
|
||||||
var rect = new DOMRect(data.x, data.y, data.width, data.height);
|
const rect = new DOMRect(data.x, data.y, data.width, data.height);
|
||||||
return checkDOMRectData(rect, data, log);
|
return checkDOMRectData(rect, data, log);
|
||||||
});
|
});
|
||||||
|
|
||||||
addTest("known DOMRect", function(log){
|
addTest("known DOMRect", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var data = {
|
const data = {
|
||||||
x: 1 + 1/4,
|
x: 1 + 1/4,
|
||||||
y: 2,
|
y: 2,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 4
|
height: 4
|
||||||
};
|
};
|
||||||
|
|
||||||
var rect = getRectByData(data);
|
const rect = getRectByData(data);
|
||||||
|
|
||||||
return checkDOMRectData(rect, data, log);
|
return checkDOMRectData(rect, data, log);
|
||||||
});
|
});
|
||||||
addTest("changed DOMRect", function(log){
|
addTest("changed DOMRect", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var data = {
|
const data = {
|
||||||
x: Math.PI,
|
x: Math.PI,
|
||||||
y: 2,
|
y: 2,
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 4
|
height: 4
|
||||||
};
|
};
|
||||||
|
|
||||||
var rect = getRectByData(data);
|
const rect = getRectByData(data);
|
||||||
rect.x = Math.PI;
|
rect.x = Math.PI;
|
||||||
|
|
||||||
return checkDOMRectData(rect, data, log);
|
return checkDOMRectData(rect, data, log);
|
||||||
@ -573,15 +572,15 @@ addTest("changed DOMRect", function(log){
|
|||||||
addTest("recreated DOMRect", function(log){
|
addTest("recreated DOMRect", function(log){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var data = {
|
const data = {
|
||||||
x: Math.PI,
|
x: Math.PI,
|
||||||
y: Math.E,
|
y: Math.E,
|
||||||
width: Math.LOG10E,
|
width: Math.LOG10E,
|
||||||
height: Math.LOG2E
|
height: Math.LOG2E
|
||||||
};
|
};
|
||||||
|
|
||||||
var rect = getRectByData(data);
|
const rect = getRectByData(data);
|
||||||
var rect2 = getRectByData(rect);
|
const rect2 = getRectByData(rect);
|
||||||
|
|
||||||
return checkDOMRectData(rect2, rect, log);
|
return checkDOMRectData(rect2, rect, log);
|
||||||
});
|
});
|
@ -1,7 +1,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
function byteArrayToHex(arrayBuffer){
|
function byteArrayToHex(arrayBuffer){
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(arrayBuffer)).forEach(function(num){
|
(new Uint32Array(arrayBuffer)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
});
|
||||||
@ -28,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const properties = ["x", "y", "width", "height", "top", "left", "right", "bottom"];
|
const properties = ["x", "y", "width", "height", "top", "left", "right", "bottom"];
|
||||||
function performTest(output, callback){
|
async function performTest(output, callback){
|
||||||
const rects = getElements().map(function(element){
|
const rects = getElements().map(function(element){
|
||||||
return {
|
return {
|
||||||
name: element.dataset.name,
|
name: element.dataset.name,
|
||||||
@ -42,15 +42,10 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
crypto.subtle.digest("SHA-256", data)
|
const hash = await crypto.subtle.digest("SHA-256", data);
|
||||||
.then(function(hash){
|
output.querySelector(".hash").textContent = byteArrayToHex(hash);
|
||||||
output.querySelector(".hash").textContent = byteArrayToHex(hash);
|
|
||||||
return;
|
|
||||||
}).catch(function(error){
|
|
||||||
output.querySelector(".hash").textContent = "Unable to compute hash: " + error;
|
|
||||||
});
|
|
||||||
|
|
||||||
var dataNode = output.querySelector(".data");
|
const dataNode = output.querySelector(".data");
|
||||||
dataNode.innerHTML = "<table><tr><th></th>" +
|
dataNode.innerHTML = "<table><tr><th></th>" +
|
||||||
rects.map(function(rect){
|
rects.map(function(rect){
|
||||||
return "<th>" + rect.name + "</th>";
|
return "<th>" + rect.name + "</th>";
|
||||||
@ -68,22 +63,16 @@
|
|||||||
}).join("") + "</tr>";
|
}).join("") + "</tr>";
|
||||||
}).join("") +
|
}).join("") +
|
||||||
"</table>";
|
"</table>";
|
||||||
rects.forEach(function(rect){
|
rects.forEach(async function(rect){
|
||||||
const data = new Float64Array(properties.length);
|
const data = new Float64Array(properties.length);
|
||||||
properties.forEach(function(property, i){
|
properties.forEach(function(property, i){
|
||||||
data[i] = rect.data[property];
|
data[i] = rect.data[property];
|
||||||
});
|
});
|
||||||
|
|
||||||
crypto.subtle.digest("SHA-256", data).then(function(hash){
|
const hash = await crypto.subtle.digest("SHA-256", data);
|
||||||
dataNode.querySelector(
|
dataNode.querySelector(
|
||||||
".rectHash[data-name=\"" + rect.name + "\"]"
|
".rectHash[data-name=\"" + rect.name + "\"]"
|
||||||
).textContent = byteArrayToHex(hash);
|
).textContent = byteArrayToHex(hash);
|
||||||
return;
|
|
||||||
}).catch(function(error){
|
|
||||||
dataNode.querySelector(
|
|
||||||
".rectHash[data-name=\"" + rect.name + "\"]"
|
|
||||||
).textContent = "Unable to compute hash: " + error;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,12 +133,12 @@
|
|||||||
return element.getBoundingClientRect();
|
return element.getBoundingClientRect();
|
||||||
});
|
});
|
||||||
createTest("Range.getClientRects", function(element){
|
createTest("Range.getClientRects", function(element){
|
||||||
var range = document.createRange();
|
const range = document.createRange();
|
||||||
range.selectNode(element);
|
range.selectNode(element);
|
||||||
return range.getClientRects()[0];
|
return range.getClientRects()[0];
|
||||||
});
|
});
|
||||||
createTest("Range.getBoundingClientRect", function(element){
|
createTest("Range.getBoundingClientRect", function(element){
|
||||||
var range = document.createRange();
|
const range = document.createRange();
|
||||||
range.selectNode(element);
|
range.selectNode(element);
|
||||||
return range.getBoundingClientRect();
|
return range.getBoundingClientRect();
|
||||||
});
|
});
|
||||||
|
@ -90,11 +90,11 @@
|
|||||||
document.body.innerHTML = "<iframe></iframe>";
|
document.body.innerHTML = "<iframe></iframe>";
|
||||||
log("TEST:", "innerHTML after 1000ms:", compare(test(window[0]), reference));
|
log("TEST:", "innerHTML after 1000ms:", compare(test(window[0]), reference));
|
||||||
|
|
||||||
var iFrame = document.createElement("iframe");
|
const iFrame = document.createElement("iframe");
|
||||||
document.body.appendChild(iFrame);
|
document.body.appendChild(iFrame);
|
||||||
log("TEST:", "appendChild after 1000ms:", compare(test(window[1]), reference));
|
log("TEST:", "appendChild after 1000ms:", compare(test(window[1]), reference));
|
||||||
|
|
||||||
var iFrame2 = document.createElement("iframe");
|
const iFrame2 = document.createElement("iframe");
|
||||||
iFrame.replaceWith(iFrame2);
|
iFrame.replaceWith(iFrame2);
|
||||||
log("TEST:", "replaceWith after 1000ms:", compare(test(window[1]), reference));
|
log("TEST:", "replaceWith after 1000ms:", compare(test(window[1]), reference));
|
||||||
|
|
||||||
@ -107,7 +107,7 @@
|
|||||||
"<li>all the displayed hashes should be the same (exception if there is a change to a wyciwyg page)</li>" +
|
"<li>all the displayed hashes should be the same (exception if there is a change to a wyciwyg page)</li>" +
|
||||||
"<li>all lines with \"TEST:\" should have a \"match\" at the end</li>" +
|
"<li>all lines with \"TEST:\" should have a \"match\" at the end</li>" +
|
||||||
"</ul>";
|
"</ul>";
|
||||||
var title = document.createElement("title");
|
const title = document.createElement("title");
|
||||||
title.textContent = "iFrame test";
|
title.textContent = "iFrame test";
|
||||||
document.getElementsByTagName("head")[0].appendChild(title);
|
document.getElementsByTagName("head")[0].appendChild(title);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// eslint-disable-next-line no-var
|
||||||
var log = function(){
|
var log = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
return function log(...str){
|
return function log(...str){
|
||||||
@ -18,9 +19,9 @@ function draw(canvas){
|
|||||||
canvas.setAttribute("width", 220);
|
canvas.setAttribute("width", 220);
|
||||||
canvas.setAttribute("height", 30);
|
canvas.setAttribute("height", 30);
|
||||||
|
|
||||||
var fp_text = "BrowserLeaks,com <canvas> 10";
|
const fp_text = "BrowserLeaks,com <canvas> 10";
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.font = "14px 'Arial'";
|
ctx.font = "14px 'Arial'";
|
||||||
ctx.textBaseline = "alphabetic";
|
ctx.textBaseline = "alphabetic";
|
||||||
@ -37,39 +38,34 @@ function test(window){
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// create window canvas
|
// create window canvas
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
// draw image in window canvas
|
// draw image in window canvas
|
||||||
draw(canvas);
|
draw(canvas);
|
||||||
return window.HTMLCanvasElement.prototype.toDataURL.call(canvas);
|
return window.HTMLCanvasElement.prototype.toDataURL.call(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hash(string){
|
async function hash(string){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var buffer = new TextEncoder("utf-8").encode(string);
|
const buffer = new TextEncoder("utf-8").encode(string);
|
||||||
return crypto.subtle.digest("SHA-256", buffer).then(function(hash){
|
const hash = await crypto.subtle.digest("SHA-256", buffer);
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(hash)).forEach(function(num){
|
(new Uint32Array(hash)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
|
||||||
return chunks.map(function(chunk){
|
|
||||||
return "0".repeat(8 - chunk.length) + chunk;
|
|
||||||
}).join("");
|
|
||||||
});
|
});
|
||||||
|
return chunks.map(function(chunk){
|
||||||
|
return "0".repeat(8 - chunk.length) + chunk;
|
||||||
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function compare(string1, string2, alwaysOutputHashes){
|
function compare(string1, string2, alwaysOutputHashes){
|
||||||
"use strict";
|
"use strict";
|
||||||
function outputHashes(message){
|
async function outputHashes(message){
|
||||||
return Promise.all([
|
const hashes = await Promise.all([
|
||||||
hash(string1),
|
hash(string1),
|
||||||
hash(string2)
|
hash(string2)
|
||||||
]).then(function(hashes){
|
]);
|
||||||
console.log(message, ...hashes);
|
console.log(message, ...hashes);
|
||||||
return;
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string1 === string2){
|
if (string1 === string2){
|
||||||
@ -100,14 +96,15 @@ function compare(string1, string2, alwaysOutputHashes){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
var reference = test(window);
|
var reference = test(window);
|
||||||
hash(reference).then(function(hash){
|
(async function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
try {
|
||||||
log("reference hash:", hash);
|
const hashValue = await hash(reference);
|
||||||
return;
|
log("reference hash:", hashValue);
|
||||||
}).catch(function(error){
|
}
|
||||||
"use strict";
|
catch (error){
|
||||||
|
log("%cX", "color: red", "Unable to compute reference hash:", error);
|
||||||
log("%cX", "color: red", "Unable to compute reference hash:", error);
|
}
|
||||||
});
|
}());
|
@ -1,15 +1,15 @@
|
|||||||
|
|
||||||
var createLog = function(){
|
const createLog = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var div = document.getElementById("log");
|
const div = document.getElementById("log");
|
||||||
|
|
||||||
return function createLog(){
|
return function createLog(){
|
||||||
var logDiv = document.createElement("div");
|
const logDiv = document.createElement("div");
|
||||||
logDiv.className = "log";
|
logDiv.className = "log";
|
||||||
div.appendChild(logDiv);
|
div.appendChild(logDiv);
|
||||||
return function createLine(str){
|
return function createLine(str){
|
||||||
var logLine = document.createElement("div");
|
const logLine = document.createElement("div");
|
||||||
logLine.className = "logLine";
|
logLine.className = "logLine";
|
||||||
logDiv.appendChild(logLine);
|
logDiv.appendChild(logLine);
|
||||||
logLine.textContent = str;
|
logLine.textContent = str;
|
||||||
@ -20,7 +20,7 @@ var createLog = function(){
|
|||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var log = createLog();
|
let log = createLog();
|
||||||
|
|
||||||
log("user agent equal between server and client: " + (
|
log("user agent equal between server and client: " + (
|
||||||
document.getElementById("serverUserAgent").text === navigator.userAgent
|
document.getElementById("serverUserAgent").text === navigator.userAgent
|
||||||
@ -29,26 +29,26 @@ log("user agent equal between server and client: " + (
|
|||||||
Object.keys(navigator.__proto__).sort().forEach(function(property){
|
Object.keys(navigator.__proto__).sort().forEach(function(property){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var value = navigator[property];
|
const value = navigator[property];
|
||||||
if ((typeof value) === "string"){
|
if ((typeof value) === "string"){
|
||||||
log(property + ": " + value);
|
log(property + ": " + value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var section = document.createElement("h2");
|
const section = document.createElement("h2");
|
||||||
section.textContent = "Values in iFrame";
|
section.textContent = "Values in iFrame";
|
||||||
document.getElementById("log").append(section);
|
document.getElementById("log").append(section);
|
||||||
|
|
||||||
log = createLog();
|
log = createLog();
|
||||||
|
|
||||||
var iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
var iframeWindow = frames[frames.length - 1];
|
const iframeWindow = frames[frames.length - 1];
|
||||||
|
|
||||||
Object.keys(navigator.__proto__).sort().forEach(function(property){
|
Object.keys(navigator.__proto__).sort().forEach(function(property){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var value = iframeWindow.navigator[property];
|
const value = iframeWindow.navigator[property];
|
||||||
if ((typeof value) === "string"){
|
if ((typeof value) === "string"){
|
||||||
log(property + "@iframe: " + value);
|
log(property + "@iframe: " + value);
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
|
|
||||||
var createLog = function(){
|
const createLog = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var div = document.getElementById("log");
|
const div = document.getElementById("log");
|
||||||
|
|
||||||
return function createLog(){
|
return function createLog(){
|
||||||
var logDiv = document.createElement("div");
|
const logDiv = document.createElement("div");
|
||||||
logDiv.className = "log";
|
logDiv.className = "log";
|
||||||
div.appendChild(logDiv);
|
div.appendChild(logDiv);
|
||||||
return {
|
return {
|
||||||
createButton: function createButton(text, callback){
|
createButton: function createButton(text, callback){
|
||||||
var button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.className = "logButton";
|
button.className = "logButton";
|
||||||
logDiv.appendChild(button);
|
logDiv.appendChild(button);
|
||||||
button.textContent = text;
|
button.textContent = text;
|
||||||
button.addEventListener("click", callback);
|
button.addEventListener("click", callback);
|
||||||
},
|
},
|
||||||
createLine: function createLine(str, type = "div"){
|
createLine: function createLine(str, type = "div"){
|
||||||
var logLine = document.createElement(type);
|
const logLine = document.createElement(type);
|
||||||
logLine.className = "logLine";
|
logLine.className = "logLine";
|
||||||
logDiv.appendChild(logLine);
|
logDiv.appendChild(logLine);
|
||||||
logLine.textContent = str;
|
logLine.textContent = str;
|
||||||
@ -29,20 +29,20 @@ var createLog = function(){
|
|||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var performTest = function(){
|
const performTest = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
return function performTest(name, func, innerRunLength, outerRunLength){
|
return function performTest(name, func, innerRunLength, outerRunLength){
|
||||||
var log = createLog();
|
const log = createLog();
|
||||||
log.createLine("test " + name, "h3");
|
log.createLine("test " + name, "h3");
|
||||||
var line = log.createLine("");
|
const line = log.createLine("");
|
||||||
var line2;
|
let line2;
|
||||||
var time = 0;
|
let time = 0;
|
||||||
var time2 = 0;
|
let time2 = 0;
|
||||||
var min = Number.POSITIVE_INFINITY;
|
let min = Number.POSITIVE_INFINITY;
|
||||||
var max = 0;
|
let max = 0;
|
||||||
var outerI = 0;
|
let outerI = 0;
|
||||||
var outerRunIncrease = outerRunLength;
|
const outerRunIncrease = outerRunLength;
|
||||||
if (func.prepareOnce){
|
if (func.prepareOnce){
|
||||||
func.prepareOnce();
|
func.prepareOnce();
|
||||||
}
|
}
|
||||||
@ -50,21 +50,21 @@ var performTest = function(){
|
|||||||
line("starting");
|
line("starting");
|
||||||
line2("");
|
line2("");
|
||||||
function run(){
|
function run(){
|
||||||
for (var i = 0; i < innerRunLength; i += 1){
|
for (let i = 0; i < innerRunLength; i += 1){
|
||||||
if (func.prepare){
|
if (func.prepare){
|
||||||
func.prepare();
|
func.prepare();
|
||||||
}
|
}
|
||||||
var start = performance.now();
|
const start = performance.now();
|
||||||
func.test();
|
func.test();
|
||||||
var end = performance.now();
|
const end = performance.now();
|
||||||
var duration = end - start;
|
const duration = end - start;
|
||||||
min = Math.min(min, duration);
|
min = Math.min(min, duration);
|
||||||
max = Math.max(max, duration);
|
max = Math.max(max, duration);
|
||||||
time2 += duration * duration;
|
time2 += duration * duration;
|
||||||
time += duration;
|
time += duration;
|
||||||
}
|
}
|
||||||
outerI += 1;
|
outerI += 1;
|
||||||
var totalRunI = outerI * innerRunLength;
|
const totalRunI = outerI * innerRunLength;
|
||||||
line(
|
line(
|
||||||
"finished run " + totalRunI + " from " + (innerRunLength * outerRunLength) +
|
"finished run " + totalRunI + " from " + (innerRunLength * outerRunLength) +
|
||||||
" -> average: " + (time / totalRunI).toFixed(2) +
|
" -> average: " + (time / totalRunI).toFixed(2) +
|
||||||
@ -91,9 +91,9 @@ function draw(canvas){
|
|||||||
canvas.setAttribute("width", 220);
|
canvas.setAttribute("width", 220);
|
||||||
canvas.setAttribute("height", 30);
|
canvas.setAttribute("height", 30);
|
||||||
|
|
||||||
var fp_text = "BrowserLeaks,com <canvas> 10";
|
const fp_text = "BrowserLeaks,com <canvas> 10";
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.font = "14px 'Arial'";
|
ctx.font = "14px 'Arial'";
|
||||||
ctx.textBaseline = "alphabetic";
|
ctx.textBaseline = "alphabetic";
|
||||||
@ -107,10 +107,10 @@ function draw(canvas){
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fingerprintTest = function(){
|
const fingerprintTest = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas;
|
let canvas;
|
||||||
return {
|
return {
|
||||||
prepare: function(){
|
prepare: function(){
|
||||||
// create window canvas
|
// create window canvas
|
||||||
@ -124,20 +124,20 @@ var fingerprintTest = function(){
|
|||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var randomImageTest = function(){
|
const randomImageTest = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var canvas;
|
let canvas;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
prepare: function(){
|
prepare: function(){
|
||||||
canvas = document.createElement("canvas");
|
canvas = document.createElement("canvas");
|
||||||
canvas.width = 1000;
|
canvas.width = 1000;
|
||||||
canvas.height = 100;
|
canvas.height = 100;
|
||||||
var imageData = new ImageData(canvas.width, canvas.height);
|
const imageData = new ImageData(canvas.width, canvas.height);
|
||||||
var data = imageData.data;
|
const data = imageData.data;
|
||||||
|
|
||||||
for (var i = 0; i < data.length; i += 4){
|
for (let i = 0; i < data.length; i += 4){
|
||||||
data[i + 0] = Math.floor(256 * Math.random());
|
data[i + 0] = Math.floor(256 * Math.random());
|
||||||
data[i + 1] = Math.floor(256 * Math.random());
|
data[i + 1] = Math.floor(256 * Math.random());
|
||||||
data[i + 2] = Math.floor(256 * Math.random());
|
data[i + 2] = Math.floor(256 * Math.random());
|
||||||
@ -152,10 +152,10 @@ var randomImageTest = function(){
|
|||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var innerHTMlTest = function(html, repeats){
|
const innerHTMlTest = function(html, repeats){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var div;
|
let div;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
prepareOnce: function(){
|
prepareOnce: function(){
|
||||||
@ -164,7 +164,7 @@ var innerHTMlTest = function(html, repeats){
|
|||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
},
|
},
|
||||||
test: function randomImageTest(){
|
test: function randomImageTest(){
|
||||||
for (var i = repeats; i--;){
|
for (let i = repeats; i--;){
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
div.innerHTML = "";
|
div.innerHTML = "";
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
function addTest(container, title, callback){
|
function addTest(container, title, callback){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var testContainer = document.createElement("div");
|
const testContainer = document.createElement("div");
|
||||||
testContainer.className = "test";
|
testContainer.className = "test";
|
||||||
|
|
||||||
var titleNode = document.createElement("h3");
|
const titleNode = document.createElement("h3");
|
||||||
titleNode.textContent = title;
|
titleNode.textContent = title;
|
||||||
testContainer.appendChild(titleNode);
|
testContainer.appendChild(titleNode);
|
||||||
|
|
||||||
var resultsNode = document.createElement("div");
|
const resultsNode = document.createElement("div");
|
||||||
resultsNode.className = "results";
|
resultsNode.className = "results";
|
||||||
testContainer.appendChild(resultsNode);
|
testContainer.appendChild(resultsNode);
|
||||||
|
|
||||||
@ -22,27 +22,28 @@ function addConsistencyTest(title, callback){
|
|||||||
|
|
||||||
addTest(document.getElementById("consistency"), title, function(resultsNode){
|
addTest(document.getElementById("consistency"), title, function(resultsNode){
|
||||||
|
|
||||||
var line = document.createElement("div");
|
const line = document.createElement("div");
|
||||||
line.textContent = "consistent: ";
|
line.textContent = "consistent: ";
|
||||||
resultsNode.appendChild(line);
|
resultsNode.appendChild(line);
|
||||||
|
|
||||||
var consistent = document.createElement("span");
|
const consistent = document.createElement("span");
|
||||||
consistent.className = "result";
|
consistent.className = "result";
|
||||||
line.appendChild(consistent);
|
line.appendChild(consistent);
|
||||||
|
|
||||||
function compute(){
|
async function compute(){
|
||||||
consistent.textContent = "computing";
|
consistent.textContent = "computing";
|
||||||
callback().then(function(value){
|
try {
|
||||||
|
const value = await callback();
|
||||||
consistent.textContent = value? "OK": "not OK";
|
consistent.textContent = value? "OK": "not OK";
|
||||||
return;
|
}
|
||||||
}).catch(function(error){
|
catch (error){
|
||||||
consistent.classList.add("failed");
|
consistent.classList.add("failed");
|
||||||
if (Array.isArray(error)){
|
if (Array.isArray(error)){
|
||||||
consistent.textContent = "";
|
consistent.textContent = "";
|
||||||
var ul = document.createElement("ul");
|
const ul = document.createElement("ul");
|
||||||
consistent.appendChild(ul);
|
consistent.appendChild(ul);
|
||||||
error.forEach(function(error){
|
error.forEach(function(error){
|
||||||
var li = document.createElement("li");
|
const li = document.createElement("li");
|
||||||
li.textContent = error;
|
li.textContent = error;
|
||||||
ul.appendChild(li);
|
ul.appendChild(li);
|
||||||
});
|
});
|
||||||
@ -50,7 +51,7 @@ function addConsistencyTest(title, callback){
|
|||||||
else {
|
else {
|
||||||
consistent.textContent = error;
|
consistent.textContent = error;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
compute();
|
compute();
|
||||||
window.addEventListener("resize", compute);
|
window.addEventListener("resize", compute);
|
||||||
@ -76,7 +77,7 @@ addConsistencyTest("screen properties", function(){
|
|||||||
addConsistencyTest("media queries: window.matchMedia - low value", function(){
|
addConsistencyTest("media queries: window.matchMedia - low value", function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var value = Math.floor(Math.min(screen.width, screen.height) / 2);
|
const value = Math.floor(Math.min(screen.width, screen.height) / 2);
|
||||||
|
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
window.matchMedia("(min-device-width: " + value + "px)").matches &&
|
window.matchMedia("(min-device-width: " + value + "px)").matches &&
|
||||||
@ -89,11 +90,11 @@ addConsistencyTest("media queries: window.matchMedia - low value", function(){
|
|||||||
addConsistencyTest("media queries: window.matchMedia - reported value", function(){
|
addConsistencyTest("media queries: window.matchMedia - reported value", function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var errors = [];
|
const errors = [];
|
||||||
["width", "height"].forEach(function(dimension){
|
["width", "height"].forEach(function(dimension){
|
||||||
["min-", "max-", ""].forEach(function(comparison){
|
["min-", "max-", ""].forEach(function(comparison){
|
||||||
var queryBase = "(" + comparison + "device-" + dimension + ": ";
|
const queryBase = "(" + comparison + "device-" + dimension + ": ";
|
||||||
var query = queryBase + screen[dimension] + "px)";
|
let query = queryBase + screen[dimension] + "px)";
|
||||||
if (!window.matchMedia(query).matches){
|
if (!window.matchMedia(query).matches){
|
||||||
errors.push(query + " did not match.");
|
errors.push(query + " did not match.");
|
||||||
query = queryBase + (screen[dimension] + 1) + "px)";
|
query = queryBase + (screen[dimension] + 1) + "px)";
|
||||||
@ -116,7 +117,7 @@ addConsistencyTest("media queries: window.matchMedia - reported value", function
|
|||||||
addConsistencyTest("media queries: window.matchMedia - big value", function(){
|
addConsistencyTest("media queries: window.matchMedia - big value", function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var value = Math.max(screen.width, screen.height) * 2;
|
const value = Math.max(screen.width, screen.height) * 2;
|
||||||
|
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
!window.matchMedia("(min-device-width: " + value + "px)").matches &&
|
!window.matchMedia("(min-device-width: " + value + "px)").matches &&
|
||||||
@ -126,27 +127,28 @@ addConsistencyTest("media queries: window.matchMedia - big value", function(){
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
var addResolutionTest = function(){
|
const addResolutionTest = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
return function addResolutionTest(title, callback, properties = ["width", "height"]){
|
return function addResolutionTest(title, callback, properties = ["width", "height"]){
|
||||||
addTest(document.getElementById("resolution"), title, function(resultsNode){
|
addTest(document.getElementById("resolution"), title, function(resultsNode){
|
||||||
properties.forEach(function(type){
|
properties.forEach(function(type){
|
||||||
var line = document.createElement("div");
|
const line = document.createElement("div");
|
||||||
line.textContent = type + ": ";
|
line.textContent = type + ": ";
|
||||||
resultsNode.appendChild(line);
|
resultsNode.appendChild(line);
|
||||||
|
|
||||||
var number = document.createElement("span");
|
const number = document.createElement("span");
|
||||||
number.className = "result " + type;
|
number.className = "result " + type;
|
||||||
line.appendChild(number);
|
line.appendChild(number);
|
||||||
function compute(){
|
async function compute(){
|
||||||
number.textContent = "computing";
|
number.textContent = "computing";
|
||||||
callback(type).then(function(value){
|
try {
|
||||||
|
const value = await callback(type);
|
||||||
number.textContent = value;
|
number.textContent = value;
|
||||||
return;
|
}
|
||||||
}).catch(function(error){
|
catch (error){
|
||||||
number.classList.add("failed");
|
number.classList.add("failed");
|
||||||
number.textContent = error;
|
number.textContent = error;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
compute();
|
compute();
|
||||||
window.addEventListener("resize", compute);
|
window.addEventListener("resize", compute);
|
||||||
@ -185,78 +187,76 @@ addResolutionTest("window properties: outer...", function(type){
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
function searchValue(tester){
|
async function searchValue(tester){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var minValue = 0;
|
let minValue = 0;
|
||||||
var maxValue = 512;
|
let maxValue = 512;
|
||||||
var ceiling = Math.pow(2, 32);
|
const ceiling = Math.pow(2, 32);
|
||||||
|
|
||||||
function stepUp(){
|
async function stepUp(){
|
||||||
if (maxValue > ceiling){
|
if (maxValue > ceiling){
|
||||||
return Promise.reject("Unable to find upper bound");
|
return Promise.reject("Unable to find upper bound");
|
||||||
}
|
}
|
||||||
return tester(maxValue).then(function(testResult){
|
const testResult = await tester(maxValue);
|
||||||
if (testResult === searchValue.isEqual){
|
if (testResult === searchValue.isEqual){
|
||||||
return maxValue;
|
return maxValue;
|
||||||
}
|
}
|
||||||
else if (testResult === searchValue.isBigger){
|
else if (testResult === searchValue.isBigger){
|
||||||
minValue = maxValue;
|
minValue = maxValue;
|
||||||
maxValue *= 2;
|
maxValue *= 2;
|
||||||
return stepUp();
|
return stepUp();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let v = 1;
|
||||||
|
async function test(){
|
||||||
|
const r = await tester(v);
|
||||||
|
v = 2;
|
||||||
|
}
|
||||||
|
async function binarySearch(){
|
||||||
|
if (maxValue - minValue < 0.01){
|
||||||
|
const testResult = await tester(minValue);
|
||||||
|
if (testResult.isEqual){
|
||||||
|
return minValue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
const testResult = await tester(maxValue);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function binarySearch(){
|
|
||||||
if (maxValue - minValue < 0.01){
|
|
||||||
return tester(minValue).then(function(testResult){
|
|
||||||
if (testResult.isEqual){
|
if (testResult.isEqual){
|
||||||
return minValue;
|
return maxValue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// eslint-disable-next-line promise/no-nesting
|
throw "Search could not find exact value." +
|
||||||
return tester(maxValue).then(function(testResult){
|
" It's between " + minValue + " and " + maxValue + ".";
|
||||||
if (testResult.isEqual){
|
|
||||||
return maxValue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw "Search could not find exact value." +
|
|
||||||
" It's between " + minValue + " and " + maxValue + ".";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var pivot = (minValue + maxValue) / 2;
|
const pivot = (minValue + maxValue) / 2;
|
||||||
return tester(pivot).then(function(testResult){
|
const testResult = await tester(pivot);
|
||||||
if (testResult === searchValue.isEqual){
|
if (testResult === searchValue.isEqual){
|
||||||
return pivot;
|
return pivot;
|
||||||
}
|
}
|
||||||
else if (testResult === searchValue.isBigger){
|
else if (testResult === searchValue.isBigger){
|
||||||
minValue = pivot;
|
minValue = pivot;
|
||||||
return binarySearch();
|
return binarySearch();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
maxValue = pivot;
|
maxValue = pivot;
|
||||||
return binarySearch();
|
return binarySearch();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stepUp().then(function(stepUpResult){
|
const stepUpResult = await stepUp();
|
||||||
if (stepUpResult){
|
if (stepUpResult){
|
||||||
return stepUpResult;
|
return stepUpResult;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return binarySearch();
|
return binarySearch();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
searchValue.isSmaller = -1;
|
searchValue.isSmaller = -1;
|
||||||
searchValue.isEqual = 0;
|
searchValue.isEqual = 0;
|
||||||
@ -297,16 +297,16 @@ addResolutionTest("media queries: window.matchMedia (min)", function(type){
|
|||||||
addResolutionTest("media queries: css (max)", function(type){
|
addResolutionTest("media queries: css (max)", function(type){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var tester = document.createElement("div");
|
const tester = document.createElement("div");
|
||||||
var id = "tester_" + (Math.random() * Math.pow(2, 32)).toString(36).replace(".", "_");
|
const id = "tester_" + (Math.random() * Math.pow(2, 32)).toString(36).replace(".", "_");
|
||||||
tester.id = id;
|
tester.id = id;
|
||||||
document.body.appendChild(tester);
|
document.body.appendChild(tester);
|
||||||
|
|
||||||
var style = document.createElement("style");
|
const style = document.createElement("style");
|
||||||
style.type = "text/css";
|
style.type = "text/css";
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
|
|
||||||
var styleSheet = document.styleSheets[document.styleSheets.length - 1];
|
const styleSheet = document.styleSheets[document.styleSheets.length - 1];
|
||||||
styleSheet.insertRule("#" + id + "{position: fixed; right: 100%; z-index: 0;}");
|
styleSheet.insertRule("#" + id + "{position: fixed; right: 100%; z-index: 0;}");
|
||||||
|
|
||||||
return searchValue(function(valueToTest){
|
return searchValue(function(valueToTest){
|
||||||
@ -314,12 +314,12 @@ addResolutionTest("media queries: css (max)", function(type){
|
|||||||
while (styleSheet.rules.length > 1){
|
while (styleSheet.rules.length > 1){
|
||||||
styleSheet.removeRule(1);
|
styleSheet.removeRule(1);
|
||||||
}
|
}
|
||||||
var rule = "@media (max-device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 1;}}";
|
let rule = "@media (max-device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 1;}}";
|
||||||
styleSheet.insertRule(rule, 1);
|
styleSheet.insertRule(rule, 1);
|
||||||
rule = "@media (device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 2;}}";
|
rule = "@media (device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 2;}}";
|
||||||
styleSheet.insertRule(rule, 2);
|
styleSheet.insertRule(rule, 2);
|
||||||
window.setTimeout(function(){
|
window.setTimeout(function(){
|
||||||
var testValue = window.getComputedStyle(tester).zIndex;
|
const testValue = window.getComputedStyle(tester).zIndex;
|
||||||
switch (testValue){
|
switch (testValue){
|
||||||
case "0":
|
case "0":
|
||||||
resolve(searchValue.isBigger);
|
resolve(searchValue.isBigger);
|
||||||
@ -341,16 +341,16 @@ addResolutionTest("media queries: css (max)", function(type){
|
|||||||
addResolutionTest("media queries: css (min)", function(type){
|
addResolutionTest("media queries: css (min)", function(type){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var tester = document.createElement("div");
|
const tester = document.createElement("div");
|
||||||
var id = "tester_" + (Math.random() * Math.pow(2, 32)).toString(36).replace(".", "_");
|
const id = "tester_" + (Math.random() * Math.pow(2, 32)).toString(36).replace(".", "_");
|
||||||
tester.id = id;
|
tester.id = id;
|
||||||
document.body.appendChild(tester);
|
document.body.appendChild(tester);
|
||||||
|
|
||||||
var style = document.createElement("style");
|
const style = document.createElement("style");
|
||||||
style.type = "text/css";
|
style.type = "text/css";
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
|
|
||||||
var styleSheet = document.styleSheets[document.styleSheets.length - 1];
|
const styleSheet = document.styleSheets[document.styleSheets.length - 1];
|
||||||
styleSheet.insertRule("#" + id + "{position: fixed; right: 100%; z-index: 0;}");
|
styleSheet.insertRule("#" + id + "{position: fixed; right: 100%; z-index: 0;}");
|
||||||
|
|
||||||
return searchValue(function(valueToTest){
|
return searchValue(function(valueToTest){
|
||||||
@ -358,12 +358,12 @@ addResolutionTest("media queries: css (min)", function(type){
|
|||||||
while (styleSheet.rules.length > 1){
|
while (styleSheet.rules.length > 1){
|
||||||
styleSheet.removeRule(1);
|
styleSheet.removeRule(1);
|
||||||
}
|
}
|
||||||
var rule = "@media (min-device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 1;}}";
|
let rule = "@media (min-device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 1;}}";
|
||||||
styleSheet.insertRule(rule, 1);
|
styleSheet.insertRule(rule, 1);
|
||||||
rule = "@media (device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 2;}}";
|
rule = "@media (device-" + type + ": " + valueToTest + "px){#" + id + "{z-index: 2;}}";
|
||||||
styleSheet.insertRule(rule, 2);
|
styleSheet.insertRule(rule, 2);
|
||||||
window.setTimeout(function(){
|
window.setTimeout(function(){
|
||||||
var testValue = window.getComputedStyle(tester).zIndex;
|
const testValue = window.getComputedStyle(tester).zIndex;
|
||||||
switch (testValue){
|
switch (testValue){
|
||||||
case "0":
|
case "0":
|
||||||
resolve(searchValue.isSmaller);
|
resolve(searchValue.isSmaller);
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
canvas.setAttribute("width", 220);
|
canvas.setAttribute("width", 220);
|
||||||
canvas.setAttribute("height", 30);
|
canvas.setAttribute("height", 30);
|
||||||
|
|
||||||
var fp_text = "BrowserLeaks,com <canvas> 10";
|
const fp_text = "BrowserLeaks,com <canvas> 10";
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.font = "14px 'Arial'";
|
ctx.font = "14px 'Arial'";
|
||||||
ctx.textBaseline = "alphabetic";
|
ctx.textBaseline = "alphabetic";
|
||||||
@ -33,9 +33,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// create window canvas
|
// create window canvas
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
// draw image in window canvas
|
// draw image in window canvas
|
||||||
var ctx = draw(canvas);
|
const ctx = draw(canvas);
|
||||||
return {
|
return {
|
||||||
imageData: ctx.getImageData(0, 0, canvas.width, canvas.height),
|
imageData: ctx.getImageData(0, 0, canvas.width, canvas.height),
|
||||||
url: canvas.toDataURL(),
|
url: canvas.toDataURL(),
|
||||||
@ -56,7 +56,7 @@
|
|||||||
function hashToString(hash){
|
function hashToString(hash){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(hash)).forEach(function(num){
|
(new Uint32Array(hash)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
});
|
||||||
@ -65,47 +65,45 @@
|
|||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
var send = function(){
|
const send = function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
return function send(form, {url, imageData, isPointInPath}){
|
return async function send(form, {url, imageData, isPointInPath}){
|
||||||
var buffer = new TextEncoder("utf-8").encode(url);
|
const buffer = new TextEncoder("utf-8").encode(url);
|
||||||
return Promise.all([
|
const hashes = await Promise.all([
|
||||||
crypto.subtle.digest("SHA-256", buffer),
|
crypto.subtle.digest("SHA-256", buffer),
|
||||||
crypto.subtle.digest("SHA-256", imageData.data)
|
crypto.subtle.digest("SHA-256", imageData.data)
|
||||||
]).then(function(hashes){
|
]);
|
||||||
var data = JSON.stringify({
|
const data = JSON.stringify({
|
||||||
urlHash: hashToString(hashes[0]),
|
urlHash: hashToString(hashes[0]),
|
||||||
imageDataHash: hashToString(hashes[1]),
|
imageDataHash: hashToString(hashes[1]),
|
||||||
isPointInPath
|
isPointInPath
|
||||||
}, null, "\t");
|
}, null, "\t");
|
||||||
form.fingerprint.value = data;
|
form.fingerprint.value = data;
|
||||||
var xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open("POST", form.action, true);
|
xhr.open("POST", form.action, true);
|
||||||
xhr.onreadystatechange = function(){
|
xhr.onreadystatechange = function(){
|
||||||
if (this.readyState === 4){
|
if (this.readyState === 4){
|
||||||
const status = this.status;
|
const status = this.status;
|
||||||
if (status === 200 || status === 304) {
|
if (status === 200 || status === 304) {
|
||||||
console.log("Sending xhr successful from", origin, ":", data);
|
console.log("Sending xhr successful from", origin, ":", data);
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log("Sending xhr failed:", this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
else {
|
||||||
xhr.send(new FormData(form));
|
console.log("Sending xhr failed:", this);
|
||||||
window.setTimeout(function(){
|
}
|
||||||
form.submit();
|
}
|
||||||
window.setTimeout(
|
};
|
||||||
function(){
|
xhr.send(new FormData(form));
|
||||||
document.getElementById("log").textContent =
|
window.setTimeout(function(){
|
||||||
"You see the real canvas fingerprint, but it cannot leak from this iFrame.";
|
form.submit();
|
||||||
},
|
window.setTimeout(
|
||||||
250
|
function(){
|
||||||
);
|
document.getElementById("log").textContent =
|
||||||
}, 1000);
|
"You see the real canvas fingerprint, but it cannot leak from this iFrame.";
|
||||||
return;
|
},
|
||||||
});
|
250
|
||||||
|
);
|
||||||
|
}, 1000);
|
||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -6,16 +6,16 @@
|
|||||||
<link href="testIcon.svg" type="image/png" rel="icon">
|
<link href="testIcon.svg" type="image/png" rel="icon">
|
||||||
<link href="testIcon.svg" type="image/png" rel="shortcut icon">
|
<link href="testIcon.svg" type="image/png" rel="shortcut icon">
|
||||||
<script>
|
<script>
|
||||||
var firstDescriptor = Object.getOwnPropertyDescriptor(HTMLCanvasElement.prototype, "getContext");
|
const firstDescriptor = Object.getOwnPropertyDescriptor(HTMLCanvasElement.prototype, "getContext");
|
||||||
console.log(new Date(), "starting first fingerprint", window.name);
|
console.log(new Date(), "starting first fingerprint", window.name);
|
||||||
function fingerPrint(){
|
function fingerPrint(){
|
||||||
"use strict";var canvas = document.createElement("canvas");
|
"use strict";const canvas = document.createElement("canvas");
|
||||||
canvas.setAttribute("width", 220);
|
canvas.setAttribute("width", 220);
|
||||||
canvas.setAttribute("height", 30);
|
canvas.setAttribute("height", 30);
|
||||||
|
|
||||||
var fp_text = "BrowserLeaks,com <canvas> 10";
|
const fp_text = "BrowserLeaks,com <canvas> 10";
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.font = "14px 'Arial'";
|
ctx.font = "14px 'Arial'";
|
||||||
ctx.textBaseline = "alphabetic";
|
ctx.textBaseline = "alphabetic";
|
||||||
@ -28,21 +28,20 @@
|
|||||||
|
|
||||||
return canvas.toDataURL();
|
return canvas.toDataURL();
|
||||||
}
|
}
|
||||||
function hash(url){
|
async function hash(url){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var buffer = new TextEncoder("utf-8").encode(url);
|
const buffer = new TextEncoder("utf-8").encode(url);
|
||||||
return crypto.subtle.digest("SHA-256", buffer).then(function(hash){
|
const hash = await crypto.subtle.digest("SHA-256", buffer);
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(hash)).forEach(function(num){
|
(new Uint32Array(hash)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
|
||||||
return chunks.map(function(chunk){
|
|
||||||
return "0".repeat(8 - chunk.length) + chunk;
|
|
||||||
}).join("");
|
|
||||||
});
|
});
|
||||||
|
return chunks.map(function(chunk){
|
||||||
|
return "0".repeat(8 - chunk.length) + chunk;
|
||||||
|
}).join("");
|
||||||
}
|
}
|
||||||
var firstFingerprint = false;
|
let firstFingerprint = false;
|
||||||
try {
|
try {
|
||||||
firstFingerprint = fingerPrint();
|
firstFingerprint = fingerPrint();
|
||||||
}
|
}
|
||||||
@ -76,14 +75,14 @@
|
|||||||
<div id="output"></div>
|
<div id="output"></div>
|
||||||
<script>
|
<script>
|
||||||
if (firstFingerprint){
|
if (firstFingerprint){
|
||||||
var output = document.getElementById("output");
|
const output = document.getElementById("output");
|
||||||
output.textContent = "context API not blocked";
|
output.textContent = "context API not blocked";
|
||||||
output.appendChild(document.createElement("br"));
|
output.appendChild(document.createElement("br"));
|
||||||
window.setTimeout(function(){
|
window.setTimeout(async function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
console.log(new Date(), "starting second fingerprint", window.name);
|
console.log(new Date(), "starting second fingerprint", window.name);
|
||||||
var secondDescriptor = Object.getOwnPropertyDescriptor(HTMLCanvasElement.prototype, "getContext");
|
const secondDescriptor = Object.getOwnPropertyDescriptor(HTMLCanvasElement.prototype, "getContext");
|
||||||
|
|
||||||
if (firstDescriptor.value === secondDescriptor.value){
|
if (firstDescriptor.value === secondDescriptor.value){
|
||||||
output.appendChild(document.createTextNode("descriptor did not change -> good!"));
|
output.appendChild(document.createTextNode("descriptor did not change -> good!"));
|
||||||
@ -95,26 +94,22 @@
|
|||||||
output.classList.add("nok");
|
output.classList.add("nok");
|
||||||
}
|
}
|
||||||
output.appendChild(document.createElement("br"));
|
output.appendChild(document.createElement("br"));
|
||||||
var secondFingerprint = fingerPrint();
|
const secondFingerprint = fingerPrint();
|
||||||
if (firstFingerprint === secondFingerprint){
|
if (firstFingerprint === secondFingerprint){
|
||||||
return hash(firstFingerprint).then(function(hash){
|
const firstHash = await hash(firstFingerprint);
|
||||||
output.appendChild(document.createTextNode("fingerprint consistent (" + hash + ") -> good!"));
|
output.appendChild(document.createTextNode("fingerprint consistent (" + firstHash + ") -> good!"));
|
||||||
output.classList.add("ok");
|
output.classList.add("ok");
|
||||||
return;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Promise.all([hash(firstFingerprint), hash(secondFingerprint)]).then(function(hashes){
|
const hashes = await Promise.all([hash(firstFingerprint), hash(secondFingerprint)]);
|
||||||
output.appendChild(
|
output.appendChild(
|
||||||
document.createTextNode(
|
document.createTextNode(
|
||||||
"fingerprint not consistent (" +
|
"fingerprint not consistent (" +
|
||||||
hashes[0] + " != " + hashes[1] +
|
hashes[0] + " != " + hashes[1] +
|
||||||
") -> very bad! (potential fingerprint leak)"
|
") -> very bad! (potential fingerprint leak)"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
output.classList.add("nok");
|
output.classList.add("nok");
|
||||||
return;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
58
test/test.js
58
test/test.js
@ -2,7 +2,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function hashToString(hash){
|
function hashToString(hash){
|
||||||
var chunks = [];
|
const chunks = [];
|
||||||
(new Uint32Array(hash)).forEach(function(num){
|
(new Uint32Array(hash)).forEach(function(num){
|
||||||
chunks.push(num.toString(16));
|
chunks.push(num.toString(16));
|
||||||
});
|
});
|
||||||
@ -11,22 +11,18 @@
|
|||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function show(container, {url, imageData, isPointInPath}){
|
async function show(container, {url, imageData, isPointInPath}){
|
||||||
var display = container.querySelector(".display");
|
const display = container.querySelector(".display");
|
||||||
display.src = url;
|
display.src = url;
|
||||||
display.title = url;
|
display.title = url;
|
||||||
var buffer = new TextEncoder("utf-8").encode(url);
|
const buffer = new TextEncoder("utf-8").encode(url);
|
||||||
Promise.all([
|
const hashes = await Promise.all([
|
||||||
crypto.subtle.digest("SHA-256", buffer),
|
crypto.subtle.digest("SHA-256", buffer),
|
||||||
crypto.subtle.digest("SHA-256", imageData.data)
|
crypto.subtle.digest("SHA-256", imageData.data)
|
||||||
]).then(function(hashes){
|
]);
|
||||||
container.querySelector(".hash").textContent =
|
container.querySelector(".hash").textContent =
|
||||||
hashToString(hashes[0]) + " / " +
|
hashToString(hashes[0]) + " / " +
|
||||||
hashToString(hashes[1]);
|
hashToString(hashes[1]);
|
||||||
return;
|
|
||||||
}).catch(function(error){
|
|
||||||
container.querySelector(".hash").textContent = "Error while calculating hash: " + error;
|
|
||||||
});
|
|
||||||
container.querySelector(".isPointInPath").textContent = isPointInPath;
|
container.querySelector(".isPointInPath").textContent = isPointInPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +43,7 @@
|
|||||||
catch (error){console.error(error);}
|
catch (error){console.error(error);}
|
||||||
window.addEventListener("click", function windowOpenTest(){
|
window.addEventListener("click", function windowOpenTest(){
|
||||||
window.removeEventListener("click", windowOpenTest);
|
window.removeEventListener("click", windowOpenTest);
|
||||||
var newWindow = window.open("/");
|
const newWindow = window.open("/");
|
||||||
try{
|
try{
|
||||||
show(document.getElementById("windowOpen"), copyToDifferentDocumentTest(newWindow.document));
|
show(document.getElementById("windowOpen"), copyToDifferentDocumentTest(newWindow.document));
|
||||||
}
|
}
|
||||||
@ -79,7 +75,7 @@
|
|||||||
show(document.getElementById("iframe6"), dynamicIframeTest3());
|
show(document.getElementById("iframe6"), dynamicIframeTest3());
|
||||||
});
|
});
|
||||||
document.querySelector("#windowOpen button").addEventListener("click", function(){
|
document.querySelector("#windowOpen button").addEventListener("click", function(){
|
||||||
var newWindow = window.open("/");
|
const newWindow = window.open("/");
|
||||||
show(document.getElementById("windowOpen"), copyToDifferentDocumentTest(newWindow.document));
|
show(document.getElementById("windowOpen"), copyToDifferentDocumentTest(newWindow.document));
|
||||||
newWindow.close();
|
newWindow.close();
|
||||||
});
|
});
|
||||||
@ -91,9 +87,9 @@ function draw(canvas){
|
|||||||
canvas.setAttribute("width", 220);
|
canvas.setAttribute("width", 220);
|
||||||
canvas.setAttribute("height", 30);
|
canvas.setAttribute("height", 30);
|
||||||
|
|
||||||
var fp_text = "BrowserLeaks,com <canvas> 10";
|
const fp_text = "BrowserLeaks,com <canvas> 10";
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.font = "14px 'Arial'";
|
ctx.font = "14px 'Arial'";
|
||||||
ctx.textBaseline = "alphabetic";
|
ctx.textBaseline = "alphabetic";
|
||||||
@ -123,9 +119,9 @@ function topTest(){
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// create window canvas
|
// create window canvas
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
// draw image in window canvas
|
// draw image in window canvas
|
||||||
var ctx = draw(canvas);
|
const ctx = draw(canvas);
|
||||||
return {
|
return {
|
||||||
imageData: ctx.getImageData(0, 0, canvas.width, canvas.height),
|
imageData: ctx.getImageData(0, 0, canvas.width, canvas.height),
|
||||||
url: canvas.toDataURL(),
|
url: canvas.toDataURL(),
|
||||||
@ -137,16 +133,16 @@ function copyToDifferentDocumentTest(otherDocument){
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// create window canvas
|
// create window canvas
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
|
|
||||||
// draw image in window canvas
|
// draw image in window canvas
|
||||||
draw(canvas);
|
draw(canvas);
|
||||||
|
|
||||||
// create other canvas and context
|
// create other canvas and context
|
||||||
var otherCanvas = otherDocument.createElement("canvas");
|
const otherCanvas = otherDocument.createElement("canvas");
|
||||||
otherCanvas.setAttribute("width", 220);
|
otherCanvas.setAttribute("width", 220);
|
||||||
otherCanvas.setAttribute("height", 30);
|
otherCanvas.setAttribute("height", 30);
|
||||||
var otherContext = otherCanvas.getContext("2d");
|
const otherContext = otherCanvas.getContext("2d");
|
||||||
|
|
||||||
// copy image from window canvas to iframe context
|
// copy image from window canvas to iframe context
|
||||||
otherContext.drawImage(canvas, 0, 0);
|
otherContext.drawImage(canvas, 0, 0);
|
||||||
@ -167,10 +163,10 @@ function iframeTest(iframe){
|
|||||||
function dynamicIframeTest1(){
|
function dynamicIframeTest1(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var length = frames.length;
|
const length = frames.length;
|
||||||
var iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
var iframeWindow = frames[length];
|
const iframeWindow = frames[length];
|
||||||
document.body.removeChild(iframe);
|
document.body.removeChild(iframe);
|
||||||
return copyToDifferentDocumentTest(iframeWindow.document);
|
return copyToDifferentDocumentTest(iframeWindow.document);
|
||||||
}
|
}
|
||||||
@ -178,10 +174,10 @@ function dynamicIframeTest1(){
|
|||||||
function dynamicIframeTest2(){
|
function dynamicIframeTest2(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var length = window.length;
|
const length = window.length;
|
||||||
var iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
var iframeWindow = window[length];
|
const iframeWindow = window[length];
|
||||||
document.body.removeChild(iframe);
|
document.body.removeChild(iframe);
|
||||||
return copyToDifferentDocumentTest(iframeWindow.document);
|
return copyToDifferentDocumentTest(iframeWindow.document);
|
||||||
}
|
}
|
||||||
@ -189,11 +185,11 @@ function dynamicIframeTest2(){
|
|||||||
function dynamicIframeTest3(){
|
function dynamicIframeTest3(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var length = window.length;
|
const length = window.length;
|
||||||
var div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
div.innerHTML = "<iframe></iframe>";
|
div.innerHTML = "<iframe></iframe>";
|
||||||
var iframeWindow = window[length];
|
const iframeWindow = window[length];
|
||||||
document.body.removeChild(div);
|
document.body.removeChild(div);
|
||||||
return copyToDifferentDocumentTest(iframeWindow.document);
|
return copyToDifferentDocumentTest(iframeWindow.document);
|
||||||
}
|
}
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
function getParameters(context){
|
function getParameters(context){
|
||||||
const parameters = [];
|
const parameters = [];
|
||||||
for (var name in context){
|
for (let name in context){
|
||||||
if (name.toUpperCase() === name){
|
if (name.toUpperCase() === name){
|
||||||
var value = context.getParameter(context[name]);
|
const value = context.getParameter(context[name]);
|
||||||
if (value !== null){
|
if (value !== null){
|
||||||
parameters.push({name: name, value: value});
|
parameters.push({name: name, value: value});
|
||||||
}
|
}
|
||||||
@ -13,18 +13,18 @@
|
|||||||
}
|
}
|
||||||
const debugExtension = context.getExtension("WEBGL_debug_renderer_info");
|
const debugExtension = context.getExtension("WEBGL_debug_renderer_info");
|
||||||
|
|
||||||
for (name in debugExtension){
|
for (let name in debugExtension){
|
||||||
if (name.toUpperCase() === name){
|
if (name.toUpperCase() === name){
|
||||||
value = context.getParameter(debugExtension[name]);
|
const value = context.getParameter(debugExtension[name]);
|
||||||
if (value !== null){
|
if (value !== null){
|
||||||
parameters.push({name: name, value: value});
|
parameters.push({name: name, value: value});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var frontParameters = ["VENDOR", "RENDERER", "UNMASKED_VENDOR_WEBGL", "UNMASKED_RENDERER_WEBGL"];
|
const frontParameters = ["VENDOR", "RENDERER", "UNMASKED_VENDOR_WEBGL", "UNMASKED_RENDERER_WEBGL"];
|
||||||
parameters.sort(function(a, b){
|
parameters.sort(function(a, b){
|
||||||
var frontA = frontParameters.indexOf(a.name);
|
const frontA = frontParameters.indexOf(a.name);
|
||||||
var frontB = frontParameters.indexOf(b.name);
|
const frontB = frontParameters.indexOf(b.name);
|
||||||
if (frontA !== -1){
|
if (frontA !== -1){
|
||||||
if (frontB !== -1){
|
if (frontB !== -1){
|
||||||
return frontA - frontB;
|
return frontA - frontB;
|
||||||
@ -45,58 +45,55 @@
|
|||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
["webgl", "webgl2"].forEach(function(context, index){
|
["webgl", "webgl2"].forEach(async function(context, index){
|
||||||
var output = document.createElement("div");
|
const output = document.createElement("div");
|
||||||
document.getElementById("output").appendChild(output);
|
document.getElementById("output").appendChild(output);
|
||||||
try {
|
try {
|
||||||
var canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.width = 11;
|
canvas.width = 11;
|
||||||
canvas.height = 13;
|
canvas.height = 13;
|
||||||
var gl = canvas.getContext(context) || canvas.getContext("experimental-" + context);
|
const gl = canvas.getContext(context) || canvas.getContext("experimental-" + context);
|
||||||
|
|
||||||
// paint it completely black
|
// paint it completely black
|
||||||
gl.clearColor(index * 0.25, index * 0.25, index * 0.25, 1);
|
gl.clearColor(index * 0.25, index * 0.25, index * 0.25, 1);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
var pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
|
const pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
|
||||||
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||||
var values = {};
|
const values = {};
|
||||||
var max = 0;
|
let max = 0;
|
||||||
for (var i = 0; i < pixels.length; i += 1){
|
for (let i = 0; i < pixels.length; i += 1){
|
||||||
values[pixels[i]] = (values[pixels[i]] || 0) + 1;
|
values[pixels[i]] = (values[pixels[i]] || 0) + 1;
|
||||||
max = Math.max(max, values[pixels[i]]);
|
max = Math.max(max, values[pixels[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parameters = getParameters(gl);
|
const parameters = getParameters(gl);
|
||||||
if (context === "webgl2"){
|
if (context === "webgl2"){
|
||||||
var parameterOutput = document.createElement("table");
|
const parameterOutput = document.createElement("table");
|
||||||
document.getElementById("parameters").appendChild(parameterOutput);
|
document.getElementById("parameters").appendChild(parameterOutput);
|
||||||
parameters.forEach(function(parameter){
|
parameters.forEach(function(parameter){
|
||||||
var parameterRow = document.createElement("tr");
|
const parameterRow = document.createElement("tr");
|
||||||
parameterRow.innerHTML = "<td>" + parameter.name + "</td><td>" + parameter.value + "</td>";
|
parameterRow.innerHTML = "<td>" + parameter.name + "</td><td>" + parameter.value + "</td>";
|
||||||
parameterOutput.appendChild(parameterRow);
|
parameterOutput.appendChild(parameterRow);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
crypto.subtle.digest("SHA-256", new TextEncoder("utf-8").encode(parameters.map(function(parameter){
|
const hashBytes = await crypto.subtle.digest("SHA-256", new TextEncoder("utf-8")
|
||||||
return parameter.name + ": " + parameter.value;
|
.encode(parameters.map(function(parameter){
|
||||||
}).join(",")))
|
return parameter.name + ": " + parameter.value;
|
||||||
.then(function(hash){
|
}).join(",")));
|
||||||
var chunks = [];
|
|
||||||
(new Uint32Array(hash)).forEach(function(num){
|
const chunks = [];
|
||||||
chunks.push(num.toString(16));
|
(new Uint32Array(hashBytes)).forEach(function(num){
|
||||||
});
|
chunks.push(num.toString(16));
|
||||||
return chunks.map(function(chunk){
|
});
|
||||||
return "0".repeat(8 - chunk.length) + chunk;
|
const hash = chunks.map(function(chunk){
|
||||||
}).join("");
|
return "0".repeat(8 - chunk.length) + chunk;
|
||||||
}).then(function(hash) {
|
}).join("");
|
||||||
output.textContent = context + ": " +
|
|
||||||
(max !== 3 * values[255]? "": "not ") + "supported " +
|
output.textContent = context + ": " +
|
||||||
"(parameter hash: " + hash + ")";
|
(max !== 3 * values[255]? "": "not ") + "supported " +
|
||||||
output.title = JSON.stringify(values);
|
"(parameter hash: " + hash + ")";
|
||||||
return;
|
output.title = JSON.stringify(values);
|
||||||
}).catch(function(error){
|
|
||||||
output.textContent = "Error while calculating hash: " + error;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch (error){
|
catch (error){
|
||||||
output.textContent = context + ": ERROR";
|
output.textContent = context + ": ERROR";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user