mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2024-12-22 12:50:36 +01:00
parent
78183f9efc
commit
734e76180f
88
lib/modifiedSVGAPI.js
Normal file
88
lib/modifiedSVGAPI.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
(function(){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let scope;
|
||||||
|
if ((typeof exports) !== "undefined"){
|
||||||
|
scope = exports;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scope = require.register("./modifiedSVGAPI", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||||
|
const {byteArrayToString: hash} = require("./hash");
|
||||||
|
|
||||||
|
|
||||||
|
let randomSupply = null;
|
||||||
|
scope.setRandomSupply = function(supply){
|
||||||
|
randomSupply = supply;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getValueHash(value){
|
||||||
|
return hash(new Float32Array([value]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const cache = {};
|
||||||
|
function getFakeValue(value, window){
|
||||||
|
const valueHash = getValueHash(value);
|
||||||
|
let cachedValue = cache[valueHash];
|
||||||
|
if (typeof cachedValue === "number"){
|
||||||
|
return cachedValue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const rng = randomSupply.getRng(1, window);
|
||||||
|
const fakedValue = value + 0.01 * (rng(0) / 0xffffffff - 0.5);
|
||||||
|
const fakedHash = getValueHash(fakedValue);
|
||||||
|
cache[valueHash] = fakedValue;
|
||||||
|
cache[fakedHash] = fakedValue;
|
||||||
|
return fakedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scope.getFakeValue = getFakeValue;
|
||||||
|
|
||||||
|
function getFakeValueCallback(args, check){
|
||||||
|
const {notify, window, original} = check;
|
||||||
|
const ret = args.length? original.call(this, ...args): original.call(this);
|
||||||
|
notify("fakedSVGReadout");
|
||||||
|
return getFakeValue(ret, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.changedFunctions = {
|
||||||
|
getTotalLength: {
|
||||||
|
object: ["SVGGeometryElement"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getTotalLength(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFakeValueCallback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getComputedTextLength: {
|
||||||
|
object: ["SVGTextContentElement"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getComputedTextLength(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFakeValueCallback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSubStringLength: {
|
||||||
|
object: ["SVGTextContentElement"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getSubStringLength(charnum, nchars){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFakeValueCallback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
scope.changedGetters = [];
|
||||||
|
|
||||||
|
setProperties(scope.changedFunctions, scope.changedGetters, {
|
||||||
|
type: "readout",
|
||||||
|
getStatus: getStatusByFlag("protectSVG"),
|
||||||
|
api: "svg"
|
||||||
|
});
|
||||||
|
}());
|
@ -16,4 +16,5 @@
|
|||||||
Q 90,60 50,90
|
Q 90,60 50,90
|
||||||
Q 10,60 10,30 z"/>
|
Q 10,60 10,30 z"/>
|
||||||
<text x="20" y="35" data-name="text" id="text" class="testRect">Text with Unicode 𝞐</text>
|
<text x="20" y="35" data-name="text" id="text" class="testRect">Text with Unicode 𝞐</text>
|
||||||
|
<text x="20" y="55" data-name="text2" id="text2" class="testRect">񳺚顃򳴡ģԹ̔򫳞񊄐񿔺ࠕ</text>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 628 B |
@ -18,6 +18,7 @@
|
|||||||
<li><a href="audioTest.html">Audio Fingerprint test</a></li>
|
<li><a href="audioTest.html">Audio Fingerprint test</a></li>
|
||||||
<li><a href="domRectTest.php">DOMRect Fingerprint test</a></li>
|
<li><a href="domRectTest.php">DOMRect Fingerprint test</a></li>
|
||||||
<li><a href="textMetricsTest.html">TextMetrics test</a></li>
|
<li><a href="textMetricsTest.html">TextMetrics test</a></li>
|
||||||
|
<li><a href="svgTest.html">SVG test</a></li>
|
||||||
<li><a href="detectionTest.html">Detection test</a></li>
|
<li><a href="detectionTest.html">Detection test</a></li>
|
||||||
<li><a href="performanceTest.html">Performance test</a></li>
|
<li><a href="performanceTest.html">Performance test</a></li>
|
||||||
<li><a href="webGL-Test.html">Support for webGL</a></li>
|
<li><a href="webGL-Test.html">Support for webGL</a></li>
|
||||||
|
43
test/svgTest.css
Normal file
43
test/svgTest.css
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
#svg {
|
||||||
|
position: fixed;
|
||||||
|
top: -2000%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#test {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 1em;
|
||||||
|
}
|
||||||
|
#test .data table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
#test .data th {
|
||||||
|
padding: 0.4em;
|
||||||
|
}
|
||||||
|
#test .data td{
|
||||||
|
border: 1px solid #c7c7c7;
|
||||||
|
padding: 0.4em;
|
||||||
|
}
|
||||||
|
#test .data td.value {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.small {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
.rectHash {
|
||||||
|
font-size: 4px;
|
||||||
|
}
|
||||||
|
.rectHash:hover {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-hidable.content-hidden .content, .content-hidable .anti-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.content-hidable .content, .content-hidable.content-hidden .anti-content {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
.content-hidable .toggle {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
36
test/svgTest.html
Normal file
36
test/svgTest.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>TextMetrics test</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<link href="testIcon.svg" type="image/png" rel="icon">
|
||||||
|
<link href="testIcon.svg" type="image/png" rel="shortcut icon">
|
||||||
|
<link rel="stylesheet" href="../default.css" type="text/css">
|
||||||
|
<link rel="stylesheet" href="./svgTest.css" type="text/css">
|
||||||
|
<style>
|
||||||
|
.hash {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 70%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>SVG test</h1>
|
||||||
|
<h2>Expected result</h2>
|
||||||
|
<ol>
|
||||||
|
<li>the hashes are different to the hashes when CanvasBlocker is disabled</li>
|
||||||
|
<li>if "refresh" is clicked nothing must change</li>
|
||||||
|
<li>upon page reload the hash changes (depending on CanvasBlocker settings - e.g. not in the stealth preset)</li>
|
||||||
|
</ol>
|
||||||
|
<h2>Tests</h2>
|
||||||
|
<iframe id="svg" src="domRectSVG.svg"></iframe>
|
||||||
|
<div id="test" id="svg">
|
||||||
|
<h3 class="title">SVG</h3>
|
||||||
|
Hash: <span class="hash"></span><br>
|
||||||
|
<span class="content-hidable content-hidden">Data: <span class="toggle"><span class="anti-content">+</span><span class="content">−</span></span><span class="data content"></span></span><br>
|
||||||
|
<button class="refresh">refresh</button>
|
||||||
|
</div>
|
||||||
|
<script src="testAPI.js"></script>
|
||||||
|
<script src="svgTest.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
114
test/svgTest.js
Normal file
114
test/svgTest.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/* globals testAPI */
|
||||||
|
(function(){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function byteArrayToHex(arrayBuffer){
|
||||||
|
const chunks = [];
|
||||||
|
(new Uint32Array(arrayBuffer)).forEach(function(num){
|
||||||
|
chunks.push(num.toString(16));
|
||||||
|
});
|
||||||
|
return chunks.map(function(chunk){
|
||||||
|
return "0".repeat(8 - chunk.length) + chunk;
|
||||||
|
}).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatNumber(number){
|
||||||
|
const str = number.toString();
|
||||||
|
return "<span class=small>" + str.substring(0, str.length - 2) + "</span>" +
|
||||||
|
str.substring(str.length - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const svg = document.getElementById("svg");
|
||||||
|
const output = document.getElementById("test");
|
||||||
|
|
||||||
|
function getElements(){
|
||||||
|
const doc = svg.contentDocument;
|
||||||
|
|
||||||
|
return Array.from(doc.querySelectorAll(".testRect"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const tests = [];
|
||||||
|
function addTest(title, callback){
|
||||||
|
tests.push({title, callback});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function performTests(){
|
||||||
|
const elements = getElements();
|
||||||
|
const results = await Promise.all(tests.map(async function(test){
|
||||||
|
return {
|
||||||
|
name: test.title,
|
||||||
|
data: await Promise.all(elements.map(async function(svgElement){
|
||||||
|
return await test.callback(svgElement);
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
const data = new Float64Array(elements.length * tests.length);
|
||||||
|
results.forEach(function(svgData, i){
|
||||||
|
svgData.data.forEach(function(testData, j){
|
||||||
|
if ((typeof testData) === "number"){
|
||||||
|
data[i * elements.length + j] = testData;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const hash = await crypto.subtle.digest("SHA-256", data);
|
||||||
|
output.querySelector(".hash").textContent = byteArrayToHex(hash);
|
||||||
|
|
||||||
|
const dataNode = output.querySelector(".data");
|
||||||
|
dataNode.innerHTML = "<table><tr><th></th>" +
|
||||||
|
elements.map(function(svgElement){
|
||||||
|
return "<th>" + svgElement.dataset.name + "</th>";
|
||||||
|
}).join("") +
|
||||||
|
results.map(function(result){
|
||||||
|
return "<tr><th>" + result.name + "</th>" + result.data.map(function(value){
|
||||||
|
if ((typeof value) === "number"){
|
||||||
|
return "<td class=\"value\">" +
|
||||||
|
formatNumber(value) +
|
||||||
|
"</td>";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "<td class=\"value unavailable\">--</td>";
|
||||||
|
}
|
||||||
|
}).join("") + "</tr>";
|
||||||
|
}).join("") +
|
||||||
|
"</table>";
|
||||||
|
}
|
||||||
|
|
||||||
|
svg.addEventListener("load", function(){
|
||||||
|
addTest("getTotalLength", function(element){
|
||||||
|
if (!element.getTotalLength){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return element.getTotalLength();
|
||||||
|
});
|
||||||
|
addTest("getComputedTextLength", function(element){
|
||||||
|
if (!element.getComputedTextLength){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return element.getComputedTextLength();
|
||||||
|
});
|
||||||
|
[{start: 3, end: 7}, {start: 7, end: 11}, {start: 3, end: 11}].forEach(function(substringDefinition){
|
||||||
|
addTest(
|
||||||
|
`getSubStringLength(${substringDefinition.start}, ${substringDefinition.end})`,
|
||||||
|
function(element){
|
||||||
|
if (!element.getSubStringLength){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return element.getSubStringLength(substringDefinition.start, substringDefinition.end);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.querySelector(".refresh").addEventListener("click", function(){
|
||||||
|
performTests();
|
||||||
|
});
|
||||||
|
performTests();
|
||||||
|
|
||||||
|
|
||||||
|
document.querySelectorAll(".content-hidable").forEach(function(parentNode){
|
||||||
|
parentNode.querySelector(".toggle").addEventListener("click", function(){
|
||||||
|
parentNode.classList.toggle("content-hidden");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}());
|
Loading…
x
Reference in New Issue
Block a user