mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2025-01-05 11:32:20 +01:00
commit
ca6e5d83e1
@ -20,6 +20,7 @@ Geschützte "Fingerprinting"-APIs:
|
|||||||
<li>audio</li>
|
<li>audio</li>
|
||||||
<li>history</li>
|
<li>history</li>
|
||||||
<li>window (standardmäßig deaktiviert)</li>
|
<li>window (standardmäßig deaktiviert)</li>
|
||||||
|
<li>DOMRect</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Falls Sie Fehler finden oder Verbesserungsvorschläge haben, teilen Sie mir das bitte auf https://github.com/kkapsner/CanvasBlocker/issues mit.
|
Falls Sie Fehler finden oder Verbesserungsvorschläge haben, teilen Sie mir das bitte auf https://github.com/kkapsner/CanvasBlocker/issues mit.
|
@ -20,6 +20,7 @@ Protected "fingerprinting" APIs:
|
|||||||
<li>audio</li>
|
<li>audio</li>
|
||||||
<li>history</li>
|
<li>history</li>
|
||||||
<li>window (disabled by default)</li>
|
<li>window (disabled by default)</li>
|
||||||
|
<li>DOMRect</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Please report issues and feature requests at https://github.com/kkapsner/CanvasBlocker/issues
|
Please report issues and feature requests at https://github.com/kkapsner/CanvasBlocker/issues
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -8,6 +8,8 @@
|
|||||||
"Nachfrageverweigerungsmodus",
|
"Nachfrageverweigerungsmodus",
|
||||||
"Oakenpants",
|
"Oakenpants",
|
||||||
"PDFs",
|
"PDFs",
|
||||||
|
"Rect",
|
||||||
|
"Rects",
|
||||||
"Spoofer",
|
"Spoofer",
|
||||||
"Thorin",
|
"Thorin",
|
||||||
"Vortäuschaktion",
|
"Vortäuschaktion",
|
||||||
|
@ -13,6 +13,14 @@ The different block modes are:
|
|||||||
<li>allow everything: Ignore all lists and allow the <canvas> API on all websites.</li>
|
<li>allow everything: Ignore all lists and allow the <canvas> API on all websites.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
Protected "fingerprinting" APIs:
|
||||||
|
* canvas 2d
|
||||||
|
* webGL
|
||||||
|
* audio
|
||||||
|
* history
|
||||||
|
* window (disabled by default)
|
||||||
|
* DOMRect
|
||||||
|
|
||||||
Special thanks to:
|
Special thanks to:
|
||||||
* spodermenpls for finding all the typos
|
* spodermenpls for finding all the typos
|
||||||
* Thorin-Oakenpants for the icon idea
|
* Thorin-Oakenpants for the icon idea
|
||||||
|
@ -105,6 +105,10 @@
|
|||||||
"message": "Window API",
|
"message": "Window API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"section_DOMRect-api":{
|
||||||
|
"message": "DOMRect API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"displayAdvancedSettings_title": {
|
"displayAdvancedSettings_title": {
|
||||||
"message": "Expertenmodus",
|
"message": "Expertenmodus",
|
||||||
@ -213,6 +217,18 @@
|
|||||||
"message": "Wollen Sie das Auslesen über die Window-API erlauben?",
|
"message": "Wollen Sie das Auslesen über die Window-API erlauben?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"askForDOMRectPermission": {
|
||||||
|
"message": "Wollen Sie die DOMRect-API erlauben?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForDOMRectInputPermission": {
|
||||||
|
"message": "Wollen Sie das Schreiben über die DOMRect-API erlauben?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForDOMRectReadoutPermission": {
|
||||||
|
"message": "Wollen Sie das Auslesen über die DOMRect-API erlauben?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"askOnlyOnce_title": {
|
"askOnlyOnce_title": {
|
||||||
"message": "Nur einmal nachfragen",
|
"message": "Nur einmal nachfragen",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -544,6 +560,10 @@
|
|||||||
"message": "Window-Auslese vorgetäuscht auf {url}",
|
"message": "Window-Auslese vorgetäuscht auf {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"fakedDOMRectReadout": {
|
||||||
|
"message": "DOMRect-Auslese vorgetäuscht auf {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"fakedInput": {
|
"fakedInput": {
|
||||||
"message": "Bei Ausgabe vorgetäuscht auf {url}",
|
"message": "Bei Ausgabe vorgetäuscht auf {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -695,14 +715,14 @@
|
|||||||
"message": "Dateispezifische Whitelist",
|
"message": "Dateispezifische Whitelist",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"whiteList_description": {
|
|
||||||
"message": "Domänen oder URLs, die die <canvas>-API verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt werden.",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"whiteList_title": {
|
"whiteList_title": {
|
||||||
"message": "Whitelist",
|
"message": "Whitelist",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"whiteList_description": {
|
||||||
|
"message": "Domänen oder URLs, die die <canvas>-API verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt werden.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"whitelist": {
|
"whitelist": {
|
||||||
"message": "erlauben",
|
"message": "erlauben",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -716,14 +736,14 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
"sessionWhiteList_description": {
|
|
||||||
"message": "Domänen oder URLs, die die <canvas>-API in der aktuellen Sitzung verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt werden.",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"sessionWhiteList_title": {
|
"sessionWhiteList_title": {
|
||||||
"message": "Sitzungs-Whitelist",
|
"message": "Sitzungs-Whitelist",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"sessionWhiteList_description": {
|
||||||
|
"message": "Domänen oder URLs, die die <canvas>-API in der aktuellen Sitzung verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt werden.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"whitelistDomainTemporarily": {
|
"whitelistDomainTemporarily": {
|
||||||
"message": "erlaube Domain übergangsweise",
|
"message": "erlaube Domain übergangsweise",
|
||||||
@ -870,6 +890,24 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"protectDOMRect_title": {
|
||||||
|
"message": "DOMRect-API beschützen",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"protectDOMRect_description": {
|
||||||
|
"message": "Beschützt vor dem \"getClientRects()\" Fingerprint und einigen anderen ähnlichen Methoden.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
"domRectIntegerFactor_title": {
|
||||||
|
"message": "DOMRect Ganzzahlfaktor",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"domRectIntegerFactor_description": {
|
||||||
|
"message": "Ein Bruchteil eines Pixels kann durch CSS kontrolliert werden. Eigenschaften eines DOMRect, die multipliziert mit diesem Faktor eine ganze Zahl ergeben, dürfen nicht verändert werden um eine Detektion zu verhindern.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"theme_title": {
|
"theme_title": {
|
||||||
"message": "Theme",
|
"message": "Theme",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
@ -105,6 +105,10 @@
|
|||||||
"message": "Window API",
|
"message": "Window API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"section_DOMRect-api":{
|
||||||
|
"message": "DOMRect API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"displayAdvancedSettings_title": {
|
"displayAdvancedSettings_title": {
|
||||||
"message": "Expert mode",
|
"message": "Expert mode",
|
||||||
@ -182,11 +186,11 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForAudioInputPermission": {
|
"askForAudioInputPermission": {
|
||||||
"message": "Do you want to allow audio-API input?",
|
"message": "Do you want to allow audio API input?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForAudioReadoutPermission": {
|
"askForAudioReadoutPermission": {
|
||||||
"message": "Do you want to allow audio readout?",
|
"message": "Do you want to allow audio API readout?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForHistoryPermission": {
|
"askForHistoryPermission": {
|
||||||
@ -194,11 +198,11 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForHistoryInputPermission": {
|
"askForHistoryInputPermission": {
|
||||||
"message": "Do you want to allow history-API input?",
|
"message": "Do you want to allow history API input?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForHistoryReadoutPermission": {
|
"askForHistoryReadoutPermission": {
|
||||||
"message": "Do you want to allow history readout?",
|
"message": "Do you want to allow history API readout?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForWindowPermission": {
|
"askForWindowPermission": {
|
||||||
@ -206,11 +210,23 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForWindowInputPermission": {
|
"askForWindowInputPermission": {
|
||||||
"message": "Do you want to allow window-API input?",
|
"message": "Do you want to allow window API input?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askForWindowReadoutPermission": {
|
"askForWindowReadoutPermission": {
|
||||||
"message": "Do you want to allow window readout?",
|
"message": "Do you want to allow window API readout?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForDOMRectPermission": {
|
||||||
|
"message": "Do you want to allow the DOMRect API?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForDOMRectInputPermission": {
|
||||||
|
"message": "Do you want to allow DOMRect API input?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForDOMRectReadoutPermission": {
|
||||||
|
"message": "Do you want to allow DOMRect API readout?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askOnlyOnce_title": {
|
"askOnlyOnce_title": {
|
||||||
@ -544,6 +560,10 @@
|
|||||||
"message": "Faked window readout on {url}",
|
"message": "Faked window readout on {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"fakedDOMRectReadout": {
|
||||||
|
"message": "Faked DOMRect readout on {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"fakedInput": {
|
"fakedInput": {
|
||||||
"message": "Faked at input on {url}",
|
"message": "Faked at input on {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -869,6 +889,24 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"protectDOMRect_title": {
|
||||||
|
"message": "Protect DOMRect API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"protectDOMRect_description": {
|
||||||
|
"message": "This protects against the \"getClientRects()\" fingerprinting and several similar methods.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
"domRectIntegerFactor_title": {
|
||||||
|
"message": "DOMRect integer factor",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"domRectIntegerFactor_description": {
|
||||||
|
"message": "Some fraction of a pixel can be controlled by CSS. To prevent detection values of a DOMRect that multiplied with this factor are integers will not be altered.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"theme_title": {
|
"theme_title": {
|
||||||
"message": "Theme",
|
"message": "Theme",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
@ -100,7 +100,13 @@
|
|||||||
forEachFunction(function({name, object}){
|
forEachFunction(function({name, object}){
|
||||||
var map = originalPropertyDescriptors[name] || new WeakMap();
|
var map = originalPropertyDescriptors[name] || new WeakMap();
|
||||||
originalPropertyDescriptors[name] = map;
|
originalPropertyDescriptors[name] = map;
|
||||||
map.set(object, Object.getOwnPropertyDescriptor(object, name));
|
|
||||||
|
const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||||
|
if (!originalPropertyDescriptor){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.set(object, originalPropertyDescriptor);
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
object,
|
object,
|
||||||
name,
|
name,
|
||||||
@ -145,11 +151,14 @@
|
|||||||
if (preIntercepted){
|
if (preIntercepted){
|
||||||
preIntercepted = false;
|
preIntercepted = false;
|
||||||
forEachFunction(function({name, object}){
|
forEachFunction(function({name, object}){
|
||||||
|
const originalPropertyDescriptor = originalPropertyDescriptors[name].get(object);
|
||||||
|
if (originalPropertyDescriptor){
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
object,
|
object,
|
||||||
name,
|
name,
|
||||||
originalPropertyDescriptors[name].get(object)
|
originalPropertyDescriptor
|
||||||
);
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -286,6 +295,7 @@
|
|||||||
var original = constructor.prototype[name];
|
var original = constructor.prototype[name];
|
||||||
const checker = generateChecker(name, changedFunction, siteStatus, original);
|
const checker = generateChecker(name, changedFunction, siteStatus, original);
|
||||||
var descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, name);
|
var descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, name);
|
||||||
|
if (descriptor){
|
||||||
if (descriptor.hasOwnProperty("value")){
|
if (descriptor.hasOwnProperty("value")){
|
||||||
if (changedFunction.fakeGenerator){
|
if (changedFunction.fakeGenerator){
|
||||||
descriptor.value = exportFunction(
|
descriptor.value = exportFunction(
|
||||||
@ -307,6 +317,7 @@
|
|||||||
}
|
}
|
||||||
Object.defineProperty(constructor.prototype, name, descriptor);
|
Object.defineProperty(constructor.prototype, name, descriptor);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -319,14 +330,14 @@
|
|||||||
const object = objectGetter(getWrapped(window));
|
const object = objectGetter(getWrapped(window));
|
||||||
if (object){
|
if (object){
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||||
if (descriptor.hasOwnProperty("get")){
|
if (descriptor && descriptor.hasOwnProperty("get")){
|
||||||
var original = descriptor.get;
|
var original = descriptor.get;
|
||||||
const checker = generateChecker(name, changedGetter, siteStatus, original);
|
const checker = generateChecker(name, changedGetter, siteStatus, original);
|
||||||
const getter = changedGetter.getterGenerator(checker);
|
const getter = changedGetter.getterGenerator(checker);
|
||||||
descriptor.get = exportFunction(getter, window);
|
descriptor.get = exportFunction(getter, window);
|
||||||
|
|
||||||
if (changedGetter.setterGenerator){
|
if (descriptor.hasOwnProperty("set") && changedGetter.setterGenerator){
|
||||||
const setter = changedGetter.setterGenerator(window, descriptor.set);
|
const setter = changedGetter.setterGenerator(window, descriptor.set, prefs);
|
||||||
descriptor.set = exportFunction(setter, window);
|
descriptor.set = exportFunction(setter, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
const getWrapped = require("sdk/getWrapped");
|
const getWrapped = require("sdk/getWrapped");
|
||||||
const {hasType, checkerWrapper} = require("./modifiedAPIFunctions");
|
const {hasType, checkerWrapper} = require("./modifiedAPIFunctions");
|
||||||
const modifiedAudioAPI = require("./modifiedAudioAPI");
|
const modifiedAudioAPI = require("./modifiedAudioAPI");
|
||||||
|
const modifiedDOMRectAPI = require("./modifiedDOMRectAPI");
|
||||||
|
|
||||||
var randomSupply = null;
|
var randomSupply = null;
|
||||||
|
|
||||||
@ -155,6 +156,7 @@
|
|||||||
scope.setRandomSupply = function(supply){
|
scope.setRandomSupply = function(supply){
|
||||||
randomSupply = supply;
|
randomSupply = supply;
|
||||||
modifiedAudioAPI.setRandomSupply(supply);
|
modifiedAudioAPI.setRandomSupply(supply);
|
||||||
|
modifiedDOMRectAPI.setRandomSupply(supply);
|
||||||
};
|
};
|
||||||
var canvasContextType = new WeakMap();
|
var canvasContextType = new WeakMap();
|
||||||
// changed functions and their fakes
|
// changed functions and their fakes
|
||||||
@ -488,4 +490,5 @@
|
|||||||
appendModified(modifiedAudioAPI);
|
appendModified(modifiedAudioAPI);
|
||||||
appendModified(require("./modifiedHistoryAPI"));
|
appendModified(require("./modifiedHistoryAPI"));
|
||||||
appendModified(require("./modifiedWindowAPI"));
|
appendModified(require("./modifiedWindowAPI"));
|
||||||
|
appendModified(modifiedDOMRectAPI);
|
||||||
}());
|
}());
|
414
lib/modifiedDOMRectAPI.js
Normal file
414
lib/modifiedDOMRectAPI.js
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
/* 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";
|
||||||
|
|
||||||
|
var scope;
|
||||||
|
if ((typeof exports) !== "undefined"){
|
||||||
|
scope = exports;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.scope.modifiedDOMRectAPI = {};
|
||||||
|
scope = window.scope.modifiedDOMRectAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {hasType, checkerWrapper} = require("./modifiedAPIFunctions");
|
||||||
|
const {md5String: hash} = require("./hash");
|
||||||
|
const getWrapped = require("sdk/getWrapped");
|
||||||
|
|
||||||
|
|
||||||
|
var randomSupply = null;
|
||||||
|
scope.setRandomSupply = function(supply){
|
||||||
|
randomSupply = supply;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cache = new Map();
|
||||||
|
function getHash(domRect){
|
||||||
|
return hash(new Float64Array([domRect.x, domRect.y, domRect.width, domRect.height]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const registeredRects = new WeakMap();
|
||||||
|
function registerDOMRect(domRect, notify){
|
||||||
|
registeredRects.set(getWrapped(domRect), {
|
||||||
|
notify: function(){
|
||||||
|
let done = false;
|
||||||
|
return function(message){
|
||||||
|
if (!done){
|
||||||
|
done = true;
|
||||||
|
notify(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getDOMRectRegistration(domRect){
|
||||||
|
return registeredRects.get(getWrapped(domRect));
|
||||||
|
}
|
||||||
|
function getFakeDomRect(window, domRect, prefs, notify){
|
||||||
|
|
||||||
|
var rng = randomSupply.getRng(4, window);
|
||||||
|
function getFakeValue(value, i){
|
||||||
|
if ((value * prefs("domRectIntegerFactor", window.location)) % 1 === 0){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return value + 0.01 * (rng(i) / 0xffffffff - 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const hash = getHash(domRect);
|
||||||
|
let cached = cache.get(hash);
|
||||||
|
if (!cached){
|
||||||
|
notify("fakedDOMRectReadout");
|
||||||
|
cached = new domRect.constructor(
|
||||||
|
getFakeValue(domRect.x, 0),
|
||||||
|
getFakeValue(domRect.y, 1),
|
||||||
|
getFakeValue(domRect.width, 2),
|
||||||
|
getFakeValue(domRect.height, 3)
|
||||||
|
);
|
||||||
|
cache.set(getHash(cached), cached);
|
||||||
|
}
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.changedFunctions = {
|
||||||
|
getClientRects: {
|
||||||
|
type: "readout",
|
||||||
|
api: "domRect",
|
||||||
|
getStatus: getStatus,
|
||||||
|
object: ["Range", "Element"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getClientRects(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
var {prefs, notify, window, original} = check;
|
||||||
|
var ret = original.apply(this, window.Array.from(args));
|
||||||
|
for (let i = 0; i < ret.length; i += 1){
|
||||||
|
registerDOMRect(ret[i], notify);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getBoundingClientRect: {
|
||||||
|
type: "readout",
|
||||||
|
api: "domRect",
|
||||||
|
getStatus: getStatus,
|
||||||
|
object: ["Range", "Element"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getBoundingClientRect(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
var {prefs, notify, window, original} = check;
|
||||||
|
var ret = original.apply(this, window.Array.from(args));
|
||||||
|
registerDOMRect(ret, notify);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getBounds: {
|
||||||
|
type: "readout",
|
||||||
|
api: "domRect",
|
||||||
|
getStatus: getStatus,
|
||||||
|
object: ["DOMQuad"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getBounds(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
var {prefs, notify, window, original} = check;
|
||||||
|
var ret = original.apply(this, window.Array.from(args));
|
||||||
|
registerDOMRect(ret, notify);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getBBox: {
|
||||||
|
type: "readout",
|
||||||
|
api: "domRect",
|
||||||
|
getStatus: getStatus,
|
||||||
|
object: ["SVGGraphicsElement"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getBBox(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
var {prefs, notify, window, original} = check;
|
||||||
|
var ret = original.apply(this, window.Array.from(args));
|
||||||
|
registerDOMRect(ret, notify);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getExtentOfChar: {
|
||||||
|
type: "readout",
|
||||||
|
api: "domRect",
|
||||||
|
getStatus: getStatus,
|
||||||
|
object: ["SVGTextContentElement"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
return function getBBox(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
var {prefs, notify, window, original} = check;
|
||||||
|
var ret = original.apply(this, window.Array.from(args));
|
||||||
|
registerDOMRect(ret, notify);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function createCheckerCallback(property){
|
||||||
|
return function(args, check){
|
||||||
|
const {prefs, notify, window, original} = check;
|
||||||
|
const originalValue = original.apply(this, window.Array.from(args));
|
||||||
|
if (prefs("protectDOMRect", window.location)){
|
||||||
|
const registration = getDOMRectRegistration(this);
|
||||||
|
if (registration){
|
||||||
|
return getFakeDomRect(window, this, prefs, registration.notify)[property];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return originalValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function setProperty(domRect, window, original, newValue, property, prefs){ // eslint-disable-line max-params
|
||||||
|
const registration = getDOMRectRegistration(domRect);
|
||||||
|
if (registration){
|
||||||
|
const fakeDomRect = getFakeDomRect(window, domRect, prefs, registration.notify);
|
||||||
|
registeredRects.delete(getWrapped(domRect));
|
||||||
|
["x", "y", "width", "height"].forEach(function(prop){
|
||||||
|
if (prop === property){
|
||||||
|
domRect[prop] = newValue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
domRect[prop] = fakeDomRect[prop];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
original.apply(domRect, window.Array.from(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.changedGetters = [
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRect.prototype;},
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "x",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get x(){
|
||||||
|
return checkerWrapper(checker, this, arguments, createCheckerCallback("x"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "x").get;
|
||||||
|
},
|
||||||
|
setterGenerator: function(window, original, prefs){
|
||||||
|
const temp = {
|
||||||
|
set x(x){
|
||||||
|
setProperty(this, window, original, x, "x", prefs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "x").set;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRect.prototype;},
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "y",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get y(){
|
||||||
|
return checkerWrapper(checker, this, arguments, createCheckerCallback("y"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "y").get;
|
||||||
|
},
|
||||||
|
setterGenerator: function(window, original, prefs){
|
||||||
|
const temp = {
|
||||||
|
set y(y){
|
||||||
|
setProperty(this, window, original, y, "y", prefs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "y").set;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRect.prototype;},
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "width",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get width(){
|
||||||
|
return checkerWrapper(checker, this, arguments, createCheckerCallback("width"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "width").get;
|
||||||
|
},
|
||||||
|
setterGenerator: function(window, original, prefs){
|
||||||
|
const temp = {
|
||||||
|
set width(width){
|
||||||
|
setProperty(this, window, original, width, "width", prefs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "width").set;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRect.prototype;},
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "height",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get height(){
|
||||||
|
return checkerWrapper(checker, this, arguments, createCheckerCallback("height"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "height").get;
|
||||||
|
},
|
||||||
|
setterGenerator: function(window, original, prefs){
|
||||||
|
const temp = {
|
||||||
|
set height(height){
|
||||||
|
setProperty(this, window, original, height, "height", prefs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "height").set;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "left",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const callback = createCheckerCallback("left");
|
||||||
|
const temp = {
|
||||||
|
get left(){
|
||||||
|
return checkerWrapper(checker, this, arguments, callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "left").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "right",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get right(){
|
||||||
|
return checkerWrapper(checker, this, arguments, createCheckerCallback("right"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "right").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "top",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get top(){
|
||||||
|
return checkerWrapper(checker, this, arguments, createCheckerCallback("top"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "top").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.DOMRectReadOnly.prototype;}
|
||||||
|
],
|
||||||
|
name: "bottom",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get bottom(){
|
||||||
|
return checkerWrapper(checker, this, arguments, createCheckerCallback("bottom"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "bottom").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.IntersectionObserverEntry.prototype;}
|
||||||
|
],
|
||||||
|
name: "intersectionRect",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get intersectionRect(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
const {prefs, notify, window, original} = check;
|
||||||
|
const originalValue = original.apply(this, window.Array.from(args));
|
||||||
|
registerDOMRect(originalValue, notify);
|
||||||
|
return originalValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "intersectionRect").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.IntersectionObserverEntry.prototype;}
|
||||||
|
],
|
||||||
|
name: "boundingClientRect",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get boundingClientRect(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
const {prefs, notify, window, original} = check;
|
||||||
|
const originalValue = original.apply(this, window.Array.from(args));
|
||||||
|
registerDOMRect(originalValue, notify);
|
||||||
|
return originalValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "boundingClientRect").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [
|
||||||
|
function(window){return window.IntersectionObserverEntry.prototype;}
|
||||||
|
],
|
||||||
|
name: "rootBounds",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get rootBounds(){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
const {prefs, notify, window, original} = check;
|
||||||
|
const originalValue = original.apply(this, window.Array.from(args));
|
||||||
|
registerDOMRect(originalValue, notify);
|
||||||
|
return originalValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "rootBounds").get;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
function getStatus(obj, status, prefs){
|
||||||
|
status = Object.create(status);
|
||||||
|
status.active = prefs("protectDOMRect", status.url) && hasType(status, "readout");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.changedGetters.forEach(function(changedGetter){
|
||||||
|
changedGetter.type = "readout";
|
||||||
|
changedGetter.getStatus = getStatus;
|
||||||
|
changedGetter.api = "domRect";
|
||||||
|
});
|
||||||
|
}());
|
@ -95,6 +95,15 @@
|
|||||||
{name: "Window-API", level: 1},
|
{name: "Window-API", level: 1},
|
||||||
"opener",
|
"opener",
|
||||||
"name",
|
"name",
|
||||||
|
{name: "DOMRect-API", level: 1},
|
||||||
|
"getClientRects",
|
||||||
|
"getBoundingClientRect",
|
||||||
|
"getBounds",
|
||||||
|
"getBBox",
|
||||||
|
"getExtentOfChar",
|
||||||
|
"intersectionRect",
|
||||||
|
"boundingClientRect",
|
||||||
|
"rootBounds",
|
||||||
],
|
],
|
||||||
defaultKeyValue: false
|
defaultKeyValue: false
|
||||||
},
|
},
|
||||||
@ -195,6 +204,7 @@
|
|||||||
"audio",
|
"audio",
|
||||||
"history",
|
"history",
|
||||||
"window",
|
"window",
|
||||||
|
"DOMRect",
|
||||||
],
|
],
|
||||||
defaultKeyValue: false
|
defaultKeyValue: false
|
||||||
},
|
},
|
||||||
@ -252,6 +262,15 @@
|
|||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
urlSpecific: true
|
urlSpecific: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "protectDOMRect",
|
||||||
|
defaultValue: true,
|
||||||
|
urlSpecific: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "domRectIntegerFactor",
|
||||||
|
defaultValue: 4
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "blockDataURLs",
|
name: "blockDataURLs",
|
||||||
defaultValue: true
|
defaultValue: true
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
"lib/modifiedAudioAPI.js",
|
"lib/modifiedAudioAPI.js",
|
||||||
"lib/modifiedHistoryAPI.js",
|
"lib/modifiedHistoryAPI.js",
|
||||||
"lib/modifiedWindowAPI.js",
|
"lib/modifiedWindowAPI.js",
|
||||||
|
"lib/modifiedDOMRectAPI.js",
|
||||||
"lib/modifiedAPI.js",
|
"lib/modifiedAPI.js",
|
||||||
"lib/randomSupplies.js",
|
"lib/randomSupplies.js",
|
||||||
"lib/intercept.js",
|
"lib/intercept.js",
|
||||||
|
@ -404,6 +404,20 @@
|
|||||||
"displayAdvancedSettings": [true]
|
"displayAdvancedSettings": [true]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"DOMRect-API",
|
||||||
|
{
|
||||||
|
"name": "protectDOMRect",
|
||||||
|
"displayDependencies": {
|
||||||
|
"displayAdvancedSettings": [true]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "domRectIntegerFactor",
|
||||||
|
"displayDependencies": {
|
||||||
|
"protectDOMRect": [true],
|
||||||
|
"displayAdvancedSettings": [true]
|
||||||
|
}
|
||||||
|
},
|
||||||
"misc",
|
"misc",
|
||||||
{
|
{
|
||||||
"name": "theme"
|
"name": "theme"
|
||||||
|
@ -4,6 +4,7 @@ Version 0.5.4:
|
|||||||
|
|
||||||
new features:
|
new features:
|
||||||
- added save/load directly to/from file option
|
- added save/load directly to/from file option
|
||||||
|
- added protection for DOMRect (getClientRects)
|
||||||
|
|
||||||
fixes:
|
fixes:
|
||||||
- window and audio API were always blocked when using any of the "block ..." modes
|
- window and audio API were always blocked when using any of the "block ..." modes
|
||||||
|
@ -177,6 +177,16 @@ addTest("property descriptor", function(log){
|
|||||||
configurable: true
|
configurable: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
object: Element.prototype,
|
||||||
|
name: "getClientRects",
|
||||||
|
descriptor: {
|
||||||
|
value: function getClientRects(){},
|
||||||
|
writable: true,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
}
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return properties.reduce(function(pass, property){
|
return properties.reduce(function(pass, property){
|
||||||
@ -420,3 +430,90 @@ addTest("window name change", function(log){
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function checkDOMRectData(rect, data, log){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var detected = false;
|
||||||
|
["x", "y", "width", "height"].forEach(function(property){
|
||||||
|
if (data[property] !== rect[property]){
|
||||||
|
log("Wrong value for", property, ":", data[property], "!=", rect[property]);
|
||||||
|
detected = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRectByData(data){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.style.cssText = "position: fixed;" +
|
||||||
|
"left: " + data.x + "px; " +
|
||||||
|
"top: " + data.y + "px; " +
|
||||||
|
"width: " + data.width + "px; " +
|
||||||
|
"height: " + data.height + "px;";
|
||||||
|
|
||||||
|
document.body.appendChild(el);
|
||||||
|
var rect = el.getBoundingClientRect();
|
||||||
|
document.body.removeChild(el);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
addTest("self created DOMRect", function(log){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
x: Math.PI,
|
||||||
|
y: Math.E,
|
||||||
|
width: Math.LOG10E,
|
||||||
|
height: Math.LOG2E
|
||||||
|
};
|
||||||
|
var rect = new DOMRect(data.x, data.y, data.width, data.height);
|
||||||
|
return checkDOMRectData(rect, data, log);
|
||||||
|
});
|
||||||
|
|
||||||
|
addTest("known DOMRect", function(log){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
x: 1 + 1/4,
|
||||||
|
y: 2,
|
||||||
|
width: 3,
|
||||||
|
height: 4
|
||||||
|
};
|
||||||
|
|
||||||
|
var rect = getRectByData(data);
|
||||||
|
|
||||||
|
return checkDOMRectData(rect, data, log);
|
||||||
|
});
|
||||||
|
addTest("changed DOMRect", function(log){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
x: Math.PI,
|
||||||
|
y: 2,
|
||||||
|
width: 3,
|
||||||
|
height: 4
|
||||||
|
};
|
||||||
|
|
||||||
|
var rect = getRectByData(data);
|
||||||
|
rect.x = Math.PI;
|
||||||
|
|
||||||
|
return checkDOMRectData(rect, data, log);
|
||||||
|
});
|
||||||
|
addTest("recreated DOMRect", function(log){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
x: Math.PI,
|
||||||
|
y: Math.E,
|
||||||
|
width: Math.LOG10E,
|
||||||
|
height: Math.LOG2E
|
||||||
|
};
|
||||||
|
|
||||||
|
var rect = getRectByData(data);
|
||||||
|
var rect2 = getRectByData(rect);
|
||||||
|
|
||||||
|
return checkDOMRectData(rect2, rect, log);
|
||||||
|
});
|
42
test/domRectIFrame.html
Normal file
42
test/domRectIFrame.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<style>
|
||||||
|
#inside{
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
color:#5B5B5B;
|
||||||
|
position: absolute;
|
||||||
|
padding: 1.3333px;
|
||||||
|
left: 10.5555px;
|
||||||
|
top: 28.4444px;
|
||||||
|
font-size: 24.5555px;
|
||||||
|
|
||||||
|
-ms-transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);
|
||||||
|
-moz-transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);
|
||||||
|
-webkit-transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);
|
||||||
|
transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);
|
||||||
|
|
||||||
|
-ms-transform-origin: 0.1111px 0.2222px 0.3333px;
|
||||||
|
-moz-transform-origin: 0.1111px 0.2222px 0.3333px;
|
||||||
|
-webkit-transform-origin: 0.1111px 0.2222px 0.3333px;
|
||||||
|
transform-origin: 0.1111px 0.2222px 0.3333px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="inside">
|
||||||
|
<h1 id="rect0">https://browserleaks.com<i>/rects</i></h4>
|
||||||
|
<span id="rect1"><strong>Element.getClientRects (̿▀̿ ̿Ĺ̯̿̿▀̿ ̿)̄ </strong></span><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<span id="rect2">F i n g e r p r i n t i n g ?</span>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
42
test/domRectTest.html
Normal file
42
test/domRectTest.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>DOMRect test</title>
|
||||||
|
<style>
|
||||||
|
#iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: -2000%;
|
||||||
|
}
|
||||||
|
.template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>DOMRect test</h1>
|
||||||
|
<iframe id="iframe" src="domRectIFrame.html"></iframe>
|
||||||
|
<div id="tests">
|
||||||
|
<div class="test">
|
||||||
|
<h2 class="title"></h2>
|
||||||
|
Hash: <span class="hash"></span><br>
|
||||||
|
Data: <span class="data"></span><br>
|
||||||
|
<button>refresh</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="domRectTest.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
78
test/domRectTest.js
Normal file
78
test/domRectTest.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
(function(){
|
||||||
|
"use strict";
|
||||||
|
function byteArrayToHex(arrayBuffer){
|
||||||
|
var 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("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = document.getElementById("tests");
|
||||||
|
const iframe = document.getElementById("iframe");
|
||||||
|
const template = document.querySelector(".test");
|
||||||
|
template.parentElement.removeChild(template);
|
||||||
|
|
||||||
|
function getElements(){
|
||||||
|
const doc = iframe.contentDocument;
|
||||||
|
|
||||||
|
return Array.from(doc.querySelectorAll("*[id^=rect]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTest(title, callback){
|
||||||
|
const properties = ["x", "y", "width", "height", "top", "left", "right", "bottom"];
|
||||||
|
function performTest(){
|
||||||
|
const rects = getElements().map(callback);
|
||||||
|
const data = new Float64Array(rects.length * properties.length);
|
||||||
|
rects.forEach(function(rect, i){
|
||||||
|
properties.forEach(function(property, j){
|
||||||
|
data[i * properties.length + j] = rect[property];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.subtle.digest("SHA-256", data)
|
||||||
|
.then(function(hash){
|
||||||
|
output.querySelector(".hash").textContent = byteArrayToHex(hash);
|
||||||
|
});
|
||||||
|
|
||||||
|
output.querySelector(".data").innerHTML = "<table><tr><th></th>" +
|
||||||
|
rects.map(function(rect, i){
|
||||||
|
return "<th>rect " + (i + 1) + "</th>";
|
||||||
|
}).join("") +
|
||||||
|
"</tr>" +
|
||||||
|
properties.map(function(property){
|
||||||
|
return "<tr><th>" + property + "</th>" + rects.map(function(rect, i){
|
||||||
|
return "<td>" + rect[property] + "</td>";
|
||||||
|
}).join("") + "</tr>";
|
||||||
|
}).join("") +
|
||||||
|
"</table>";
|
||||||
|
|
||||||
|
}
|
||||||
|
const output = template.cloneNode(true);
|
||||||
|
output.querySelector(".title").textContent = title;
|
||||||
|
output.querySelector("button").addEventListener("click", performTest);
|
||||||
|
|
||||||
|
container.appendChild(output);
|
||||||
|
performTest();
|
||||||
|
}
|
||||||
|
iframe.addEventListener("load", function(){
|
||||||
|
createTest("Element.getClientRects", function(element){
|
||||||
|
return element.getClientRects()[0];
|
||||||
|
});
|
||||||
|
createTest("Element.getBoundingClientRect", function(element){
|
||||||
|
return element.getBoundingClientRect();
|
||||||
|
});
|
||||||
|
createTest("Range.getClientRects", function(element){
|
||||||
|
var range = document.createRange();
|
||||||
|
range.selectNode(element);
|
||||||
|
return range.getClientRects()[0];
|
||||||
|
});
|
||||||
|
createTest("Range.getBoundingClientRect", function(element){
|
||||||
|
var range = document.createRange();
|
||||||
|
range.selectNode(element);
|
||||||
|
return range.getBoundingClientRect();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}());
|
@ -10,6 +10,7 @@
|
|||||||
<li><a href="test.html">Fingerprinting test</a></li>
|
<li><a href="test.html">Fingerprinting test</a></li>
|
||||||
<li><a href="dataUrlTest.php">Data-URL test</a></li>
|
<li><a href="dataUrlTest.php">Data-URL test</a></li>
|
||||||
<li><a href="audioTest.html">Audio Fingerprint test</a></li>
|
<li><a href="audioTest.html">Audio Fingerprint test</a></li>
|
||||||
|
<li><a href="domRectTest.html">DOMRect Fingerprint 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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user