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 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="55" data-name="text2" id="text2" class="testRect">񳺚顃򳴡ģԹ̔򫳞񊄐񿔺ࠕ</text>
|
||||
</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="domRectTest.php">DOMRect Fingerprint 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="performanceTest.html">Performance test</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