1
0
mirror of https://github.com/kkapsner/CanvasBlocker synced 2024-12-22 04:40:20 +01:00

Big linting

This commit is contained in:
kkapsner 2019-11-28 01:26:35 +01:00
parent b5e6d049ce
commit aef6bd3d59
58 changed files with 2074 additions and 1856 deletions

View File

@ -1,40 +1,68 @@
{ {
"env": { "env": {
"browser": true, "browser": true,
"commonjs": true, "commonjs": true,
"es6": true, "es6": true,
"webextensions": true "webextensions": true
}, },
"parserOptions": { "parserOptions": {
"ecmaFeatures": { "ecmaFeatures": {
"jsx": true "jsx": true
}, },
"sourceType": "script" "sourceType": "script"
}, },
"extends": "eslint:recommended", "plugins": ["promise", "eslint-comments"],
"globals": { "extends": [
"exportFunction": false "eslint:recommended",
}, "plugin:promise/recommended",
"rules": { "plugin:eslint-comments/recommended"
"brace-style": ["error", "stroustrup", {"allowSingleLine": true}], ],
"comma-spacing": ["error", { "before": false, "after": true }], "globals": {
"constructor-super": "warn", "exportFunction": false
"eqeqeq": "error", },
"max-len": ["warn", {"code": 120, "tabWidth": 4}], "rules": {
"max-lines": ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}], "brace-style": ["error", "stroustrup", {"allowSingleLine": true}],
"max-params": ["warn", 4], "comma-spacing": ["error", { "before": false, "after": true }],
"no-const-assign": "warn", "complexity": ["warn", 20],
"no-this-before-super": "warn", "constructor-super": "warn",
"no-undef": "error", "eqeqeq": "error",
"no-unreachable": "warn", "eslint-comments/no-use": ["error", {"allow": ["eslint-disable-next-line"]}],
"no-unused-vars": "off", "indent": ["error", "tab", {"SwitchCase": 1}],
"no-trailing-spaces": ["error", {"skipBlankLines": true}], "max-depth": ["warn", 4],
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"], "max-len": ["warn", {"code": 120, "tabWidth": 4}],
"indent": ["error", "tab", {"SwitchCase": 1}], "max-lines-per-function": ["warn", {"max": 80,"skipBlankLines": true, "skipComments": true}],
"space-in-parens": ["error", "never"], "max-lines": ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}],
"valid-typeof": "warn", "max-params": ["warn", 4],
"quotes": ["error", "double"], "no-console": "error",
"semi": ["error", "always"], "no-const-assign": "error",
"strict": ["error", "function"] "no-inner-declarations": "warn",
} "no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
"no-prototype-builtins": "off",
"no-this-before-super": "warn",
"no-trailing-spaces": ["error", {"skipBlankLines": true}],
"no-undef": "error",
"no-unreachable": "warn",
"no-unused-vars": "off",
"no-use-before-define": ["error", {"functions": false}],
"no-var": "error",
"quotes": ["error", "double"],
"semi": ["error", "always"],
"space-in-parens": ["error", "never"],
"strict": ["error", "function"],
"valid-typeof": "warn"
},
"overrides": [
{
"files": ["detectionTest.js", "modifiedCanvasAPI.js", "options.js", "settingsDisplay.js"],
"rules": {
"max-lines": "off"
}
},
{
"files": ["test/*.js"],
"rules": {
"no-var": "off"
}
}
]
} }

View File

@ -11,7 +11,7 @@
logging.message("Opened browser action"); logging.message("Opened browser action");
settings.onloaded(function(){ settings.onloaded(function(){
var actions = document.getElementById("actions"); const actions = document.getElementById("actions");
[ [
{ {
@ -54,10 +54,10 @@
logging.verbose("Hiding advanced action"); logging.verbose("Hiding advanced action");
return; return;
} }
var actionButton = document.createElement("button"); const actionButton = document.createElement("button");
actionButton.className = "action"; actionButton.className = "action";
var icon = document.createElement("span"); const icon = document.createElement("span");
icon.className = "icon"; icon.className = "icon";
icon.style.maskImage = "url(" + action.icon + ")"; icon.style.maskImage = "url(" + action.icon + ")";
@ -72,7 +72,7 @@
actions.appendChild(actionButton); actions.appendChild(actionButton);
}); });
var search = document.createElement("input"); const search = document.createElement("input");
search.placeholder = extension.getTranslation("search"); search.placeholder = extension.getTranslation("search");
search.className = "search action"; search.className = "search action";
actions.appendChild(search); actions.appendChild(search);

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -15,15 +15,15 @@
// Check canvas appearance // Check canvas appearance
function canvasAppearance(window, api, context){ function canvasAppearance(window, api, context){
var oldBorder = false; let oldBorder = false;
var canvas = false; let canvas = false;
var inDOM = null; let inDOM = null;
if (api === "canvas" && context){ if (api === "canvas" && context){
var nodeName; let nodeName;
try { try {
nodeName = context.nodeName; nodeName = context.nodeName;
} }
catch (e){ catch (error){
nodeName = ""; nodeName = "";
} }
if (nodeName === "CANVAS"){ if (nodeName === "CANVAS"){
@ -45,17 +45,17 @@
canvas: canvas, canvas: canvas,
askCategory: canvas? (inDOM? "visible": "invisible"): (api === "canvas"? "nocanvas": api), askCategory: canvas? (inDOM? "visible": "invisible"): (api === "canvas"? "nocanvas": api),
get text(){ get text(){
var text = canvas? (this.visible? "visible": "invisible"): (api === "canvas"? "nocanvas": api); const text = canvas? (this.visible? "visible": "invisible"): (api === "canvas"? "nocanvas": api);
Object.defineProperty(this, "text", {value: text}); Object.defineProperty(this, "text", {value: text});
return text; return text;
}, },
inDom: inDOM, inDom: inDOM,
get visible(){ get visible(){
var visible = inDOM; let visible = inDOM;
if (inDOM){ if (inDOM){
canvas.scrollIntoView(); canvas.scrollIntoView();
var rect = canvas.getBoundingClientRect(); const rect = canvas.getBoundingClientRect();
var foundEl = window.document.elementFromPoint( const foundEl = window.document.elementFromPoint(
rect.left + rect.width / 2, rect.left + rect.width / 2,
rect.top + rect.height / 2 rect.top + rect.height / 2
); );
@ -72,9 +72,9 @@
}; };
} }
var modes = new WeakMap(); const modes = new WeakMap();
function getAskMode(window, type, _){ function getAskMode(window, type, _){
var mode = modes.get(window); let mode = modes.get(window);
if (mode){ if (mode){
return mode[type]; return mode[type];
} }
@ -132,11 +132,11 @@
} }
scope.ask = function({window, type, api, canvas, errorStack}, {_, prefs}){ scope.ask = function({window, type, api, canvas, errorStack}, {_, prefs}){
var answer; let answer;
var askMode = getAskMode(window, type, _); const askMode = getAskMode(window, type, _);
var askStatus = askMode.askStatus; const askStatus = askMode.askStatus;
var appearance = canvasAppearance(window, api, canvas); const appearance = canvasAppearance(window, api, canvas);
var category = appearance.askCategory; let category = appearance.askCategory;
if (prefs("askOnlyOnce") !== "no" && askStatus.alreadyAsked[category]){ if (prefs("askOnlyOnce") !== "no" && askStatus.alreadyAsked[category]){
// already asked // already asked
appearance.reset(); appearance.reset();
@ -146,7 +146,6 @@
let imgContainer = null; let imgContainer = null;
if (type === "readout" && prefs("showCanvasWhileAsking") && canvas){ if (type === "readout" && prefs("showCanvasWhileAsking") && canvas){
try { try {
let content = canvas.toDataURL();
let document = window.top.document; let document = window.top.document;
imgContainer = document.createElement("div"); imgContainer = document.createElement("div");
imgContainer.style.cssText = ` imgContainer.style.cssText = `
@ -177,12 +176,12 @@
imgContainer.appendChild(img); imgContainer.appendChild(img);
document.body.appendChild(imgContainer); document.body.appendChild(imgContainer);
} }
catch (e){ catch (error){
// unable to read the canvas // unable to read the canvas
} }
} }
// asking // asking
var msg = askMode.askText[appearance.text]; let msg = askMode.askText[appearance.text];
// visible vs invisible is only calculated here correctly // visible vs invisible is only calculated here correctly
category = appearance.text; category = appearance.text;
@ -196,8 +195,8 @@
if (prefs("askOnlyOnce") === "combined"){ if (prefs("askOnlyOnce") === "combined"){
["context", "readout", "input"].forEach(function(type){ ["context", "readout", "input"].forEach(function(type){
var askMode = getAskMode(window, type, _); const askMode = getAskMode(window, type, _);
var askStatus = askMode.askStatus; const askStatus = askMode.askStatus;
askStatus.alreadyAsked[category] = true; askStatus.alreadyAsked[category] = true;
askStatus.answer[category] = answer; askStatus.answer[category] = answer;
}); });

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -16,12 +16,12 @@
const extension = require("./extension"); const extension = require("./extension");
// Translation // Translation
var _ = function(name, replace, translateAPI){ const _ = function(name, replace, translateAPI){
if (!translateAPI){ if (!translateAPI){
translateAPI = extension.getTranslation; translateAPI = extension.getTranslation;
} }
var str = translateAPI(name) || name; let str = translateAPI(name) || name;
if (replace){ if (replace){
// replace generic content in the translation by given parameter // replace generic content in the translation by given parameter
Object.keys(replace).forEach(function(name){ Object.keys(replace).forEach(function(name){
@ -33,7 +33,7 @@
// Stack parsing // Stack parsing
function parseStackEntry(entry){ function parseStackEntry(entry){
var m = /@(.*):(\d*):(\d*)$/.exec(entry) || ["", entry, "--", "--"]; const m = /@(.*):(\d*):(\d*)$/.exec(entry) || ["", entry, "--", "--"];
return { return {
url: m[1], url: m[1],
line: parseInt(m[2], 10), line: parseInt(m[2], 10),
@ -61,13 +61,12 @@
// parse calling stack // parse calling stack
const extensionID = extension.extensionID; const extensionID = extension.extensionID;
function parseErrorStack(errorStack){ function parseErrorStack(errorStack){
var callers = errorStack.trim().split("\n"); const callers = errorStack.trim().split("\n").map(parseStackEntry).filter(function(caller){
callers = callers.map(parseStackEntry).filter(function(caller){
return !caller.url.startsWith(extensionID); return !caller.url.startsWith(extensionID);
}); });
return { return {
toString: function(translateAPI){ toString: function(translateAPI){
var msg = ""; let msg = "";
msg += "\n\n" + _("sourceOutput", undefined, translateAPI) + ": "; msg += "\n\n" + _("sourceOutput", undefined, translateAPI) + ": ";
if (settings.showCompleteCallingStack){ if (settings.showCompleteCallingStack){
msg += callers.reduce(function(stack, c){ msg += callers.reduce(function(stack, c){
@ -82,7 +81,7 @@
}, },
match: function(stackRule){ match: function(stackRule){
if (typeof stackRule.stackPosition !== "undefined"){ if (typeof stackRule.stackPosition !== "undefined"){
var pos = stackRule.stackPosition; let pos = stackRule.stackPosition;
if (pos < 0){ if (pos < 0){
pos += callers.length; pos += callers.length;
} }

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -19,7 +19,7 @@
scope.check = function check({url, errorStack}){ scope.check = function check({url, errorStack}){
url = new URL(url || "about:blank"); url = new URL(url || "about:blank");
var match = checkBoth(errorStack, url, settings.get("blockMode", url)).match( const match = checkBoth(errorStack, url, settings.get("blockMode", url)).match(
/^(block|allow|fake|ask)(|Everything|Internal)$/ /^(block|allow|fake|ask)(|Everything|Internal)$/
); );
if (match){ if (match){
@ -63,7 +63,7 @@
return "allowInternal"; return "allowInternal";
} }
var mode = "block"; let mode = "block";
switch (blockMode){ switch (blockMode){
case "blockEverything": case "blockEverything":
mode = "block"; mode = "block";

View File

@ -5,7 +5,7 @@
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -23,8 +23,8 @@
this.minBoundary.nextColor = this.maxBoundary; this.minBoundary.nextColor = this.maxBoundary;
} }
addColor(r, g, b, a){ addColor(r, g, b, a){
var index = String.fromCharCode(r, g, b, a); const index = String.fromCharCode(r, g, b, a);
var color = this.colors[index]; let color = this.colors[index];
if (!color){ if (!color){
color = { color = {
index, index,
@ -42,10 +42,10 @@
if (color.count > color.nextColor.count){ if (color.count > color.nextColor.count){
// swap colors to remain in right order // swap colors to remain in right order
// a_ -> b_ -> c -> d becomes a_ -> c -> b_ -> d // a_ -> b_ -> c -> d becomes a_ -> c -> b_ -> d
var a_ = color.previousColor; const a_ = color.previousColor;
var b_ = color; const b_ = color;
var c = color.nextColor; const c = color.nextColor;
var d = color.nextColor.nextColor; const d = color.nextColor.nextColor;
a_.nextColor = c; a_.nextColor = c;
c.previousColor = a_; c.previousColor = a_;
@ -59,8 +59,8 @@
} }
getMaxColors(n){ getMaxColors(n){
n = Math.min(n, this.numberOfColors); n = Math.min(n, this.numberOfColors);
var colors = Object.create(null); const colors = Object.create(null);
var current = this.maxBoundary; let current = this.maxBoundary;
for (;n && current;n -= 1){ for (;n && current;n -= 1){
current = current.previousColor; current = current.previousColor;
colors[current.index] = current; colors[current.index] = current;
@ -70,8 +70,8 @@
} }
scope.compute = function computeColorStatistics(rawData){ scope.compute = function computeColorStatistics(rawData){
var statistic = new Statistic(); const statistic = new Statistic();
for (var i = 0, l = rawData.length; i < l; i += 4){ for (let i = 0, l = rawData.length; i < l; i += 4){
statistic.addColor( statistic.addColor(
rawData[i + 0], rawData[i + 0],
rawData[i + 1], rawData[i + 1],
@ -86,10 +86,10 @@
return statistic.numberOfColors > threshold; return statistic.numberOfColors > threshold;
} }
else { else {
var colors = Object.create(null); const colors = Object.create(null);
var count = 0; let count = 0;
for (var i = 0, l = rawData.length; i < l; i += 4){ for (let i = 0, l = rawData.length; i < l; i += 4){
var index = String.fromCharCode( const index = String.fromCharCode(
rawData[i + 0], rawData[i + 0],
rawData[i + 1], rawData[i + 1],
rawData[i + 2], rawData[i + 2],

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -21,6 +21,10 @@
const mainVersion = parseInt(info.version.replace(/\..+/, ""), 10); const mainVersion = parseInt(info.version.replace(/\..+/, ""), 10);
canMergeHeader = mainVersion > 59; canMergeHeader = mainVersion > 59;
blockBlob = mainVersion < 60; blockBlob = mainVersion < 60;
return canMergeHeader;
}).catch(function(){
canMergeHeader = false;
blockBlob = true;
}); });
function setHeader(headers, header){ function setHeader(headers, header){
if (canMergeHeader){ if (canMergeHeader){

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }

View File

@ -14,13 +14,12 @@
const iframeProtection = require("./iframeProtection"); const iframeProtection = require("./iframeProtection");
const logging = require("./logging"); const logging = require("./logging");
const {error, warning, message, notice, verbose, setPrefix: setLogPrefix} = logging; logging.setPrefix("frame script");
setLogPrefix("frame script");
// Variable to "unload" the script // Variable to "unload" the script
var enabled = true; let enabled = true;
message("starting", location.href); logging.message("starting", location.href);
function check(message){ function check(message){
if (enabled){ if (enabled){
@ -72,38 +71,38 @@
} }
computeExtensionSecret(); computeExtensionSecret();
message("open port to background script"); logging.message("open port to background script");
var port = browser.runtime.connect(); const port = browser.runtime.connect();
if (window === window.top){ if (window === window.top){
message("Is top level window -> tab had navigation -> clear page action"); logging.message("Is top level window -> tab had navigation -> clear page action");
port.postMessage({"canvasBlocker-clear-page-action": true}); port.postMessage({"canvasBlocker-clear-page-action": true});
} }
var tabId; let tabId;
port.onMessage.addListener(function(data){ port.onMessage.addListener(function(data){
message("Got data from port", data); logging.message("Got data from port", data);
if (data.hasOwnProperty("tabId")){ if (data.hasOwnProperty("tabId")){
notice("my tab id is", data.tabId); logging.notice("my tab id is", data.tabId);
tabId = data.tabId; tabId = data.tabId;
} }
if (data.hasOwnProperty("cookieStoreId")){ if (data.hasOwnProperty("cookieStoreId")){
notice("my tab cookie store id is", data.cookieStoreId); logging.notice("my tab cookie store id is", data.cookieStoreId);
const {persistent: persistentRnd} = require("./randomSupplies"); const {persistent: persistentRnd} = require("./randomSupplies");
persistentRnd.setCookieStoreId(data.cookieStoreId); persistentRnd.setCookieStoreId(data.cookieStoreId);
} }
const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd"; const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd";
if (data.hasOwnProperty(persistentRndName)){ if (data.hasOwnProperty(persistentRndName)){
const persistentRndValue = data[persistentRndName]; const persistentRndValue = data[persistentRndName];
notice("got persistent random data", persistentRndValue); logging.notice("got persistent random data", persistentRndValue);
const {persistent: persistentRnd} = require("./randomSupplies"); const {persistent: persistentRnd} = require("./randomSupplies");
Object.keys(persistentRndValue).forEach(function(domain){ Object.keys(persistentRndValue).forEach(function(domain){
verbose("random data for", domain, persistentRndValue[domain]); logging.verbose("random data for", domain, persistentRndValue[domain]);
persistentRnd.setDomainRnd(domain, persistentRndValue[domain]); persistentRnd.setDomainRnd(domain, persistentRndValue[domain]);
}); });
} }
}); });
var notifications = []; const notifications = [];
var notificationCounter = {}; const notificationCounter = {};
var sentAPIs = {}; const sentAPIs = {};
function notify(data){ function notify(data){
if (!settings.ignoredAPIs[data.api]){ if (!settings.ignoredAPIs[data.api]){
if (settings.storeNotificationData){ if (settings.storeNotificationData){
@ -128,16 +127,18 @@
} }
var interceptedWindows = new WeakMap(); const interceptedWindows = new WeakMap();
function interceptWindow(window){ function interceptWindow(window){
let wrappedTry;
try { try {
var href = window.location.href; // eslint-disable-next-line no-unused-vars
var wrappedTry = getWrapped(window); const href = window.location.href;
wrappedTry = getWrapped(window);
} }
catch (e){ catch (error){
// we are unable to read the location due to SOP // we are unable to read the location due to SOP
// therefore we also can not intercept anything. // therefore we also can not intercept anything.
notice("NOT intercepting window due to SOP", window); logging.notice("NOT intercepting window due to SOP", window);
return false; return false;
} }
const wrappedWindow = wrappedTry; const wrappedWindow = wrappedTry;
@ -150,12 +151,12 @@
return false; return false;
} }
message("intercepting window", window); logging.message("intercepting window", window);
intercept( intercept(
{subject: window}, {subject: window},
{check, checkStack, ask: askWrapper, notify, prefs} {check, checkStack, ask: askWrapper, notify, prefs}
); );
message("prepare to intercept (i)frames."); logging.message("prepare to intercept (i)frames.");
function interceptAllFrames(){ function interceptAllFrames(){
const currentLength = window.length; const currentLength = window.length;
@ -185,7 +186,7 @@
return true; return true;
} }
message("register listener for messages from background script"); logging.message("register listener for messages from background script");
extension.message.on(function(data){ extension.message.on(function(data){
if (data["canvasBlocker-unload"]){ if (data["canvasBlocker-unload"]){
enabled = false; enabled = false;
@ -194,14 +195,14 @@
data.hasOwnProperty("canvasBlocker-sendNotifications") && data.hasOwnProperty("canvasBlocker-sendNotifications") &&
data["canvasBlocker-sendNotifications"] === tabId data["canvasBlocker-sendNotifications"] === tabId
){ ){
notice("sending notifications:", notifications); logging.notice("sending notifications:", notifications);
extension.message.send({ extension.message.send({
sender: tabId, sender: tabId,
url: window.location.href, url: window.location.href,
"canvasBlocker-notificationCounter": notificationCounter, "canvasBlocker-notificationCounter": notificationCounter,
"canvasBlocker-notifications": notifications "canvasBlocker-notifications": notifications
}); });
notice("notifications sent"); logging.notice("notifications sent");
} }
}); });

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -20,11 +20,11 @@
}; };
scope.sumXor = function(inputByteArray){ scope.sumXor = function(inputByteArray){
var hash = new Uint32Array(4); const hash = new Uint32Array(4);
var sum = new Float64Array(hash.buffer, 8, 1); // const sum = new Float64Array(hash.buffer, 8, 1);
var intView = new Uint32Array(inputByteArray.buffer); const intView = new Uint32Array(inputByteArray.buffer);
var floatView = new Float32Array(inputByteArray.buffer); // const floatView = new Float32Array(inputByteArray.buffer);
var length = intView.length; const length = intView.length;
for (let i = 0; i < length; i += 1){ for (let i = 0; i < length; i += 1){
// sum[0] += floatView[i]; // sum[0] += floatView[i];
hash[0] ^= intView[i]; hash[0] ^= intView[i];
@ -34,11 +34,11 @@
}; };
scope.hashCode = function(inputByteArray){ scope.hashCode = function(inputByteArray){
var hash = new Uint32Array(1); const hash = new Uint32Array(1);
var intView = new Uint32Array(inputByteArray.buffer); const intView = new Uint32Array(inputByteArray.buffer);
var length = intView.length; const length = intView.length;
for (let i = 0; i < length; i += 1){ for (let i = 0; i < length; i += 1){
var v = hash[0]; const v = hash[0];
hash[0] = ((v << 5) - v) + intView[i]; hash[0] = ((v << 5) - v) + intView[i];
} }
return hash; return hash;
@ -81,21 +81,21 @@
return function md5(inputByteArray){ return function md5(inputByteArray){
h.set(hInitial); h.set(hInitial);
var length = inputByteArray.buffer.byteLength; const length = inputByteArray.buffer.byteLength;
var messageBitLength = length * 8; const messageBitLength = length * 8;
// create byte array with length dividable by 64 (512 bit) // create byte array with length dividable by 64 (512 bit)
var neededLength = Math.ceil((length + 1 + 8) / 64) * 64; const neededLength = Math.ceil((length + 1 + 8) / 64) * 64;
var messageByteArray = new Uint8Array(neededLength); const messageByteArray = new Uint8Array(neededLength);
messageByteArray.set(new Uint8Array(inputByteArray.buffer)); messageByteArray.set(new Uint8Array(inputByteArray.buffer));
var view = new DataView(messageByteArray.buffer); const view = new DataView(messageByteArray.buffer);
// append 10...000000 // append 10...000000
messageByteArray[length] = 0x80; messageByteArray[length] = 0x80;
// append size in 64 bit big endian // append size in 64 bit big endian
view.setUint32(neededLength - 8, messageBitLength, true); view.setUint32(neededLength - 8, messageBitLength, true);
for (var i = 0; i < neededLength; i += 64){ for (let i = 0; i < neededLength; i += 64){
for (let j = 0; j < 64; j += 4){ for (let j = 0; j < 64; j += 4){
w[j / 4] = view.getUint32(i + j, true); w[j / 4] = view.getUint32(i + j, true);
} }
@ -118,7 +118,7 @@
temp[4] = (temp[2] ^ (temp[1] | (~ temp[3]))); temp[4] = (temp[2] ^ (temp[1] | (~ temp[3])));
temp[5] = (7*j) % 16; temp[5] = (7*j) % 16;
} }
var temp_ = temp[3]; const temp_ = temp[3];
temp[3] = temp[2]; temp[3] = temp[2];
temp[2] = temp[1]; temp[2] = temp[1];
temp[1] = (leftRotate(temp[0] + temp[4] + k[j] + w[temp[5]], r[j]) + temp[1]); temp[1] = (leftRotate(temp[0] + temp[4] + k[j] + w[temp[5]], r[j]) + temp[1]);
@ -165,14 +165,14 @@
h.set(hInitial); h.set(hInitial);
var length = inputByteArray.buffer.byteLength; const length = inputByteArray.buffer.byteLength;
var messageBitLength = length * 8; const messageBitLength = length * 8;
// create byte array with length dividable by 64 (512 bit) // create byte array with length dividable by 64 (512 bit)
var neededLength = Math.ceil((length + 1 + 8) / 64) * 64; const neededLength = Math.ceil((length + 1 + 8) / 64) * 64;
var messageByteArray = new Uint8Array(neededLength); const messageByteArray = new Uint8Array(neededLength);
messageByteArray.set(new Uint8Array(inputByteArray.buffer)); messageByteArray.set(new Uint8Array(inputByteArray.buffer));
var view = new DataView(messageByteArray.buffer); const view = new DataView(messageByteArray.buffer);
// append 10...000000 // append 10...000000
messageByteArray[length] = 0x80; messageByteArray[length] = 0x80;

View File

@ -19,8 +19,7 @@
return lists.get("white").match(url) || settings.get("blockMode", url).startsWith("allow"); return lists.get("white").match(url) || settings.get("blockMode", url).startsWith("allow");
} }
scope.protect = function protect(window, wrappedWindow, singleCallback, allCallback){ function createChangeProperty(window){
function changeProperty(object, name, type, changed){ function changeProperty(object, name, type, changed){
const descriptor = Object.getOwnPropertyDescriptor(object, name); const descriptor = Object.getOwnPropertyDescriptor(object, name);
const original = descriptor[type]; const original = descriptor[type];
@ -49,7 +48,10 @@
return; return;
} }
} }
return changeProperty;
}
function protectFrameProperties({window, wrappedWindow, changeProperty, singleCallback}){
["HTMLIFrameElement", "HTMLFrameElement"].forEach(function(constructorName){ ["HTMLIFrameElement", "HTMLFrameElement"].forEach(function(constructorName){
const constructor = window[constructorName]; const constructor = window[constructorName];
const wrappedConstructor = wrappedWindow[constructorName]; const wrappedConstructor = wrappedWindow[constructorName];
@ -61,7 +63,7 @@
const originalContentWindowGetter = contentWindowDescriptor.get; const originalContentWindowGetter = contentWindowDescriptor.get;
const contentWindowTemp = { const contentWindowTemp = {
get contentWindow(){ get contentWindow(){
var window = originalContentWindowGetter.call(this); const window = originalContentWindowGetter.call(this);
if (window){ if (window){
singleCallback(window); singleCallback(window);
} }
@ -80,7 +82,7 @@
const originalContentDocumentGetter = contentDocumentDescriptor.get; const originalContentDocumentGetter = contentDocumentDescriptor.get;
const contentDocumentTemp = { const contentDocumentTemp = {
get contentDocument(){ get contentDocument(){
var document = originalContentDocumentGetter.call(this); const document = originalContentDocumentGetter.call(this);
if (document){ if (document){
singleCallback(document.defaultView); singleCallback(document.defaultView);
} }
@ -92,6 +94,9 @@
window window
)); ));
}); });
}
function protectDOMModifications({window, wrappedWindow, changeProperty, allCallback}){
[ [
// useless as length could be obtained before the iframe is created and window.frames === window // useless as length could be obtained before the iframe is created and window.frames === window
// { // {
@ -161,31 +166,31 @@
)); ));
}); });
}); });
}
// MutationObserver to intercept iFrames while generating the DOM.
const observe = function(){ function enableMutationObserver({window, allCallback}){
var observer = new MutationObserver(allCallback); const observer = new MutationObserver(allCallback);
var observing = false; let observing = false;
function observe(){ function observe(){
if ( if (
!observing && !observing &&
window.document window.document
){ ){
observer.observe(window.document, {subtree: true, childList: true}); observer.observe(window.document, {subtree: true, childList: true});
observing = true; observing = true;
}
} }
observe(); }
window.document.addEventListener("DOMContentLoaded", function(){ observe();
if (observing){ window.document.addEventListener("DOMContentLoaded", function(){
observer.disconnect(); if (observing){
observing = false; observer.disconnect();
} observing = false;
}); }
return observe; });
}(); return observe;
}
// MutationObserver does not trigger fast enough when document.write is used
function protectDocumentWrite({window, wrappedWindow, changeProperty, observe, allCallback}){
const documentWriteDescriptorOnHTMLDocument = Object.getOwnPropertyDescriptor( const documentWriteDescriptorOnHTMLDocument = Object.getOwnPropertyDescriptor(
wrappedWindow.HTMLDocument.prototype, wrappedWindow.HTMLDocument.prototype,
"write" "write"
@ -199,6 +204,7 @@
documentWriteDescriptorOnHTMLDocument? documentWriteDescriptorOnHTMLDocument?
wrappedWindow.HTMLDocument.prototype: wrappedWindow.HTMLDocument.prototype:
wrappedWindow.Document.prototype, wrappedWindow.Document.prototype,
// eslint-disable-next-line no-unused-vars
"write", "value", exportFunction(function write(markup){ "write", "value", exportFunction(function write(markup){
for (let i = 0, l = arguments.length; i < l; i += 1){ for (let i = 0, l = arguments.length; i < l; i += 1){
const str = "" + arguments[i]; const str = "" + arguments[i];
@ -234,6 +240,7 @@
wrappedWindow.HTMLDocument.prototype: wrappedWindow.HTMLDocument.prototype:
wrappedWindow.Document.prototype, wrappedWindow.Document.prototype,
"writeln", "value", exportFunction( "writeln", "value", exportFunction(
// eslint-disable-next-line no-unused-vars
function writeln(markup){ function writeln(markup){
for (let i = 0, l = arguments.length; i < l; i += 1){ for (let i = 0, l = arguments.length; i < l; i += 1){
const str = "" + arguments[i]; const str = "" + arguments[i];
@ -253,5 +260,21 @@
window window
) )
); );
}
scope.protect = function protect(window, wrappedWindow, singleCallback, allCallback){
const changeProperty = createChangeProperty(window);
const api = {window, wrappedWindow, changeProperty, singleCallback, allCallback};
protectFrameProperties(api);
protectDOMModifications(api);
// MutationObserver to intercept iFrames while generating the DOM.
api.observe = enableMutationObserver(api);
// MutationObserver does not trigger fast enough when document.write is used
protectDocumentWrite(api);
}; };
}()); }());

View File

@ -41,380 +41,394 @@
setRandomSupplyByType(settings.rng); setRandomSupplyByType(settings.rng);
}); });
function getURL(window){ function getURL(windowToProcess){
let href; let href;
try { try {
href = window.location.href; href = windowToProcess.location.href;
} }
catch (e){ catch (error){
// unable to read location due to SOP // unable to read location due to SOP
// since we are not able to do anything in that case we can allow everything // since we are not able to do anything in that case we can allow everything
return "about:SOP"; return "about:SOP";
} }
if (!href || href === "about:blank"){ if (!href || href === "about:blank"){
if (window !== window.parent){ if (windowToProcess !== windowToProcess.parent){
return getURL(window.parent); return getURL(windowToProcess.parent);
} }
else if (window.opener){ else if (windowToProcess.opener){
return getURL(window.opener); return getURL(windowToProcess.opener);
} }
} }
return href; return href;
} }
const getAllFunctionObjects = function(windowToProcess, changedFunction){
return (
Array.isArray(changedFunction.object)?
changedFunction.object:
[changedFunction.object]
).map(function(name){
if (name){
const constructor = getWrapped(windowToProcess)[name];
if (constructor){
return constructor.prototype;
}
}
return false;
}).concat(
changedFunction.objectGetters?
changedFunction.objectGetters.map(function(objectGetter){
return objectGetter(getWrapped(windowToProcess));
}):
[]
);
};
const forEachFunction = function(windowToProcess, callback){
apiNames.forEach(function(name){
const changedFunction = changedFunctions[name];
getAllFunctionObjects(windowToProcess, changedFunction).forEach(function(object){
if (object){
callback({name, object: object, changedFunction});
}
});
});
};
const forEachGetter = function(windowToProcess, callback){
changedGetters.forEach(function(changedGetter){
const name = changedGetter.name;
changedGetter.objectGetters.forEach(function(changedGetter){
const object = changedGetter(getWrapped(windowToProcess));
if (object){
callback({name, object, objectGetter: changedGetter});
}
});
});
};
scope.preIntercept = function preIntercept({subject: window}, apis){ const forEach = function(windowToProcess, callback){
if (!settings.isStillDefault){ forEachFunction(windowToProcess, callback);
logging.message("settings already loaded -> no need to pre intercept"); forEachGetter(windowToProcess, callback);
scope.intercept({subject: window}, apis); };
const doRealIntercept = function(windowToProcess, apis, state){
if (!state.intercepted){
scope.intercept({subject: windowToProcess}, apis);
state.intercepted = true;
} }
else { };
logging.message("settings not loaded -> need to pre intercept"); const doPreIntercept = function(windowToProcess, apis, state){
let forceLoad = true; const forceLoad = true;
let preIntercepted = false; const originalPropertyDescriptors = {};
let intercepted = false; const undoPreIntercept = function(){
const forEachFunction = function(callback){ if (state.preIntercepted){
apiNames.forEach(function(name){ state.preIntercepted = false;
const changedFunction = changedFunctions[name]; forEach(windowToProcess, function({name, object}){
( const originalPropertyDescriptor = originalPropertyDescriptors[name].get(object);
Array.isArray(changedFunction.object)? if (originalPropertyDescriptor){
changedFunction.object:
[changedFunction.object]
).map(function(name){
if (name){
const constructor = getWrapped(window)[name];
if (constructor){
return constructor.prototype;
}
}
return false;
}).concat(
changedFunction.objectGetters?
changedFunction.objectGetters.map(function(objectGetter){
return objectGetter(getWrapped(window));
}):
[]
).forEach(function(object){
if (object){
callback({name, object: object});
}
});
});
changedGetters.forEach(function(changedGetter){
const name = changedGetter.name;
changedGetter.objectGetters.forEach(function(objectGetter){
const object = objectGetter(getWrapped(window));
if (object){
callback({name, object});
}
});
});
};
let originalPropertyDescriptors = {};
const doPreIntercept = function(){
if (!preIntercepted){
forEachFunction(function({name, object}){
const map = originalPropertyDescriptors[name] || new WeakMap();
originalPropertyDescriptors[name] = map;
const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(object, name);
if (!originalPropertyDescriptor){
return;
}
map.set(object, originalPropertyDescriptor);
Object.defineProperty( Object.defineProperty(
object, object,
name, name,
{ originalPropertyDescriptor
enumerable: true,
configurable: true,
get: exportFunction(function(){
if (forceLoad){
logging.warning("force load the settings. Calling stack:", (new Error()).stack);
undoPreIntercept();
settings.forceLoad();
doRealIntercept();
const descriptor = Object.getOwnPropertyDescriptor(object, name);
return descriptor.value || descriptor.get.call(this);
}
else {
logging.notice("API blocked (%s)", name);
const url = getURL(window);
if (!url){
return undef;
}
const error = new Error();
apis.notify({
url,
errorStack: error.stack,
messageId: "preBlock",
timestamp: new Date(),
functionName: name,
dataURL: false
});
return;
}
}, window),
set: exportFunction(function(){}, window)
}
); );
}); }
preIntercepted = true; });
} }
}; };
const undoPreIntercept = function(){ if (!state.preIntercepted){
if (preIntercepted){ forEach(windowToProcess, function({name, object}){
preIntercepted = false; const map = originalPropertyDescriptors[name] || new WeakMap();
forEachFunction(function({name, object}){ originalPropertyDescriptors[name] = map;
const originalPropertyDescriptor = originalPropertyDescriptors[name].get(object);
if (originalPropertyDescriptor){ const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(object, name);
Object.defineProperty( if (!originalPropertyDescriptor){
object, return;
name,
originalPropertyDescriptor
);
}
});
}
};
const doRealIntercept = function(){
if (!intercepted){
scope.intercept({subject: window}, apis);
intercepted = true;
} }
map.set(object, originalPropertyDescriptor);
Object.defineProperty(
object,
name,
{
enumerable: true,
configurable: true,
get: exportFunction(function(){
if (forceLoad){
logging.warning("force load the settings. Calling stack:", (new Error()).stack);
undoPreIntercept();
settings.forceLoad();
doRealIntercept(windowToProcess, apis, state);
const descriptor = Object.getOwnPropertyDescriptor(object, name);
return descriptor.value || descriptor.get.call(this);
}
else {
logging.notice("API blocked (%s)", name);
const url = getURL(windowToProcess);
if (!url){
return undef;
}
const error = new Error();
apis.notify({
url,
errorStack: error.stack,
messageId: "preBlock",
timestamp: new Date(),
functionName: name,
dataURL: false
});
return;
}
}, windowToProcess),
set: exportFunction(function(){}, windowToProcess)
}
);
});
state.preIntercepted = true;
}
return undoPreIntercept;
};
scope.preIntercept = function preIntercept({subject: windowToProcess}, apis){
if (!settings.isStillDefault){
logging.message("settings already loaded -> no need to pre intercept");
scope.intercept({subject: windowToProcess}, apis);
}
else {
logging.message("settings not loaded -> need to pre intercept");
const state = {
preIntercepted: false,
intercepted: false
}; };
doPreIntercept(); const undoPreIntercept = doPreIntercept(windowToProcess, apis, state);
settings.onloaded(function(){ settings.onloaded(function(){
undoPreIntercept(); undoPreIntercept();
doRealIntercept(); doRealIntercept(windowToProcess, apis, state);
}); });
} }
}; };
function getDataURL(object, prefs){
return (
object &&
prefs("storeImageForInspection") &&
prefs("showNotifications")?
(
object instanceof HTMLCanvasElement?
object.toDataURL():
(
object.canvas instanceof HTMLCanvasElement?
object.canvas.toDataURL():
false
)
):
false
);
}
let extensionID = extension.extensionID; let extensionID = extension.extensionID;
scope.intercept = function intercept({subject: window}, {check, checkStack, ask, notify, prefs}){
function getDataURL(object, prefs){ function generateChecker({
return ( name, changedFunction, siteStatus, original,
object && window: windowToProcess, prefs, notify, checkStack, ask
prefs("storeImageForInspection") && }){
prefs("showNotifications")? return function checker(callingDepth = 2){
( const errorStack = (new Error()).stack;
object instanceof HTMLCanvasElement?
object.toDataURL(): try {
( // return original if the extension itself requested the function
object.canvas instanceof HTMLCanvasElement? if (
object.canvas.toDataURL(): errorStack
false .split("\n", callingDepth + 2)[callingDepth + 1]
) .split("@", callingDepth + 1)[1]
): .startsWith(extensionID)
false ){
); return {allow: true, original, window: windowToProcess};
}
function generateChecker(name, changedFunction, siteStatus, original){
return function checker(callingDepth = 2){
const error = new Error();
const errorStack = error.stack;
try {
// return original if the extension itself requested the function
if (
errorStack
.split("\n", callingDepth + 2)[callingDepth + 1]
.split("@", callingDepth + 1)[1]
.startsWith(extensionID)
){
return {allow: true, original, window};
}
} }
catch (e) { }
// stack had an unknown form catch (error) {
} // stack had an unknown form
if (checkStack(errorStack)){ }
return {allow: true, original, window}; if (checkStack(errorStack)){
} return {allow: true, original, window: windowToProcess};
const funcStatus = changedFunction.getStatus(this, siteStatus, prefs); }
const funcStatus = changedFunction.getStatus(this, siteStatus, prefs);
const This = this;
function notifyCallback(messageId){ const This = this;
notify({ function notifyCallback(messageId){
url: getURL(window), notify({
errorStack, url: getURL(windowToProcess),
messageId, errorStack,
timestamp: new Date(), messageId,
functionName: name, timestamp: new Date(),
functionName: name,
api: changedFunction.api,
dataURL: getDataURL(This, prefs)
});
}
const protectedAPIFeatures = prefs("protectedAPIFeatures");
if (
funcStatus.active &&
(
!protectedAPIFeatures.hasOwnProperty(name + " @ " + changedFunction.api) ||
protectedAPIFeatures[name + " @ " + changedFunction.api]
)
){
if (funcStatus.mode === "ask"){
funcStatus.mode = ask({
window: windowToProcess,
type: changedFunction.type,
api: changedFunction.api, api: changedFunction.api,
dataURL: getDataURL(This, prefs) canvas: this instanceof HTMLCanvasElement?
this:
(
this &&
(this.canvas instanceof HTMLCanvasElement)?
this.canvas:
false
),
errorStack
}); });
} }
const protectedAPIFeatures = prefs("protectedAPIFeatures"); switch (funcStatus.mode){
if ( case "allow":
funcStatus.active && return {allow: true, original, window: windowToProcess};
( case "fake":
!protectedAPIFeatures.hasOwnProperty(name + " @ " + changedFunction.api) || return {
protectedAPIFeatures[name + " @ " + changedFunction.api] allow: "fake",
) prefs,
){ notify: notifyCallback,
if (funcStatus.mode === "ask"){ window: windowToProcess,
funcStatus.mode = ask({ original
window: window, };
type: changedFunction.type, //case "block":
api: changedFunction.api, default:
canvas: this instanceof HTMLCanvasElement? return {allow: false, notify: notifyCallback};
this: }
( }
this && else {
(this.canvas instanceof HTMLCanvasElement)? return {allow: true, original, window: windowToProcess};
this.canvas: }
false };
), }
errorStack
function interceptFunctions(windowToProcess, siteStatus, {checkStack, ask, notify, prefs}){
apiNames.forEach(function(name){
const changedFunction = changedFunctions[name];
const functionStatus = changedFunction.getStatus(undefined, siteStatus, prefs);
logging.verbose("status for", name, ":", functionStatus);
if (functionStatus.active){
getAllFunctionObjects(windowToProcess, changedFunction).forEach(function(object){
if (object){
const original = object[name];
const checker = generateChecker({
name, changedFunction, siteStatus, original,
window: windowToProcess, prefs, checkStack, ask, notify
}); });
} const descriptor = Object.getOwnPropertyDescriptor(object, name);
switch (funcStatus.mode){ if (descriptor){
case "allow": if (descriptor.hasOwnProperty("value")){
return {allow: true, original, window}; if (changedFunction.fakeGenerator){
case "fake": descriptor.value = exportFunction(
return { changedFunction.fakeGenerator(checker, original, windowToProcess),
allow: "fake", windowToProcess
prefs, );
notify: notifyCallback,
window,
original
};
//case "block":
default:
return {
allow: false,
notify: notifyCallback
};
}
}
else {
return {allow: true, original, window};
}
};
}
const siteStatus = check({url: getURL(window)});
logging.verbose("status for page", window, siteStatus);
if (siteStatus.mode !== "allow"){
apiNames.forEach(function(name){
const changedFunction = changedFunctions[name];
const functionStatus = changedFunction.getStatus(undefined, siteStatus, prefs);
logging.verbose("status for", name, ":", functionStatus);
if (functionStatus.active){
(
Array.isArray(changedFunction.object)?
changedFunction.object:
[changedFunction.object]
).map(function(name){
if (name){
const constructor = getWrapped(window)[name];
if (constructor){
return constructor.prototype;
}
}
return false;
}).concat(
changedFunction.objectGetters?
changedFunction.objectGetters.map(function(objectGetter){
return objectGetter(getWrapped(window));
}):
[]
).forEach(function(object){
if (object){
const original = object[name];
const checker = generateChecker(name, changedFunction, siteStatus, original);
const descriptor = Object.getOwnPropertyDescriptor(object, name);
if (descriptor){
if (descriptor.hasOwnProperty("value")){
if (changedFunction.fakeGenerator){
descriptor.value = exportFunction(
changedFunction.fakeGenerator(checker, original, window),
window
);
}
else {
descriptor.value = null;
}
} }
else { else {
descriptor.get = exportFunction(function(){ descriptor.value = null;
return exportFunction(
changedFunction.fakeGenerator(checker),
window
);
}, window);
}
Object.defineProperty(object, name, descriptor);
}
}
});
}
});
changedGetters.forEach(function(changedGetter){
const name = changedGetter.name;
const functionStatus = changedGetter.getStatus(undefined, siteStatus, prefs);
logging.verbose("status for", changedGetter, ":", functionStatus);
if (functionStatus.active){
changedGetter.objectGetters.forEach(function(objectGetter){
const object = objectGetter(getWrapped(window));
if (object){
const descriptor = Object.getOwnPropertyDescriptor(object, name);
if (descriptor && descriptor.hasOwnProperty("get")){
const original = descriptor.get;
const checker = generateChecker(name, changedGetter, siteStatus, original);
const getter = changedGetter.getterGenerator(checker, original, window);
descriptor.get = exportFunction(getter, window);
if (descriptor.hasOwnProperty("set") && changedGetter.setterGenerator){
const setter = changedGetter.setterGenerator(window, descriptor.set, prefs);
descriptor.set = exportFunction(setter, window);
}
Object.defineProperty(object, name, descriptor);
}
else if (
changedGetter.valueGenerator &&
descriptor && descriptor.hasOwnProperty("value")
){
const protectedAPIFeatures = prefs("protectedAPIFeatures");
if (
functionStatus.active &&
(
!protectedAPIFeatures.hasOwnProperty(name + " @ " + changedGetter.api) ||
protectedAPIFeatures[name + " @ " + changedGetter.api]
)
){
switch (functionStatus.mode){
case "ask": case "block": case "fake":
descriptor.value = changedGetter.valueGenerator({
mode: functionStatus.mode,
original: descriptor.value,
notify: function notifyCallback(messageId){
notify({
url: getURL(window),
errorStack: (new Error()).stack,
messageId,
timestamp: new Date(),
functionName: name,
api: changedGetter.api
});
}
});
Object.defineProperty(object, name, descriptor);
break;
}
} }
} }
else { else {
logging.error("Try to fake non getter property:", changedGetter); descriptor.get = exportFunction(function(){
return exportFunction(
changedFunction.fakeGenerator(checker),
windowToProcess
);
}, windowToProcess);
}
Object.defineProperty(object, name, descriptor);
}
}
});
}
});
}
function interceptGetters(windowToProcess, siteStatus, {checkStack, ask, notify, prefs}){
changedGetters.forEach(function(changedGetter){
const name = changedGetter.name;
const functionStatus = changedGetter.getStatus(undefined, siteStatus, prefs);
logging.verbose("status for", changedGetter, ":", functionStatus);
if (functionStatus.active){
changedGetter.objectGetters.forEach(function(objectGetter){
const object = objectGetter(getWrapped(windowToProcess));
if (object){
const descriptor = Object.getOwnPropertyDescriptor(object, name);
if (descriptor && descriptor.hasOwnProperty("get")){
const original = descriptor.get;
const checker = generateChecker({
name, changedFunction: changedGetter, siteStatus, original,
window: windowToProcess, prefs, checkStack, ask, notify
});
const getter = changedGetter.getterGenerator(checker, original, windowToProcess);
descriptor.get = exportFunction(getter, windowToProcess);
if (descriptor.hasOwnProperty("set") && changedGetter.setterGenerator){
const setter = changedGetter.setterGenerator(
windowToProcess,
descriptor.set,
prefs
);
descriptor.set = exportFunction(setter, windowToProcess);
}
Object.defineProperty(object, name, descriptor);
}
else if (
changedGetter.valueGenerator &&
descriptor && descriptor.hasOwnProperty("value")
){
const protectedAPIFeatures = prefs("protectedAPIFeatures");
if (
functionStatus.active &&
(
!protectedAPIFeatures.hasOwnProperty(name + " @ " + changedGetter.api) ||
protectedAPIFeatures[name + " @ " + changedGetter.api]
)
){
switch (functionStatus.mode){
case "ask": case "block": case "fake":
descriptor.value = changedGetter.valueGenerator({
mode: functionStatus.mode,
original: descriptor.value,
notify: function notifyCallback(messageId){
notify({
url: getURL(windowToProcess),
errorStack: (new Error()).stack,
messageId,
timestamp: new Date(),
functionName: name,
api: changedGetter.api
});
}
});
Object.defineProperty(object, name, descriptor);
break;
}
} }
} }
}); else {
} logging.error("Try to fake non getter property:", changedGetter);
}); }
}
});
}
});
}
scope.intercept = function intercept({subject: windowToProcess}, apis){
const siteStatus = apis.check({url: getURL(windowToProcess)});
logging.verbose("status for page", windowToProcess, siteStatus);
if (siteStatus.mode !== "allow"){
interceptFunctions(windowToProcess, siteStatus, apis);
interceptGetters(windowToProcess, siteStatus, apis);
} }
}; };
}()); }());

View File

@ -6,7 +6,7 @@
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -14,11 +14,11 @@
scope = require.register("./lists", {}); scope = require.register("./lists", {});
} }
var settings = require("./settings"); const settings = require("./settings");
function getDomainRegExpList(domainList){ function getDomainRegExpList(domainList){
var list = domainList const list = domainList
.split(",") .split(",")
.map(function(entry){ .map(function(entry){
return entry.replace(/^\s+|\s+$/g, ""); return entry.replace(/^\s+|\s+$/g, "");
@ -27,8 +27,8 @@
return !!entry.length; return !!entry.length;
}) })
.map(function(entry){ .map(function(entry){
var regExp; let regExp;
var domain = !!entry.match(/^[A-Za-z0-9_.-]+$/); const domain = !!entry.match(/^[A-Za-z0-9_.-]+$/);
if (domain){ if (domain){
regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$", "i"); regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$", "i");
} }
@ -59,7 +59,7 @@
return list; return list;
} }
var lists = { const lists = {
white: [], white: [],
sessionWhite: [], sessionWhite: [],
"ignore": [], "ignore": [],
@ -81,9 +81,9 @@
}); });
function updateStackList(value){ function updateStackList(value){
var list; let list;
try { try {
var data = JSON.parse(value); let data = JSON.parse(value);
if (!Array.isArray(data)){ if (!Array.isArray(data)){
data = [data]; data = [data];
} }
@ -91,7 +91,7 @@
return typeof entry === "object" && typeof entry.url === "string"; return typeof entry === "object" && typeof entry.url === "string";
}); });
} }
catch(e){ catch(error){
list = []; list = [];
} }
list.match = function(stack){ list.match = function(stack){
@ -109,13 +109,13 @@
scope.get = function getList(type){ scope.get = function getList(type){
if (type === "white"){ if (type === "white"){
var combined = lists.white.slice().concat(lists.sessionWhite); const combined = lists.white.slice().concat(lists.sessionWhite);
return addMatchToList(combined); return addMatchToList(combined);
} }
return lists[type]; return lists[type];
}; };
scope.appendTo = function appendToList(type, entry){ scope.appendTo = function appendToList(type, entry){
var oldValue = settings[type + "List"]; const oldValue = settings[type + "List"];
return settings.set(type + "List", oldValue + (oldValue? ",": "") + entry).then(function(){ return settings.set(type + "List", oldValue + (oldValue? ",": "") + entry).then(function(){
return updateList(type); return updateList(type);
}); });

View File

@ -1,11 +1,10 @@
/* eslint no-console: off */
/* This Source Code Form is subject to the terms of the Mozilla Public /* 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -17,21 +16,21 @@
scope.setSettings = function(realSettings){ scope.setSettings = function(realSettings){
if (!settings){ if (!settings){
settings = realSettings; settings = realSettings;
settings.loaded.then(scope.clearQueue); return settings.loaded.then(scope.clearQueue);
} }
else { else {
warning("logging: Settings can only be set once."); warning("logging: Settings can only be set once.");
} }
}; };
var prefix = ""; let prefix = "";
function leftPad(str, char, pad){ function leftPad(str, char, pad){
str = "" + str; str = "" + str;
return char.repeat(pad - str.length) + str; return char.repeat(pad - str.length) + str;
} }
var colors = { const colors = {
1: "color: red", 1: "color: red",
25: "color: orange", 25: "color: orange",
50: "", 50: "",
@ -40,7 +39,7 @@
999: "background-color: lightgray" 999: "background-color: lightgray"
}; };
var queue = []; let queue = [];
function performLog(level, args, date){ function performLog(level, args, date){
if (!date){ if (!date){
date = new Date(); date = new Date();
@ -50,7 +49,7 @@
} }
else { else {
if (settings.logLevel >= level){ if (settings.logLevel >= level){
var pre = "%c[CanvasBlocker] "; let pre = "%c[CanvasBlocker] ";
if (prefix){ if (prefix){
pre += prefix + ": "; pre += prefix + ": ";
} }
@ -71,6 +70,7 @@
args.unshift(colors[level] || ""); args.unshift(colors[level] || "");
args.unshift(pre); args.unshift(pre);
} }
// eslint-disable-next-line no-console
console.log.apply(console, args); console.log.apply(console, args);
} }
} }
@ -94,7 +94,7 @@
scope.clearQueue = function(){ scope.clearQueue = function(){
if (queue.length){ if (queue.length){
metaLog("clear logging queue"); metaLog("clear logging queue");
var tmp = queue; const tmp = queue;
queue = []; queue = [];
tmp.forEach(function(item){ tmp.forEach(function(item){
performLog(item.level, item.args, item.date); performLog(item.level, item.args, item.date);

View File

@ -6,25 +6,81 @@
const settings = require("./settings"); const settings = require("./settings");
const logging = require("./logging"); const logging = require("./logging");
const {error, warning, message, notice, verbose, } = logging;
logging.setPrefix("main script"); logging.setPrefix("main script");
const persistentRndStorage = require("./persistentRndStorage"); const persistentRndStorage = require("./persistentRndStorage");
const notification = require("./notification"); const notification = require("./notification");
message("start of background script"); const registerSettingsContentScript = (function(){
message("waiting for settings to be loaded"); let unregisterSettingsContentScript = function(){};
let lastRegistering;
return function registerSettingsContentScript(){
logging.message("Register content script for the settings.");
logging.verbose("Unregister old content script, if present.");
unregisterSettingsContentScript();
const data = {};
settings.forEach(function(def){
data[def.name] = def.get();
});
lastRegistering = data;
browser.contentScripts.register({
matches: ["<all_urls>"],
matchAboutBlank: true,
allFrames: true,
runAt: "document_start",
js: [{
code: `(function(settingsData){
if (typeof require !== "undefined"){
const settings = require("./settings");
const logging = require("./logging");
if (settings.init(settingsData)){
logging.message("Initialized settings by dynamic content script.");
}
else {
logging.warning("Dynamic content script was too late to provide settings.");
}
}
else {
if (!window.scope){
window.scope = {};
}
window.scope.settingsData = settingsData;
console.warn(
"[CanvasBlocker] invalid content script order: require not defined at",
window.location.href
);
}
}(${JSON.stringify(data)}))`
}]
}).then(function(api){
logging.verbose("Content script registered.");
if (data !== lastRegistering){
logging.verbose("Multiple content scripts registered at once. Remove unnecessary one.");
api.unregister();
}
else {
unregisterSettingsContentScript = api.unregister;
}
return;
}).catch(function(error){
logging.warning("Unable to register content script:", error);
});
};
}());
logging.message("start of background script");
logging.message("waiting for settings to be loaded");
settings.onloaded(function(){ settings.onloaded(function(){
notice("everything loaded"); logging.notice("everything loaded");
message("perform startup reset"); logging.message("perform startup reset");
settings.startupReset(); settings.startupReset();
persistentRndStorage.init(); persistentRndStorage.init();
message("register non port message listener"); logging.message("register non port message listener");
browser.runtime.onMessage.addListener(function(data){ browser.runtime.onMessage.addListener(function(data){
notice("got data without port", data); logging.notice("got data without port", data);
var keys = Object.keys(data); const keys = Object.keys(data);
if (data["canvasBlocker-new-domain-rnd"]){ if (data["canvasBlocker-new-domain-rnd"]){
persistentRndStorage.setDomainData( persistentRndStorage.setDomainData(
data["canvasBlocker-new-domain-rnd"].domain, data["canvasBlocker-new-domain-rnd"].domain,
@ -47,31 +103,34 @@
return; return;
} }
} }
notice("pass the message to the tabs"); logging.notice("pass the message to the tabs");
browser.tabs.query({}).then(function(tabs){ browser.tabs.query({}).then(function(tabs){
tabs.forEach(function(tab){ tabs.forEach(function(tab){
browser.tabs.sendMessage(tab.id, data); browser.tabs.sendMessage(tab.id, data);
}); });
return;
}).catch(function(error){
logging.warning("Unable to get browser tabs:", error);
}); });
}); });
message("register port listener"); logging.message("register port listener");
browser.runtime.onConnect.addListener(function(port){ browser.runtime.onConnect.addListener(function(port){
notice("got port", port); logging.notice("got port", port);
if (!port.sender.tab){ if (!port.sender.tab){
notice("got port without tab = Firefox bug:", port); logging.notice("got port without tab = Firefox bug:", port);
return; return;
} }
verbose("send back the tab id", port.sender.tab.id); logging.verbose("send back the tab id", port.sender.tab.id);
verbose("send back the tab cookie store id", port.sender.tab.cookieStoreId); logging.verbose("send back the tab cookie store id", port.sender.tab.cookieStoreId);
verbose("send back the persistent random seeds", persistentRndStorage.persistentRnd); logging.verbose("send back the persistent random seeds", persistentRndStorage.persistentRnd);
port.postMessage({ port.postMessage({
tabId: port.sender.tab.id, tabId: port.sender.tab.id,
cookieStoreId: port.sender.tab.cookieStoreId, cookieStoreId: port.sender.tab.cookieStoreId,
persistentRnd: persistentRndStorage.persistentRnd, persistentRnd: persistentRndStorage.persistentRnd,
persistentIncognitoRnd: persistentRndStorage.persistentIncognitoRnd persistentIncognitoRnd: persistentRndStorage.persistentIncognitoRnd
}); });
var url = new URL(port.sender.url); const url = new URL(port.sender.url);
port.onMessage.addListener(function(data){ port.onMessage.addListener(function(data){
if (data.hasOwnProperty("canvasBlocker-notify")){ if (data.hasOwnProperty("canvasBlocker-notify")){
notification.show(port.sender.tab.id, url, data["canvasBlocker-notify"].api); notification.show(port.sender.tab.id, url, data["canvasBlocker-notify"].api);
@ -79,76 +138,25 @@
if (data.hasOwnProperty("canvasBlocker-clear-page-action")){ if (data.hasOwnProperty("canvasBlocker-clear-page-action")){
notification.hide(port.sender.tab.id, url); notification.hide(port.sender.tab.id, url);
} }
verbose("got data", data, "from port", port); logging.verbose("got data", data, "from port", port);
}); });
}); });
message("register storage change event listener"); logging.message("register storage change event listener");
if (browser.contentScripts){ if (browser.contentScripts){
let unregister = function(){}; registerSettingsContentScript();
let lastRegistering; settings.on("any", registerSettingsContentScript);
const register = function register(){
logging.message("Register content script for the settings.");
logging.verbose("Unregister old content script, if present.");
unregister();
var data = {};
settings.forEach(function(def){
data[def.name] = def.get();
});
lastRegistering = data;
browser.contentScripts.register({
matches: ["<all_urls>"],
matchAboutBlank: true,
allFrames: true,
runAt: "document_start",
js: [{
code: `(function(settingsData){
if (typeof require !== "undefined"){
const settings = require("./settings");
const logging = require("./logging");
if (settings.init(settingsData)){
logging.message("Initialized settings by dynamic content script.");
}
else {
logging.warning("Dynamic content script was too late to provide settings.");
}
}
else {
if (!window.scope){
window.scope = {};
}
window.scope.settingsData = settingsData;
console.warn(
"[CanvasBlocker] invalid content script order: require not defined at",
window.location.href
);
}
}(${JSON.stringify(data)}))`
}]
}).then(function(api){
logging.verbose("Content script registered.");
if (data !== lastRegistering){
logging.verbose("Multiple content scripts registered at once. Remove unnecessary one.");
api.unregister();
}
else {
unregister = api.unregister;
}
});
};
register();
settings.on("any", register);
} }
else { else {
logging.error("Old Firefox does not support browser.contentScript.register()"); logging.error("Old Firefox does not support browser.contentScript.register()");
} }
}); });
message("Initialize data-URL workaround."); logging.message("Initialize data-URL workaround.");
require("./dataUrls").init(); require("./dataUrls").init();
message("Initialize navigator HTTP header protection."); logging.message("Initialize navigator HTTP header protection.");
require("./navigator").init(); require("./navigator").init();
browser.runtime.onInstalled.addListener(function(details){ browser.runtime.onInstalled.addListener(function(details){
@ -165,7 +173,7 @@
} }
switch (details.reason){ switch (details.reason){
case "install": case "install":
message("CanvasBlocker installed"); logging.message("CanvasBlocker installed");
openOptions(details.reason); openOptions(details.reason);
browser.tabs.create({ browser.tabs.create({
url: browser.extension.getURL("options/presets.html?notice=" + details.reason) url: browser.extension.getURL("options/presets.html?notice=" + details.reason)
@ -174,12 +182,12 @@
case "update": case "update":
settings.onloaded(function(){ settings.onloaded(function(){
if (!settings.dontShowOptionsOnUpdate){ if (!settings.dontShowOptionsOnUpdate){
message("CanvasBlocker updated"); logging.message("CanvasBlocker updated");
openOptions(details.reason); openOptions(details.reason);
} }
}); });
} }
}); });
message("end"); logging.message("end");
}()); }());

View File

@ -96,8 +96,7 @@
const parentTop = getGlobalOffsetTop(parent) - getGlobalScrollTop(parent); const parentTop = getGlobalOffsetTop(parent) - getGlobalScrollTop(parent);
const parentHeight = parent.offsetHeight; const parentHeight = parent.offsetHeight;
const height = dialog.offsetHeight; const height = dialog.offsetHeight;
const top = Math.max( const top = Math.max(0,
0,
Math.min( Math.min(
container.offsetHeight - height, container.offsetHeight - height,
parentTop + parentHeight / 2 - height / 2 parentTop + parentHeight / 2 - height / 2

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -32,7 +32,7 @@
scope.setFunctionProperties = function setFunctionProperties(functions, data){ scope.setFunctionProperties = function setFunctionProperties(functions, data){
Object.keys(functions).forEach(function(key){ Object.keys(functions).forEach(function(key){
var func = functions[key]; const func = functions[key];
["type", "api", "getStatus"].forEach(function(property){ ["type", "api", "getStatus"].forEach(function(property){
if (data[property] && !func[property]){ if (data[property] && !func[property]){
func[property] = data[property]; func[property] = data[property];

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -12,25 +12,24 @@
scope = require.register("./modifiedAudioAPI", {}); scope = require.register("./modifiedAudioAPI", {});
} }
const logging = require("./logging");
const {sha256String: hashing} = require("./hash"); const {sha256String: hashing} = require("./hash");
const {checkerWrapper} = require("./modifiedAPIFunctions"); const {checkerWrapper} = require("./modifiedAPIFunctions");
var randomSupply = null; let randomSupply = null;
const getAudioFakeRate = function(){ const getAudioFakeRate = function(){
const audioFakeRate = { const audioFakeRate = {
"1": function(array){return 1;}, "1": function(){return 1;},
"10": function(array){return 10;}, "10": function(){return 10;},
"100": function(array){return 100;}, "100": function(){return 100;},
"1000": function(array){return 1000;}, "1000": function(){return 1000;},
"0.1%": function(array){return array.length / 1000;}, "0.1%": function(array){return array.length / 1000;},
"1%": function(array){return array.length / 100;}, "1%": function(array){return array.length / 100;},
"10%": function(array){return array.length / 10;}, "10%": function(array){return array.length / 10;},
"100%": function(array){return array.length;}, "100%": function(array){return array.length;},
}; };
return function getAudioFakeRate(array, prefs){ return function getAudioFakeRate(array, prefs){
var func = audioFakeRate[prefs("audioFakeRate")]; const func = audioFakeRate[prefs("audioFakeRate")];
if (typeof func === "function"){ if (typeof func === "function"){
return func(array); return func(array);
} }
@ -66,18 +65,18 @@
} }
function forEachIndex(array, prefs, callback){ function forEachIndex(array, prefs, callback){
var length = array.length; const length = array.length;
var rate = getAudioFakeRate(array, prefs); const rate = getAudioFakeRate(array, prefs);
var start = 0; let start = 0;
forEachFixedIndex(prefs, function(index){ forEachFixedIndex(prefs, function(index){
callback(index, start); callback(index, start);
start += 1; start += 1;
}); });
if (start < rate){ if (start < rate){
var delta = Math.floor(length / (rate - start)); const delta = Math.floor(length / (rate - start));
var indexRng = randomSupply.getIndexRng(1, length - delta * (rate - start - 1), window); const indexRng = randomSupply.getIndexRng(1, length - delta * (rate - start - 1), window);
var offset = indexRng(0); let offset = indexRng(0);
for (var i = start; i < rate; i += 1){ for (let i = start; i < rate; i += 1){
callback(offset, i); callback(offset, i);
offset += delta; offset += delta;
} }
@ -88,7 +87,7 @@
const intCache = Object.create(null); const intCache = Object.create(null);
function arrayHasAnyNonZero(array){ function arrayHasAnyNonZero(array){
for (var i = 0, l = array.length; i < l; i += 1){ for (let i = 0, l = array.length; i < l; i += 1){
if (array[i]){ if (array[i]){
return true; return true;
} }
@ -105,9 +104,9 @@
cached = floatCache[hash]; cached = floatCache[hash];
} }
if (!cached){ if (!cached){
var rate = getAudioFakeRate(array, prefs); const rate = getAudioFakeRate(array, prefs);
var noiseLevel = getAudioNoiseLevel(prefs); const noiseLevel = getAudioNoiseLevel(prefs);
var rng = randomSupply.getRng(rate, window); const rng = randomSupply.getRng(rate, window);
forEachIndex(array, prefs, function(index, i){ forEachIndex(array, prefs, function(index, i){
let value; let value;
if (array[index] !== 0){ if (array[index] !== 0){
@ -137,8 +136,8 @@
cached = intCache[hash]; cached = intCache[hash];
} }
if (!cached){ if (!cached){
var rate = getAudioFakeRate(array, prefs); const rate = getAudioFakeRate(array, prefs);
var rng = randomSupply.getValueRng(rate, window); const rng = randomSupply.getValueRng(rate, window);
forEachIndex(array, prefs, function(index, i){ forEachIndex(array, prefs, function(index, i){
array[index] = rng(array[index], i); array[index] = rng(array[index], i);
}); });
@ -171,9 +170,9 @@
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function getFloatFrequencyData(array){ return function getFloatFrequencyData(array){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
notify("fakedAudioReadout"); notify("fakedAudioReadout");
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
fakeFloat32Array(array, window, prefs); fakeFloat32Array(array, window, prefs);
return ret; return ret;
}); });
@ -185,9 +184,9 @@
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function getByteFrequencyData(array){ return function getByteFrequencyData(array){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
notify("fakedAudioReadout"); notify("fakedAudioReadout");
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
fakeUint8Array(array, window, prefs); fakeUint8Array(array, window, prefs);
return ret; return ret;
}); });
@ -199,9 +198,9 @@
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function getFloatTimeDomainData(array){ return function getFloatTimeDomainData(array){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
notify("fakedAudioReadout"); notify("fakedAudioReadout");
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
fakeFloat32Array(array, window, prefs); fakeFloat32Array(array, window, prefs);
return ret; return ret;
}); });
@ -213,9 +212,9 @@
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function getByteTimeDomainData(array){ return function getByteTimeDomainData(array){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
notify("fakedAudioReadout"); notify("fakedAudioReadout");
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
fakeUint8Array(array, window, prefs); fakeUint8Array(array, window, prefs);
return ret; return ret;
}); });
@ -225,10 +224,11 @@
getChannelData: { getChannelData: {
object: ["AudioBuffer"], object: ["AudioBuffer"],
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function getChannelData(channel){ return function getChannelData(channel){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
if (!getChannelDataAlreadyFakedArrays.get(ret)){ if (!getChannelDataAlreadyFakedArrays.get(ret)){
notify("fakedAudioReadout"); notify("fakedAudioReadout");
fakeFloat32Array(ret, window, prefs); fakeFloat32Array(ret, window, prefs);
@ -242,16 +242,17 @@
copyFromChannel: { copyFromChannel: {
object: ["AudioBuffer"], object: ["AudioBuffer"],
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function copyFromChannel(destination, channelNumber, startInChannel){ return function copyFromChannel(destination, channelNumber, startInChannel){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
var channelData = this.getChannelData(channelNumber); const channelData = this.getChannelData(channelNumber);
if (!getChannelDataAlreadyFakedArrays.get(channelData)){ if (!getChannelDataAlreadyFakedArrays.get(channelData)){
notify("fakedAudioReadout"); notify("fakedAudioReadout");
fakeFloat32Array(channelData, window, prefs); fakeFloat32Array(channelData, window, prefs);
getChannelDataAlreadyFakedArrays.set(channelData, true); getChannelDataAlreadyFakedArrays.set(channelData, true);
} }
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
return ret; return ret;
}); });
}; };
@ -260,11 +261,12 @@
getFrequencyResponse: { getFrequencyResponse: {
object: ["BiquadFilterNode", "IIRFilterNode"], object: ["BiquadFilterNode", "IIRFilterNode"],
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function getFrequencyResponse(frequencyArray, magResponseOutput, phaseResponseOutput){ return function getFrequencyResponse(frequencyArray, magResponseOutput, phaseResponseOutput){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
notify("fakedAudioReadout"); notify("fakedAudioReadout");
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
fakeFloat32Array(magResponseOutput, window, prefs); fakeFloat32Array(magResponseOutput, window, prefs);
fakeFloat32Array(phaseResponseOutput, window, prefs); fakeFloat32Array(phaseResponseOutput, window, prefs);
return ret; return ret;

View File

@ -10,7 +10,7 @@
const {copyCanvasToWebgl} = require("./webgl"); const {copyCanvasToWebgl} = require("./webgl");
const {getWrapped, checkerWrapper} = require("./modifiedAPIFunctions"); const {getWrapped, checkerWrapper} = require("./modifiedAPIFunctions");
var randomSupply = null; let randomSupply = null;
function getContext(window, canvas){ function getContext(window, canvas){
return window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d") || return window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d") ||
@ -20,8 +20,8 @@
window.HTMLCanvasElement.prototype.getContext.call(canvas, "experimental-webgl2"); window.HTMLCanvasElement.prototype.getContext.call(canvas, "experimental-webgl2");
} }
function getImageData(window, context){ function getImageData(window, context){
var imageData; let imageData;
var source; let source;
if ((context.canvas.width || 0) * (context.canvas.height || 0) === 0){ if ((context.canvas.width || 0) * (context.canvas.height || 0) === 0){
imageData = new (getWrapped(window).ImageData)(0, 0); imageData = new (getWrapped(window).ImageData)(0, 0);
source = new (getWrapped(window).ImageData)(0, 0); source = new (getWrapped(window).ImageData)(0, 0);
@ -54,24 +54,25 @@
}; };
} }
var canvasCache = Object.create(null); const canvasCache = Object.create(null);
function getFakeCanvas(window, original, prefs){ function getFakeCanvas(window, original, prefs){
try { try {
let originalDataURL;
if (prefs("useCanvasCache")){ if (prefs("useCanvasCache")){
var originalDataURL = original.toDataURL(); originalDataURL = original.toDataURL();
var cached = canvasCache[originalDataURL]; const cached = canvasCache[originalDataURL];
if (cached){ if (cached){
return cached; return cached;
} }
} }
// original may not be a canvas -> we must not leak an error // original may not be a canvas -> we must not leak an error
var context = getContext(window, original); let context = getContext(window, original);
var {imageData, source} = getImageData(window, context); const {imageData, source} = getImageData(window, context);
var desc = imageData.data; const desc = imageData.data;
var l = desc.length; const l = desc.length;
var ignoredColors = {}; let ignoredColors = {};
var statistic; let statistic;
if (prefs("ignoreFrequentColors")){ if (prefs("ignoreFrequentColors")){
statistic = colorStatistics.compute(source); statistic = colorStatistics.compute(source);
ignoredColors = statistic.getMaxColors(prefs("ignoreFrequentColors")); ignoredColors = statistic.getMaxColors(prefs("ignoreFrequentColors"));
@ -82,10 +83,10 @@
} }
} }
var rng = randomSupply.getPixelRng(l, window, ignoredColors); const rng = randomSupply.getPixelRng(l, window, ignoredColors);
var fakeAlphaChannel = prefs("fakeAlphaChannel"); const fakeAlphaChannel = prefs("fakeAlphaChannel");
for (var i = 0; i < l; i += 4){ for (let i = 0; i < l; i += 4){
var [r, g, b, a] = rng( const [r, g, b, a] = rng(
source[i + 0], source[i + 0],
source[i + 1], source[i + 1],
source[i + 2], source[i + 2],
@ -97,7 +98,7 @@
desc[i + 2] = b; desc[i + 2] = b;
desc[i + 3] = fakeAlphaChannel? a: source[i + 3]; desc[i + 3] = fakeAlphaChannel? a: source[i + 3];
} }
var canvas = original.cloneNode(true); const canvas = original.cloneNode(true);
context = window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d"); context = window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d");
context.putImageData(imageData, 0, 0); context.putImageData(imageData, 0, 0);
if (prefs("useCanvasCache")){ if (prefs("useCanvasCache")){
@ -106,25 +107,25 @@
} }
return canvas; return canvas;
} }
catch (e){ catch (error){
logging.warning("Error while faking:", e); logging.warning("Error while faking:", error);
return original; return original;
} }
} }
function randomMixImageData(window, imageData1, imageData2){ function randomMixImageData(window, imageData1, imageData2){
var data1 = imageData1.data; const data1 = imageData1.data;
var data2 = imageData2.data; const data2 = imageData2.data;
var l = data1.length; const l = data1.length;
if (l === data2.length){ if (l === data2.length){
var rng = randomSupply.getPixelRng(l, window, {}); const rng = randomSupply.getPixelRng(l, window, {});
for (var i = 0; i < l; i += 4){ for (let i = 0; i < l; i += 4){
const signR = data1[i + 0] > data2[i + 0]? -1: 1; const signR = data1[i + 0] > data2[i + 0]? -1: 1;
const signG = data1[i + 1] > data2[i + 1]? -1: 1; const signG = data1[i + 1] > data2[i + 1]? -1: 1;
const signB = data1[i + 2] > data2[i + 2]? -1: 1; const signB = data1[i + 2] > data2[i + 2]? -1: 1;
const signA = data1[i + 3] > data2[i + 3]? -1: 1; const signA = data1[i + 3] > data2[i + 3]? -1: 1;
var [deltaR, deltaG, deltaB, deltaA] = rng( const [deltaR, deltaG, deltaB, deltaA] = rng(
signR * (data2[i + 0] - data1[i + 0]), signR * (data2[i + 0] - data1[i + 0]),
signG * (data2[i + 1] - data1[i + 1]), signG * (data2[i + 1] - data1[i + 1]),
signB * (data2[i + 2] - data1[i + 2]), signB * (data2[i + 2] - data1[i + 2]),
@ -142,9 +143,9 @@
function canvasSizeShouldBeFaked(canvas, prefs){ function canvasSizeShouldBeFaked(canvas, prefs){
if (canvas){ if (canvas){
var size = canvas.height * canvas.width; const size = canvas.height * canvas.width;
var maxSize = prefs("maxFakeSize") || Number.POSITIVE_INFINITY; const maxSize = prefs("maxFakeSize") || Number.POSITIVE_INFINITY;
var minSize = prefs("minFakeSize") || 0; const minSize = prefs("minFakeSize") || 0;
return size > minSize && size <= maxSize; return size > minSize && size <= maxSize;
} }
else { else {
@ -181,7 +182,98 @@
scope.setRandomSupply = function(supply){ scope.setRandomSupply = function(supply){
randomSupply = supply; randomSupply = supply;
}; };
var canvasContextType = new WeakMap();
function getNumber(originalValue, max, index, window){
const bitLength = Math.floor(Math.log2(max) + 1);
const rng = randomSupply.getBitRng(bitLength, window);
let value = 0;
for (let i = 0; i < bitLength; i += 1){
value <<= 1;
value ^= rng(originalValue, index + i);
}
return value;
}
const parameterFakeTypes = {
decimal: function(originalValue, definition, window){
const int = Math.floor(originalValue);
if (int !== originalValue){
const decimal = originalValue - int;
const rng = randomSupply.getRng(1, window);
const newDecimal = decimal * (rng(definition.pname) / 0xFFFFFFFF);
return int + newDecimal;
}
else {
return originalValue;
}
},
shift: function(originalValue, definition, window){
const value = getNumber(originalValue, definition.max, definition.pname, window);
return originalValue >>> value;
},
"-": function(originalValue, definition, window){
const value = getNumber(originalValue, definition.max, definition.pname, window) *
(definition.factor || 1);
if (value > originalValue){
return 0;
}
return originalValue - value;
}
};
const parameterChangeDefinition = {
2928: {name: "DEPTH_RANGE", type: "decimal", isArray: true},
3379: {name: "MAX_TEXTURE_SIZE", type: "shift", max: 1},
3386: {name: "MAX_VIEWPORT_DIMS", type: "shift", max: 1, isArray: true},
32883: {name: "MAX_3D_TEXTURE_SIZE", type: "shift", max: 1},
33000: {name: "MAX_ELEMENTS_VERTICES", type: "-", max: 3, factor: 50},
33001: {name: "MAX_ELEMENTS_INDICES", type: "-", max: 3, factor: 50},
33901: {name: "ALIASED_POINT_SIZE_RANGE", type: "decimal", isArray: true},
33902: {name: "ALIASED_LINE_WIDTH_RANGE", type: "decimal", isArray: true},
34024: {name: "MAX_RENDERBUFFER_SIZE", type: "shift", max: 1},
34045: {name: "MAX_TEXTURE_LOD_BIAS", type: "-", max: 1, factor: 1},
34076: {name: "MAX_CUBE_MAP_TEXTURE_SIZE", type: "shift", max: 1},
34921: {name: "MAX_VERTEX_ATTRIBS", type: "shift", max: 1},
34930: {name: "MAX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
35071: {name: "MAX_ARRAY_TEXTURE_LAYERS", type: "shift", max: 1},
35371: {name: "MAX_VERTEX_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
35373: {name: "MAX_FRAGMENT_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
35374: {name: "MAX_COMBINED_UNIFORM_BLOCKS", type: "-", max: 3, factor: 1},
35375: {name: "MAX_UNIFORM_BUFFER_BINDINGS", type: "-", max: 3, factor: 1},
35376: {name: "MAX_UNIFORM_BLOCK_SIZE", type: "shift", max: 1},
35377: {name: "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
35379: {name: "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
35657: {name: "MAX_FRAGMENT_UNIFORM_COMPONENTS", type: "shift", max: 1},
35658: {name: "MAX_VERTEX_UNIFORM_COMPONENTS", type: "shift", max: 1},
35659: {name: "MAX_VARYING_COMPONENTS", type: "shift", max: 1},
35660: {name: "MAX_VERTEX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
35661: {name: "MAX_COMBINED_TEXTURE_IMAGE_UNITS", type: "-", max: 1, factor: 2},
35968: {name: "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", type: "shift", max: 1},
35978: {name: "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", type: "shift", max: 1},
36203: {name: "MAX_ELEMENT_INDEX", type: "-", max: 15, factor: 1},
36347: {name: "MAX_VERTEX_UNIFORM_VECTORS", type: "shift", max: 1},
36348: {name: "MAX_VARYING_VECTORS", type: "shift", max: 1},
36349: {name: "MAX_FRAGMENT_UNIFORM_VECTORS", type: "shift", max: 1},
37154: {name: "MAX_VERTEX_OUTPUT_COMPONENTS", type: "shift", max: 1},
37157: {name: "MAX_FRAGMENT_INPUT_COMPONENTS", type: "shift", max: 1},
7936: {name: "VENDOR", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLVendor") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}},
7937: {name: "RENDERER", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLRenderer") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}},
37445: {name: "UNMASKED_VENDOR_WEBGL", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLUnmaskedVendor") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}},
37446: {name: "UNMASKED_RENDERER_WEBGL", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLUnmaskedRenderer") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}}
};
const canvasContextType = new WeakMap();
// changed functions and their fakes // changed functions and their fakes
scope.changedFunctions = { scope.changedFunctions = {
getContext: { getContext: {
@ -209,9 +301,10 @@
}, },
object: "HTMLCanvasElement", object: "HTMLCanvasElement",
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function(context, contextAttributes){ return function(context, contextAttributes){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {window, original} = check;
canvasContextType.set(this, context); canvasContextType.set(this, context);
return original.apply(this, window.Array.from(args)); return original.apply(this, window.Array.from(args));
}); });
@ -225,7 +318,7 @@
status = Object.create(status); status = Object.create(status);
status.active = protectedPartChecker("readout"); status.active = protectedPartChecker("readout");
if (!status.active && protectedPartChecker("input")){ if (!status.active && protectedPartChecker("input")){
var contextType = canvasContextType.get(obj); const contextType = canvasContextType.get(obj);
status.active = contextType !== "2d"; status.active = contextType !== "2d";
} }
return status; return status;
@ -234,9 +327,9 @@
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function toDataURL(){ return function toDataURL(){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
if (canvasSizeShouldBeFaked(this, prefs)){ if (canvasSizeShouldBeFaked(this, prefs)){
var fakeCanvas = getFakeCanvas(window, this, prefs); const fakeCanvas = getFakeCanvas(window, this, prefs);
if (fakeCanvas !== this){ if (fakeCanvas !== this){
notify("fakedReadout"); notify("fakedReadout");
} }
@ -256,18 +349,19 @@
status = Object.create(status); status = Object.create(status);
status.active = protectedPartChecker("readout"); status.active = protectedPartChecker("readout");
if (!status.active && protectedPartChecker("input")){ if (!status.active && protectedPartChecker("input")){
var contextType = canvasContextType.get(obj); const contextType = canvasContextType.get(obj);
status.active = contextType !== "2d"; status.active = contextType !== "2d";
} }
return status; return status;
}, },
object: "HTMLCanvasElement", object: "HTMLCanvasElement",
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function toBlob(callback){ return function toBlob(callback){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
if (canvasSizeShouldBeFaked(this, prefs)){ if (canvasSizeShouldBeFaked(this, prefs)){
var fakeCanvas = getFakeCanvas(window, this, prefs); const fakeCanvas = getFakeCanvas(window, this, prefs);
if (fakeCanvas !== this){ if (fakeCanvas !== this){
notify("fakedReadout"); notify("fakedReadout");
} }
@ -288,18 +382,19 @@
status = Object.create(status); status = Object.create(status);
status.active = protectedPartChecker("readout"); status.active = protectedPartChecker("readout");
if (!status.active && protectedPartChecker("input")){ if (!status.active && protectedPartChecker("input")){
var contextType = canvasContextType.get(obj); const contextType = canvasContextType.get(obj);
status.active = contextType !== "2d"; status.active = contextType !== "2d";
} }
return status; return status;
}, },
object: "HTMLCanvasElement", object: "HTMLCanvasElement",
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function mozGetAsFile(callback){ return function mozGetAsFile(callback){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
if (canvasSizeShouldBeFaked(this, prefs)){ if (canvasSizeShouldBeFaked(this, prefs)){
var fakeCanvas = getFakeCanvas(window, this, prefs); const fakeCanvas = getFakeCanvas(window, this, prefs);
if (fakeCanvas !== this){ if (fakeCanvas !== this){
notify("fakedReadout"); notify("fakedReadout");
} }
@ -322,12 +417,13 @@
}, },
object: "CanvasRenderingContext2D", object: "CanvasRenderingContext2D",
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function getImageData(sx, sy, sw, sh){ return function getImageData(sx, sy, sw, sh){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){ if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
var fakeCanvas; let fakeCanvas;
var context = this; let context = this;
if (this && this.canvas) { if (this && this.canvas) {
fakeCanvas = getFakeCanvas(window, this.canvas, prefs); fakeCanvas = getFakeCanvas(window, this.canvas, prefs);
} }
@ -359,12 +455,12 @@
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function isPointInPath(x, y){ return function isPointInPath(x, y){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {notify, window, original} = check;
var rng = randomSupply.getValueRng(1, window); const rng = randomSupply.getValueRng(1, window);
var originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
if ((typeof originalValue) === "boolean"){ if ((typeof originalValue) === "boolean"){
notify("fakedReadout"); notify("fakedReadout");
var index = x + this.width * y; const index = x + this.width * y;
return original.call(this, rng(x, index), rng(y, index), args[2]); return original.call(this, rng(x, index), rng(y, index), args[2]);
} }
else { else {
@ -386,9 +482,9 @@
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function isPointInStroke(x, y){ return function isPointInStroke(x, y){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {notify, window, original} = check;
var rng = randomSupply.getValueRng(1, window); const rng = randomSupply.getValueRng(1, window);
var originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
if ((typeof originalValue) === "boolean"){ if ((typeof originalValue) === "boolean"){
notify("fakedReadout"); notify("fakedReadout");
if (x instanceof window.Path2D){ if (x instanceof window.Path2D){
@ -420,22 +516,23 @@
}, },
object: "CanvasRenderingContext2D", object: "CanvasRenderingContext2D",
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function fillText(str, x, y){ return function fillText(str, x, y){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){ if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
notify("fakedInput"); notify("fakedInput");
var oldImageData; let oldImageData;
try { try {
// "this" is not trustable - it may be not a context // "this" is not trustable - it may be not a context
oldImageData = getImageData(window, this).imageData; oldImageData = getImageData(window, this).imageData;
} }
catch (e){ catch (error){
// nothing to do here // nothing to do here
} }
// if "this" is not a correct context the next line will throw an error // if "this" is not a correct context the next line will throw an error
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
var newImageData = getImageData(window, this).imageData; const newImageData = getImageData(window, this).imageData;
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0); this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
return ret; return ret;
} }
@ -456,22 +553,23 @@
}, },
object: "CanvasRenderingContext2D", object: "CanvasRenderingContext2D",
fakeGenerator: function(checker){ fakeGenerator: function(checker){
// eslint-disable-next-line no-unused-vars
return function strokeText(str, x, y){ return function strokeText(str, x, y){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){ if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
notify("fakedInput"); notify("fakedInput");
var oldImageData; let oldImageData;
try { try {
// "this" is not trustable - it may be not a context // "this" is not trustable - it may be not a context
oldImageData = getImageData(window, this).imageData; oldImageData = getImageData(window, this).imageData;
} }
catch (e){ catch (error){
// nothing to do here // nothing to do here
} }
// if "this" is not a correct context the next line will throw an error // if "this" is not a correct context the next line will throw an error
var ret = original.apply(this, window.Array.from(args)); const ret = original.apply(this, window.Array.from(args));
var newImageData = getImageData(window, this).imageData; const newImageData = getImageData(window, this).imageData;
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0); this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
return ret; return ret;
} }
@ -492,13 +590,14 @@
}, },
object: ["WebGLRenderingContext", "WebGL2RenderingContext"], object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
fakeGenerator: function(checker){ fakeGenerator: function(checker){
return function readPixels(x, y, width, height, format, type, pixels){ // eslint-disable-line max-params // eslint-disable-next-line max-params, no-unused-vars
return function readPixels(x, y, width, height, format, type, pixels){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){ if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
notify("fakedReadout"); notify("fakedReadout");
var fakeCanvas = getFakeCanvas(window, this.canvas, prefs); const fakeCanvas = getFakeCanvas(window, this.canvas, prefs);
var {context} = copyCanvasToWebgl( const {context} = copyCanvasToWebgl(
window, window,
fakeCanvas, fakeCanvas,
this instanceof window.WebGLRenderingContext? "webgl": "webgl2" this instanceof window.WebGLRenderingContext? "webgl": "webgl2"
@ -522,111 +621,22 @@
}, },
object: ["WebGLRenderingContext", "WebGL2RenderingContext"], object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
fakeGenerator: function(checker){ fakeGenerator: function(checker){
function getNumber(originalValue, max, index, window){ Object.keys(parameterChangeDefinition).forEach(function(parameterName){
const bitLength = Math.floor(Math.log2(max) + 1); const definition = parameterChangeDefinition[parameterName];
const rng = randomSupply.getBitRng(bitLength, window);
let value = 0;
for (let i = 0; i < bitLength; i += 1){
value <<= 1;
value ^= rng(originalValue, index + i);
}
return value;
}
const types = {
decimal: function(originalValue, definition, window){
const int = Math.floor(originalValue);
if (int !== originalValue){
const decimal = originalValue - int;
const rng = randomSupply.getRng(1, window);
const newDecimal = decimal * (rng(definition.pname) / 0xFFFFFFFF);
return int + newDecimal;
}
else {
return originalValue;
}
},
shift: function(originalValue, definition, window){
const value = getNumber(originalValue, definition.max, definition.pname, window);
return originalValue >>> value;
},
"-": function(originalValue, definition, window){
const value = getNumber(originalValue, definition.max, definition.pname, window) *
(definition.factor || 1);
if (value > originalValue){
return 0;
}
return originalValue - value;
}
};
const changeDefinition = {
2928: {name: "DEPTH_RANGE", type: "decimal", isArray: true},
3379: {name: "MAX_TEXTURE_SIZE", type: "shift", max: 1},
3386: {name: "MAX_VIEWPORT_DIMS", type: "shift", max: 1, isArray: true},
32883: {name: "MAX_3D_TEXTURE_SIZE", type: "shift", max: 1},
33000: {name: "MAX_ELEMENTS_VERTICES", type: "-", max: 3, factor: 50},
33001: {name: "MAX_ELEMENTS_INDICES", type: "-", max: 3, factor: 50},
33901: {name: "ALIASED_POINT_SIZE_RANGE", type: "decimal", isArray: true},
33902: {name: "ALIASED_LINE_WIDTH_RANGE", type: "decimal", isArray: true},
34024: {name: "MAX_RENDERBUFFER_SIZE", type: "shift", max: 1},
34045: {name: "MAX_TEXTURE_LOD_BIAS", type: "-", max: 1, factor: 1},
34076: {name: "MAX_CUBE_MAP_TEXTURE_SIZE", type: "shift", max: 1},
34921: {name: "MAX_VERTEX_ATTRIBS", type: "shift", max: 1},
34930: {name: "MAX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
35071: {name: "MAX_ARRAY_TEXTURE_LAYERS", type: "shift", max: 1},
35371: {name: "MAX_VERTEX_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
35373: {name: "MAX_FRAGMENT_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
35374: {name: "MAX_COMBINED_UNIFORM_BLOCKS", type: "-", max: 3, factor: 1},
35375: {name: "MAX_UNIFORM_BUFFER_BINDINGS", type: "-", max: 3, factor: 1},
35376: {name: "MAX_UNIFORM_BLOCK_SIZE", type: "shift", max: 1},
35377: {name: "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
35379: {name: "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
35657: {name: "MAX_FRAGMENT_UNIFORM_COMPONENTS", type: "shift", max: 1},
35658: {name: "MAX_VERTEX_UNIFORM_COMPONENTS", type: "shift", max: 1},
35659: {name: "MAX_VARYING_COMPONENTS", type: "shift", max: 1},
35660: {name: "MAX_VERTEX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
35661: {name: "MAX_COMBINED_TEXTURE_IMAGE_UNITS", type: "-", max: 1, factor: 2},
35968: {name: "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", type: "shift", max: 1},
35978: {name: "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", type: "shift", max: 1},
36203: {name: "MAX_ELEMENT_INDEX", type: "-", max: 15, factor: 1},
36347: {name: "MAX_VERTEX_UNIFORM_VECTORS", type: "shift", max: 1},
36348: {name: "MAX_VARYING_VECTORS", type: "shift", max: 1},
36349: {name: "MAX_FRAGMENT_UNIFORM_VECTORS", type: "shift", max: 1},
37154: {name: "MAX_VERTEX_OUTPUT_COMPONENTS", type: "shift", max: 1},
37157: {name: "MAX_FRAGMENT_INPUT_COMPONENTS", type: "shift", max: 1},
7936: {name: "VENDOR", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLVendor") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}},
7937: {name: "RENDERER", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLRenderer") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}},
37445: {name: "UNMASKED_VENDOR_WEBGL", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLUnmaskedVendor") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}},
37446: {name: "UNMASKED_RENDERER_WEBGL", fake: function(originalValue, window, prefs){
const settingValue = prefs("webGLUnmaskedRenderer") || originalValue;
return {value: settingValue, faked: settingValue === originalValue};
}}
};
const parameterNames = Object.keys(changeDefinition);
parameterNames.forEach(function(parameterName){
const definition = changeDefinition[parameterName];
definition.pname = parameterName; definition.pname = parameterName;
if (!definition.fake){ if (!definition.fake){
definition.fake = definition.isArray? definition.fake = definition.isArray?
function fake(originalValue, window){ function fake(originalValue, window){
let faked = false; let faked = false;
let fakedValue = []; let fakedValue = [];
for (var i = 0; i < originalValue.length; i += 1){ for (let i = 0; i < originalValue.length; i += 1){
fakedValue[i] = types[this.type](originalValue[i], this, window); fakedValue[i] = parameterFakeTypes[this.type](originalValue[i], this, window);
faked |= originalValue[i] === fakedValue[i]; faked |= originalValue[i] === fakedValue[i];
originalValue[i] = fakedValue[i]; originalValue[i] = fakedValue[i];
} }
this.fake = function(originalValue){ this.fake = function(originalValue){
if (faked){ if (faked){
for (var i = 0; i < originalValue.length; i += 1){ for (let i = 0; i < originalValue.length; i += 1){
originalValue[i] = fakedValue[i]; originalValue[i] = fakedValue[i];
} }
} }
@ -641,7 +651,7 @@
}; };
}: }:
function fake(originalValue, window){ function fake(originalValue, window){
let value = types[this.type](originalValue, this, window); let value = parameterFakeTypes[this.type](originalValue, this, window);
let faked = value === originalValue; let faked = value === originalValue;
this.fake = function(){ this.fake = function(){
return {value, faked}; return {value, faked};
@ -652,10 +662,10 @@
}); });
return function getParameter(pname){ return function getParameter(pname){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
var {prefs, notify, window, original} = check; const {prefs, notify, window, original} = check;
const originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
if (changeDefinition[pname]){ if (parameterChangeDefinition[pname]){
const definition = changeDefinition[pname]; const definition = parameterChangeDefinition[pname];
const {value, faked} = definition.fake(originalValue, window, prefs); const {value, faked} = definition.fake(originalValue, window, prefs);
if (faked){ if (faked){
notify("fakedReadout"); notify("fakedReadout");

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -23,7 +23,7 @@
const temp = eval(`({ const temp = eval(`({
get ${property}(){ get ${property}(){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check; const {notify, window, original} = check;
const originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
const returnValue = navigator.getNavigatorValue("${property}"); const returnValue = navigator.getNavigatorValue("${property}");
if (originalValue !== returnValue){ if (originalValue !== returnValue){

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -177,7 +177,7 @@
const temp = { const temp = {
get availLeft(){ get availLeft(){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check; const {notify, window, original} = check;
const originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
if (originalValue !== 0){ if (originalValue !== 0){
notify("fakedScreenReadout"); notify("fakedScreenReadout");
@ -196,7 +196,7 @@
const temp = { const temp = {
get availTop(){ get availTop(){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check; const {notify, window, original} = check;
const originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
if (originalValue !== 0){ if (originalValue !== 0){
notify("fakedScreenReadout"); notify("fakedScreenReadout");
@ -215,7 +215,7 @@
const temp = { const temp = {
get outerWidth(){ get outerWidth(){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check; const {notify, window, original} = check;
const originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
const returnValue = window.innerWidth; const returnValue = window.innerWidth;
if (originalValue !== returnValue){ if (originalValue !== returnValue){
@ -235,7 +235,7 @@
const temp = { const temp = {
get outerHeight(){ get outerHeight(){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check; const {notify, window, original} = check;
const originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
const returnValue = window.innerHeight; const returnValue = window.innerHeight;
if (originalValue !== returnValue){ if (originalValue !== returnValue){

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -77,7 +77,7 @@
settings.protectedAPIFeatures["userAgent @ navigator"] settings.protectedAPIFeatures["userAgent @ navigator"]
) )
){ ){
for (var header of details.requestHeaders){ for (let header of details.requestHeaders){
if (header.name.toLowerCase() === "user-agent"){ if (header.name.toLowerCase() === "user-agent"){
header.value = getValue("userAgent"); header.value = getValue("userAgent");
} }

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -170,6 +170,9 @@
tabs.forEach(function(tab){ tabs.forEach(function(tab){
browser.pageAction.hide(tab.id); browser.pageAction.hide(tab.id);
}); });
return;
}).catch(function(error){
logging.warning("Unable to get browser tabs:", error);
}); });
} }
}); });
@ -188,6 +191,9 @@
text: "" text: ""
}); });
}); });
return;
}).catch(function(error){
logging.warning("Unable to get browser tabs:", error);
}); });
} }
} }

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -18,6 +18,7 @@
scope.persistentRnd = Object.create(null); scope.persistentRnd = Object.create(null);
scope.persistentIncognitoRnd = Object.create(null); scope.persistentIncognitoRnd = Object.create(null);
let clearTimeout;
scope.init = function init(){ scope.init = function init(){
logging.message("initializing persistent rng storage"); logging.message("initializing persistent rng storage");
@ -26,8 +27,8 @@
if (settings.storePersistentRnd){ if (settings.storePersistentRnd){
try { try {
let storedData = JSON.parse(settings.persistentRndStorage); let storedData = JSON.parse(settings.persistentRndStorage);
for (var domain in storedData){ for (let domain in storedData){
var value = storedData[domain]; const value = storedData[domain];
if ( if (
Array.isArray(value) && Array.isArray(value) &&
value.length === 128 && value.length === 128 &&
@ -39,7 +40,7 @@
} }
} }
} }
catch (e){ catch (error){
// JSON is not valid -> ignore it // JSON is not valid -> ignore it
} }
} }
@ -74,7 +75,7 @@
}; };
const getInterval = function(){ const getInterval = function(){
var units = { const units = {
seconds: 1000, seconds: 1000,
minutes: 60 * 1000, minutes: 60 * 1000,
hours: 60 * 60 * 1000, hours: 60 * 60 * 1000,
@ -95,18 +96,20 @@
})){ })){
clearIncognito(); clearIncognito();
} }
return;
}).catch(function(error){
logging.warning("Unable to get browser windows:", error);
}); });
}); });
let clearTimeout;
function registerTimeout(){ function registerTimeout(){
var interval = getInterval(); const interval = getInterval();
if (interval > 0){ if (interval > 0){
var timeout = settings.lastPersistentRndClearing + interval - Date.now(); const timeout = settings.lastPersistentRndClearing + interval - Date.now();
logging.message("registering persistent rng data clearing timeout. Clearing in ", timeout, "ms"); logging.message("registering persistent rng data clearing timeout. Clearing in ", timeout, "ms");
if (timeout > 1073741824){ if (timeout > 1073741824){
// window.setTimeout can only handle delays up to 32 bit. // window.setTimeout can only handle delays up to 32 bit.
// Therefore we repeat the registering afert 2^30 = 1073741824 seconds // Therefore we repeat the registering after 2^30 = 1073741824 seconds
clearTimeout = window.setTimeout(registerTimeout, 1073741824); clearTimeout = window.setTimeout(registerTimeout, 1073741824);
} }
else { else {
@ -119,6 +122,9 @@
tabs.forEach(function(tab){ tabs.forEach(function(tab){
browser.tabs.sendMessage(tab.id, data); browser.tabs.sendMessage(tab.id, data);
}); });
return;
}).catch(function(error){
logging.warning("Unable to get browser tabs:", error);
}); });
} }
function clearIncognito(){ function clearIncognito(){

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -15,7 +15,6 @@
const rngTemplate = { const rngTemplate = {
getBitRng: function(length, window){ getBitRng: function(length, window){
const rng = this.getRng(Math.ceil(length / 32), window); const rng = this.getRng(Math.ceil(length / 32), window);
let bitIndex = 32;
let rnd = 0; let rnd = 0;
let mask = 0xffffffff * 2; let mask = 0xffffffff * 2;
return function(value, i){ return function(value, i){
@ -38,20 +37,21 @@
getValueRng: function(length, window){ getValueRng: function(length, window){
const rng = this.getBitRng(length, window); const rng = this.getBitRng(length, window);
return function(value, i){ return function(value, i){
var rnd = rng(value, i); const rnd = rng(value, i);
// XOR the last bit to alter it... or not // XOR the last bit to alter it... or not
return value ^ (rnd & 0x01); return value ^ (rnd & 0x01);
}; };
}, },
getPixelRng: function(length, window, ignoredColors){ getPixelRng: function(length, window, ignoredColors){
var rng = this.getValueRng(length, window); const rng = this.getValueRng(length, window);
return function(r, g, b, a, i){ // eslint-disable-line max-params // eslint-disable-next-line max-params
var index = String.fromCharCode(r, g, b, a); return function(r, g, b, a, i){
const index = String.fromCharCode(r, g, b, a);
if (ignoredColors[index]){ if (ignoredColors[index]){
return [r, g, b, a]; return [r, g, b, a];
} }
var baseIndex = i * 4; const baseIndex = i * 4;
return [ return [
rng(r, baseIndex + 0), rng(r, baseIndex + 0),
rng(g, baseIndex + 1), rng(g, baseIndex + 1),
@ -81,7 +81,7 @@
return window.location.host; return window.location.host;
} }
var persistentRnd = Object.create(null); let persistentRnd = Object.create(null);
let cookieStoreId = false; let cookieStoreId = false;
settings.onloaded(function(){ settings.onloaded(function(){
try { try {
@ -90,8 +90,8 @@
settings.persistentIncognitoRndStorage: settings.persistentIncognitoRndStorage:
settings.persistentRndStorage settings.persistentRndStorage
); );
for (var domain in storedData){ for (let domain in storedData){
var value = storedData[domain]; const value = storedData[domain];
if ( if (
Array.isArray(value) && Array.isArray(value) &&
value.length === 128 && value.length === 128 &&
@ -103,7 +103,7 @@
} }
} }
} }
catch (e){ catch (error){
// JSON is not valid -> ignore it // JSON is not valid -> ignore it
} }
}); });
@ -111,7 +111,7 @@
extension.message.on(function(data){ extension.message.on(function(data){
if (data["canvasBlocker-set-domain-rnd"]){ if (data["canvasBlocker-set-domain-rnd"]){
var {domain, incognito, rnd} = data["canvasBlocker-set-domain-rnd"]; const {domain, incognito, rnd} = data["canvasBlocker-set-domain-rnd"];
if (incognito === extension.inIncognitoContext){ if (incognito === extension.inIncognitoContext){
persistentRnd[domain] = new Uint8Array(rnd); persistentRnd[domain] = new Uint8Array(rnd);
} }
@ -130,11 +130,11 @@
xhr.send(); xhr.send();
xhr = null; xhr = null;
} }
catch (e){ catch (error){
logging.verbose("Error in XHR:", e); logging.verbose("Error in XHR:", error);
} }
} }
var domain = cookieStoreId + getDomain(window); const domain = cookieStoreId + getDomain(window);
if (!persistentRnd[domain]){ if (!persistentRnd[domain]){
// create the (sub-)domains random numbers if not existing // create the (sub-)domains random numbers if not existing
persistentRnd[domain] = new Uint8Array(128); persistentRnd[domain] = new Uint8Array(128);
@ -165,26 +165,26 @@
} }
}; };
scope.persistent.getRng = function(length, window){ scope.persistent.getRng = function(length, window){
var bitSet = new Uint32Array(getPersistentRnd(window).buffer); const bitSet = new Uint32Array(getPersistentRnd(window).buffer);
var bitSetLength = bitSet.length; const bitSetLength = bitSet.length;
return function(i){ return function(i){
return bitSet[i % bitSetLength]; return bitSet[i % bitSetLength];
}; };
}; };
scope.persistent.getBitRng = function(length, window){ scope.persistent.getBitRng = function(length, window){
var bitSet = getPersistentRnd(window); const bitSet = getPersistentRnd(window);
return function(value, i){ return function(value, i){
// use the last 7 bits from the value for the index of the // use the last 7 bits from the value for the index of the
// random number // random number
var index = value & 0x7F; const index = value & 0x7F;
// use the last 3 bits from the position and the first bit from // use the last 3 bits from the position and the first bit from
// from the value to get bit to use from the random number // from the value to get bit to use from the random number
var bitIndex = ((i & 0x03) << 1) | (value >>> 7); const bitIndex = ((i & 0x03) << 1) | (value >>> 7);
// extract the bit // extract the bit
var bit = (bitSet[index] >>> bitIndex) & 0x01; const bit = (bitSet[index] >>> bitIndex) & 0x01;
return bit; return bit;
}; };
@ -196,16 +196,17 @@
return scope.nonPersistent.getRng(length, window); return scope.nonPersistent.getRng(length, window);
}; };
scope.constant.getPixelRng = (function(){ scope.constant.getPixelRng = (function(){
var colors = Object.create(null); const colors = Object.create(null);
return function getConstantPixelRng(length, window, ignoredColors){ return function getConstantPixelRng(length, window, ignoredColors){
var rng = scope.nonPersistent.getValueRng(1024, window); const rng = scope.nonPersistent.getValueRng(1024, window);
return function(r, g, b, a, i){ // eslint-disable-line max-params // eslint-disable-next-line max-params, no-unused-vars
var index = String.fromCharCode(r, g, b, a); return function(r, g, b, a, i){
const index = String.fromCharCode(r, g, b, a);
if (ignoredColors[index]){ if (ignoredColors[index]){
return [r, g, b, a]; return [r, g, b, a];
} }
var color = colors[index]; let color = colors[index];
if (!color){ if (!color){
color = [ color = [
rng(r, 0), rng(r, 0),
@ -224,8 +225,8 @@
scope.nonPersistent.name = "nonPersistent"; scope.nonPersistent.name = "nonPersistent";
scope.nonPersistent.getRng = function(length, window){ scope.nonPersistent.getRng = function(length, window){
const maxLength = 0x4000; const maxLength = 0x4000;
var randomI = maxLength; let randomI = maxLength;
var randomNumbers = new Uint32Array(Math.min(maxLength, length)); let randomNumbers = new Uint32Array(Math.min(maxLength, length));
return function(i){ return function(i){
if (randomI >= randomNumbers.length){ if (randomI >= randomNumbers.length){
// refill the random number bucket if empty // refill the random number bucket if empty
@ -235,7 +236,7 @@
} }
window.crypto.getRandomValues(randomNumbers); window.crypto.getRandomValues(randomNumbers);
} }
var rnd = randomNumbers[randomI]; const rnd = randomNumbers[randomI];
randomI += 1; randomI += 1;
return rnd; return rnd;

View File

@ -10,14 +10,14 @@ const require = function(){
const scope = window.scope; const scope = window.scope;
function getScopeName(module){ function getScopeName(module){
var scopeName = module.replace(/^\..*\//, "").replace(/\..+/, ""); const scopeName = module.replace(/^\..*\//, "").replace(/\..+/, "");
// console.log(scopeName); // console.log(scopeName);
return scopeName; return scopeName;
} }
function require(module){ function require(module){
if (module.startsWith(".")){ if (module.startsWith(".")){
var scopeName = getScopeName(module); const scopeName = getScopeName(module);
return scope[scopeName]; return scope[scopeName];
} }
throw new ReferenceError("Unable to get non relative module " + module + "!"); throw new ReferenceError("Unable to get non relative module " + module + "!");

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -35,7 +35,7 @@
if (resultSets.length){ if (resultSets.length){
return Array.from( return Array.from(
resultSets.reduce(function(previousSet, set){ resultSets.reduce(function(previousSet, set){
var andSet = new Set(); const andSet = new Set();
set.forEach(function(entry){ set.forEach(function(entry){
if (previousSet.has(entry)){ if (previousSet.has(entry)){
andSet.add(entry); andSet.add(entry);

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -19,7 +19,7 @@
scope.expandContainer = null; scope.expandContainer = null;
scope.getUrlValueContainer = function(name, url){ scope.getUrlValueContainer = function(name, url){
var matching = scope.urlContainer.get().filter(function(urlSetting){ const matching = scope.urlContainer.get().filter(function(urlSetting){
return urlSetting.hasOwnProperty(name); return urlSetting.hasOwnProperty(name);
}).filter(function(urlSetting){ }).filter(function(urlSetting){
return urlSetting.match(url); return urlSetting.match(url);
@ -32,8 +32,8 @@
} }
}; };
scope.setUrlValue = function(name, value, url){ scope.setUrlValue = function(name, value, url){
var urlContainerValue = scope.urlContainer.get(); const urlContainerValue = scope.urlContainer.get();
var matching = urlContainerValue.filter(function(urlSetting){ let matching = urlContainerValue.filter(function(urlSetting){
return urlSetting.match(url); return urlSetting.match(url);
}); });
if (!matching.length){ if (!matching.length){
@ -46,8 +46,8 @@
return scope.urlContainer.set(urlContainerValue); return scope.urlContainer.set(urlContainerValue);
}; };
scope.resetUrlValue = function(name, url){ scope.resetUrlValue = function(name, url){
var urlContainerValue = scope.urlContainer.get(); let urlContainerValue = scope.urlContainer.get();
var matching = urlContainerValue.filter(function(urlSetting){ const matching = urlContainerValue.filter(function(urlSetting){
return urlSetting.match(url); return urlSetting.match(url);
}); });
if (matching.length){ if (matching.length){
@ -61,6 +61,92 @@
} }
}; };
function processHideContainer(settingDefinition){
scope.hideContainer = settingDefinition;
let changeListeners = {};
settingDefinition.setHideByName = function(name, value){
logging.verbose("set hide of", name, "to", value);
const hideStore = settingDefinition.get();
hideStore[name] = value;
settingDefinition.set(hideStore);
(changeListeners[name] || []).forEach(function(listener){
listener(value);
});
};
settingDefinition.getHideByName = function(name){
const hideStore = settingDefinition.get();
return hideStore[name] || false;
};
settingDefinition.onHideChange = function(name, listener){
if (!changeListeners[name]){
changeListeners[name] = [];
}
changeListeners[name].push(listener);
};
settingDefinition.on(function(event){
const value = event.newValue;
Object.keys(value).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(value[name]);
});
});
const oldValue = event.oldValue;
Object.keys(oldValue).filter(function(name){
return !value.hasOwnProperty(name);
}).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(false);
});
});
});
settingDefinition.hideAble = false;
}
function processExpandContainer(settingDefinition){
scope.expandContainer = settingDefinition;
let changeListeners = {};
settingDefinition.setExpandByName = function(name, value){
logging.verbose("set expand of", name, "to", value);
const expandStore = settingDefinition.get();
expandStore[name] = value;
settingDefinition.set(expandStore);
(changeListeners[name] || []).forEach(function(listener){
listener(value);
});
};
settingDefinition.getExpandByName = function(name, defaultValue = false){
const expandStore = settingDefinition.get();
if ((typeof expandStore[name]) !== "undefined"){
return expandStore[name] || false;
}
else {
return defaultValue;
}
};
settingDefinition.onExpandChange = function(name, listener){
if (!changeListeners[name]){
changeListeners[name] = [];
}
changeListeners[name].push(listener);
};
settingDefinition.on(function(event){
const value = event.newValue;
Object.keys(value).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(value[name]);
});
});
const oldValue = event.oldValue;
Object.keys(oldValue).filter(function(name){
return !value.hasOwnProperty(name);
}).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(false);
});
});
});
}
scope.check = function(settingDefinition){ scope.check = function(settingDefinition){
if (settingDefinition.isUrlContainer){ if (settingDefinition.isUrlContainer){
scope.urlContainer = settingDefinition; scope.urlContainer = settingDefinition;
@ -70,89 +156,11 @@
} }
if (settingDefinition.isHideContainer){ if (settingDefinition.isHideContainer){
scope.hideContainer = settingDefinition; processHideContainer(settingDefinition);
let changeListeners = {};
settingDefinition.setHideByName = function(name, value){
logging.verbose("set hide of", name, "to", value);
const hideStore = settingDefinition.get();
hideStore[name] = value;
settingDefinition.set(hideStore);
(changeListeners[name] || []).forEach(function(listener){
listener(value);
});
};
settingDefinition.getHideByName = function(name){
const hideStore = settingDefinition.get();
return hideStore[name] || false;
};
settingDefinition.onHideChange = function(name, listener){
if (!changeListeners[name]){
changeListeners[name] = [];
}
changeListeners[name].push(listener);
};
settingDefinition.on(function(event){
const value = event.newValue;
Object.keys(value).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(value[name]);
});
});
const oldValue = event.oldValue;
Object.keys(oldValue).filter(function(name){
return !value.hasOwnProperty(name);
}).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(false);
});
});
});
settingDefinition.hideAble = false;
} }
if (settingDefinition.isExpandContainer){ if (settingDefinition.isExpandContainer){
scope.expandContainer = settingDefinition; processExpandContainer(settingDefinition);
let changeListeners = {};
settingDefinition.setExpandByName = function(name, value){
logging.verbose("set expand of", name, "to", value);
const expandStore = settingDefinition.get();
expandStore[name] = value;
settingDefinition.set(expandStore);
(changeListeners[name] || []).forEach(function(listener){
listener(value);
});
};
settingDefinition.getExpandByName = function(name, defaultValue = false){
const expandStore = settingDefinition.get();
if ((typeof expandStore[name]) !== "undefined"){
return expandStore[name] || false;
}
else {
return defaultValue;
}
};
settingDefinition.onExpandChange = function(name, listener){
if (!changeListeners[name]){
changeListeners[name] = [];
}
changeListeners[name].push(listener);
};
settingDefinition.on(function(event){
const value = event.newValue;
Object.keys(value).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(value[name]);
});
});
const oldValue = event.oldValue;
Object.keys(oldValue).filter(function(name){
return !value.hasOwnProperty(name);
}).forEach(function(name){
(changeListeners[name] || []).forEach(function(listener){
listener(false);
});
});
});
} }
}; };
@ -160,8 +168,8 @@
if (scope.urlContainer){ if (scope.urlContainer){
scope.urlContainer.on(function({newValue, oldValue}){ scope.urlContainer.on(function({newValue, oldValue}){
newValue.forEach(function(urlSetting){ newValue.forEach(function(urlSetting){
var regExp; let regExp;
var domain = !!urlSetting.url.match(/^[A-Za-z0-9_.-]+$/); const domain = !!urlSetting.url.match(/^[A-Za-z0-9_.-]+$/);
if (domain){ if (domain){
regExp = new RegExp( regExp = new RegExp(
"(?:^|\\.)" + urlSetting.url.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$", "(?:^|\\.)" + urlSetting.url.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$",
@ -200,9 +208,9 @@
); );
}); });
var newUrls = newValue.map(function(entry){return entry.url;}); const newUrls = newValue.map(function(entry){return entry.url;});
var oldUrls = oldValue.map(function(entry){return entry.url;}); const oldUrls = oldValue.map(function(entry){return entry.url;});
var matching = {}; const matching = {};
newUrls.forEach(function(url, i){ newUrls.forEach(function(url, i){
matching[url] = {new: i, old: oldUrls.indexOf(url)}; matching[url] = {new: i, old: oldUrls.indexOf(url)};
}); });
@ -212,12 +220,12 @@
} }
}); });
Object.keys(matching).forEach(function(url){ Object.keys(matching).forEach(function(url){
var oldEntry = oldValue[matching[url].old] || {}; const oldEntry = oldValue[matching[url].old] || {};
var newEntry = newValue[matching[url].new] || {}; const newEntry = newValue[matching[url].new] || {};
scope.urlContainer.entries.forEach(function(settingDefinition){ scope.urlContainer.entries.forEach(function(settingDefinition){
var name = settingDefinition.name; const name = settingDefinition.name;
var oldValue = oldEntry[name]; const oldValue = oldEntry[name];
var newValue = newEntry[name]; const newValue = newEntry[name];
if (oldValue !== newValue){ if (oldValue !== newValue){
((eventHandler[name] || {})[url] || []).forEach(function(callback){ ((eventHandler[name] || {})[url] || []).forEach(function(callback){

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var settingDefinitions = [ const settingDefinitions = [
{ {
name: "logLevel", name: "logLevel",
defaultValue: 1, defaultValue: 1,

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }

View File

@ -4,7 +4,7 @@
(function(require){ (function(require){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -37,7 +37,7 @@
if (!Array.isArray(newValue)){ if (!Array.isArray(newValue)){
return "wrongType"; return "wrongType";
} }
var entriesInvalid = newValue.reduce(function(v, entry){ const entriesInvalid = newValue.reduce(function(v, entry){
v = v || settingDefinition.entries.reduce(function(v, entryDefinition){ v = v || settingDefinition.entries.reduce(function(v, entryDefinition){
return v || isDefinitionInvalid(entryDefinition, entry[entryDefinition.name]); return v || isDefinitionInvalid(entryDefinition, entry[entryDefinition.name]);
}, false); }, false);
@ -74,7 +74,7 @@
else if (settingDefinition.urlSpecific){ else if (settingDefinition.urlSpecific){
return function getValue(url){ return function getValue(url){
if (url){ if (url){
var match = settingContainers.getUrlValueContainer(settingDefinition.name, url); const match = settingContainers.getUrlValueContainer(settingDefinition.name, url);
if (match){ if (match){
return match[settingDefinition.name]; return match[settingDefinition.name];
} }
@ -105,13 +105,13 @@
function createSetter(settingDefinition){ function createSetter(settingDefinition){
if (settingDefinition.dynamic){ if (settingDefinition.dynamic){
return function setValue(newValue){ return function setValue(newValue){
settingDefinition.setter(scope); settingDefinition.setter(scope, newValue);
}; };
} }
else { else {
const name = settingDefinition.name; const name = settingDefinition.name;
const isValid = function isValid(newValue){ const isValid = function isValid(newValue){
var invalid = settingDefinition.invalid(newValue); const invalid = settingDefinition.invalid(newValue);
if (invalid){ if (invalid){
if (invalid === "fixed"){ if (invalid === "fixed"){
logging.warning("Trying to set the fixed setting", name, ":", newValue); logging.warning("Trying to set the fixed setting", name, ":", newValue);
@ -133,13 +133,14 @@
logging.verbose("Trying to store new value for %s", name, newValue); logging.verbose("Trying to store new value for %s", name, newValue);
settings[name] = newValue; settings[name] = newValue;
if (!settingDefinition.transient){ if (!settingDefinition.transient){
var storeObject = {}; const storeObject = {};
storeObject[name] = newValue; storeObject[name] = newValue;
var promise = browser.storage.local.set(storeObject); const promise = browser.storage.local.set(storeObject);
promise.then(function(){ promise.then(function(){
logging.verbose("New value stored for %s:", name, newValue); logging.verbose("New value stored for %s:", name, newValue);
}, function(err){ return;
logging.error("Unable to store new value for %s:", name, newValue, err); }).catch(function(error){
logging.error("Unable to store new value for %s:", name, newValue, error);
}); });
return promise; return promise;
} }
@ -227,7 +228,7 @@
}; };
settingDefinitions.forEach(function(settingDefinition){ settingDefinitions.forEach(function(settingDefinition){
var name = settingDefinition.name; const name = settingDefinition.name;
definitionsByName[name] = settingDefinition; definitionsByName[name] = settingDefinition;
if (typeof settingDefinition.defaultValue === "function"){ if (typeof settingDefinition.defaultValue === "function"){
settingDefinition.defaultValue = settingDefinition.defaultValue(); settingDefinition.defaultValue = settingDefinition.defaultValue();
@ -282,7 +283,7 @@
}); });
scope.getDefinition = function(name){ scope.getDefinition = function(name){
var foundDefinition = definitionsByName[name]; const foundDefinition = definitionsByName[name];
if (foundDefinition){ if (foundDefinition){
return Object.create(foundDefinition); return Object.create(foundDefinition);
} }
@ -300,7 +301,7 @@
}; };
scope.set = function(name, ...args){ scope.set = function(name, ...args){
var foundDefinition = definitionsByName[name]; const foundDefinition = definitionsByName[name];
if (foundDefinition){ if (foundDefinition){
return foundDefinition.set(...args); return foundDefinition.set(...args);
} }
@ -309,7 +310,7 @@
} }
}; };
scope.get = function(name, ...args){ scope.get = function(name, ...args){
var foundDefinition = definitionsByName[name]; const foundDefinition = definitionsByName[name];
if (foundDefinition){ if (foundDefinition){
return foundDefinition.get(...args); return foundDefinition.get(...args);
} }
@ -328,9 +329,9 @@
const resetSymbol = Symbol("reset"); const resetSymbol = Symbol("reset");
function changeValue(name, newValue){ function changeValue(name, newValue){
var settingDefinition = scope.getDefinition(name); const settingDefinition = scope.getDefinition(name);
if (settingDefinition){ if (settingDefinition){
var oldValue = settings[name]; const oldValue = settings[name];
if (newValue === resetSymbol){ if (newValue === resetSymbol){
newValue = getDefaultValue(settingDefinition); newValue = getDefaultValue(settingDefinition);
} }
@ -355,7 +356,7 @@
browser.storage.onChanged.addListener(function(changes, area){ browser.storage.onChanged.addListener(function(changes, area){
if (area === "local"){ if (area === "local"){
logging.notice("settings changed", changes); logging.notice("settings changed", changes);
var delayedChange = []; const delayedChange = [];
Object.entries(changes).forEach(function(entry){ Object.entries(changes).forEach(function(entry){
const [name, change] = entry; const [name, change] = entry;
if (settingContainers.urlContainer && name === settingContainers.urlContainer.name){ if (settingContainers.urlContainer && name === settingContainers.urlContainer.name){
@ -407,7 +408,7 @@
{settings, logging, changeValue, urlContainer: settingContainers.urlContainer} {settings, logging, changeValue, urlContainer: settingContainers.urlContainer}
); );
} }
var delayedChange = []; const delayedChange = [];
Object.entries(storage).forEach(function(entry){ Object.entries(storage).forEach(function(entry){
const [name, value] = entry; const [name, value] = entry;
if (settingContainers.urlContainer && name === settingContainers.urlContainer.name){ if (settingContainers.urlContainer && name === settingContainers.urlContainer.name){
@ -451,8 +452,8 @@
xhr.send(); xhr.send();
xhr = null; xhr = null;
} }
catch (e){ catch (error){
logging.verbose("Error in XHR:", e); logging.verbose("Error in XHR:", error);
} }
logging.message("settings still default?", settings.isStillDefault); logging.message("settings still default?", settings.isStillDefault);
} }

View File

@ -5,7 +5,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -17,13 +17,14 @@
scope.validVersions = [undefined, 0.1, 0.2, 0.3, 0.4, 0.5]; scope.validVersions = [undefined, 0.1, 0.2, 0.3, 0.4, 0.5];
scope.transitions = { scope.transitions = {
// eslint-disable-next-line no-unused-vars
"": function(oldStorage){ "": function(oldStorage){
return { return {
storageVersion: 0.5 storageVersion: 0.5
}; };
}, },
0.1: function(oldStorage){ 0.1: function(oldStorage){
var newStorage = { const newStorage = {
storageVersion: 0.2 storageVersion: 0.2
}; };
if (oldStorage.hasOwnProperty("askOnlyOnce")){ if (oldStorage.hasOwnProperty("askOnlyOnce")){
@ -32,7 +33,7 @@
return newStorage; return newStorage;
}, },
0.2: function(oldStorage){ 0.2: function(oldStorage){
var newStorage = { const newStorage = {
storageVersion: 0.3, storageVersion: 0.3,
urlSettings: ( urlSettings: (
oldStorage.urlSettings && oldStorage.urlSettings &&
@ -40,13 +41,13 @@
)? oldStorage.urlSettings: [] )? oldStorage.urlSettings: []
}; };
var urlSettings = {}; const urlSettings = {};
(oldStorage.blackList || "").split(",") (oldStorage.blackList || "").split(",")
.map(function(url){return url.trim();}) .map(function(url){return url.trim();})
.filter(function(url){return !!url;}) .filter(function(url){return !!url;})
.forEach(function(url){ .forEach(function(url){
var entry = urlSettings[url]; let entry = urlSettings[url];
if (!entry){ if (!entry){
entry = {url, blockMode: "block"}; entry = {url, blockMode: "block"};
urlSettings[url] = entry; urlSettings[url] = entry;
@ -57,7 +58,7 @@
.map(function(url){return url.trim();}) .map(function(url){return url.trim();})
.filter(function(url){return !!url;}) .filter(function(url){return !!url;})
.forEach(function(url){ .forEach(function(url){
var entry = urlSettings[url]; let entry = urlSettings[url];
if (!entry){ if (!entry){
entry = {url, blockMode: "allow"}; entry = {url, blockMode: "allow"};
urlSettings[url] = entry; urlSettings[url] = entry;
@ -68,7 +69,7 @@
.map(function(url){return url.trim();}) .map(function(url){return url.trim();})
.filter(function(url){return !!url;}) .filter(function(url){return !!url;})
.forEach(function(url){ .forEach(function(url){
var entry = urlSettings[url]; let entry = urlSettings[url];
if (!entry){ if (!entry){
entry = {url, showNotifications: false}; entry = {url, showNotifications: false};
urlSettings[url] = entry; urlSettings[url] = entry;
@ -87,7 +88,7 @@
return newStorage; return newStorage;
}, },
0.3: function(oldStorage){ 0.3: function(oldStorage){
var newStorage = { const newStorage = {
storageVersion: 0.4 storageVersion: 0.4
}; };
if (oldStorage.hasOwnProperty("apiWhiteList")){ if (oldStorage.hasOwnProperty("apiWhiteList")){
@ -100,7 +101,7 @@
return newStorage; return newStorage;
}, },
0.4: function(oldStorage){ 0.4: function(oldStorage){
var newStorage = { const newStorage = {
storageVersion: 0.5 storageVersion: 0.5
}; };
@ -134,7 +135,7 @@
return newStorage; return newStorage;
}, },
0.5: function(oldStorage){ 0.5: function(oldStorage){
var newStorage = { const newStorage = {
storageVersion: 0.6 storageVersion: 0.6
}; };
@ -159,7 +160,7 @@
}, },
}; };
scope.check = function(storage, {settings, logging, changeValue, urlContainer}){ scope.check = function(storage, {settings, logging}){
if (!storage.storageVersion){ if (!storage.storageVersion){
logging.message("No storage version found. Initializing storage."); logging.message("No storage version found. Initializing storage.");
@ -168,13 +169,13 @@
browser.storage.local.set(storage); browser.storage.local.set(storage);
} }
else if (storage.storageVersion !== settings.storageVersion){ else if (storage.storageVersion !== settings.storageVersion){
var toChange = {}; const toChange = {};
while (storage.storageVersion !== settings.storageVersion){ while (storage.storageVersion !== settings.storageVersion){
logging.message("Old storage found (", logging.message("Old storage found (",
storage.storageVersion, "expected", settings.storageVersion, storage.storageVersion, "expected", settings.storageVersion,
")"); ")");
if (scope.transitions[storage.storageVersion]){ if (scope.transitions[storage.storageVersion]){
var changes = scope.transitions[storage.storageVersion](storage); const changes = scope.transitions[storage.storageVersion](storage);
Object.entries(changes).forEach(function(entry){ Object.entries(changes).forEach(function(entry){
const [name, value] = entry; const [name, value] = entry;
toChange[name] = value; toChange[name] = value;

View File

@ -17,7 +17,7 @@
scope.init = function(page){ scope.init = function(page){
const basePath = browser.extension.getURL("themes"); const basePath = browser.extension.getURL("themes");
var baseLink = document.createElement("link"); const baseLink = document.createElement("link");
baseLink.href = `${basePath}/base/layout.css`; baseLink.href = `${basePath}/base/layout.css`;
baseLink.rel = "stylesheet"; baseLink.rel = "stylesheet";
baseLink.type = "text/css"; baseLink.type = "text/css";
@ -25,7 +25,7 @@
const links = ["layout", page].filter(function(file){ const links = ["layout", page].filter(function(file){
return file; return file;
}).map(function(file){ }).map(function(file){
var link = document.createElement("link"); const link = document.createElement("link");
link.cbFile = file; link.cbFile = file;
link.rel = "alternative"; link.rel = "alternative";
link.type = "text/css"; link.type = "text/css";

View File

@ -4,9 +4,9 @@
(function(){ (function(){
"use strict"; "use strict";
var logging = require("./logging"); const logging = require("./logging");
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -15,9 +15,8 @@
} }
scope.copyCanvasToWebgl = function copyCanvasToWebgl(window, canvas, webGLVersion = "webgl"){ scope.copyCanvasToWebgl = function copyCanvasToWebgl(window, canvas, webGLVersion = "webgl"){
var webGlCanvas = canvas.cloneNode(true); const webGlCanvas = canvas.cloneNode(true);
var success; const context =
var context =
window.HTMLCanvasElement.prototype.getContext.call(webGlCanvas, webGLVersion) || window.HTMLCanvasElement.prototype.getContext.call(webGlCanvas, webGLVersion) ||
window.HTMLCanvasElement.prototype.getContext.call(webGlCanvas, "experimental-" + webGLVersion); window.HTMLCanvasElement.prototype.getContext.call(webGlCanvas, "experimental-" + webGLVersion);
if (!context){ if (!context){
@ -27,38 +26,35 @@
} }
context.viewport(0, 0, webGlCanvas.width, webGlCanvas.height); context.viewport(0, 0, webGlCanvas.width, webGlCanvas.height);
var program = context.createProgram(); const program = context.createProgram();
var shader = context.createShader(context.VERTEX_SHADER); const vertexShader = context.createShader(context.VERTEX_SHADER);
var vertex = "attribute vec4 a_position;\nattribute vec2 a_texCoord;\nvarying vec2 v_texCoord;\n" + const vertex = "attribute vec4 a_position;\nattribute vec2 a_texCoord;\nvarying vec2 v_texCoord;\n" +
"void main(){\n\tgl_Position = a_position;\n\tv_texCoord = a_texCoord;\n}"; "void main(){\n\tgl_Position = a_position;\n\tv_texCoord = a_texCoord;\n}";
context.shaderSource(shader, vertex); context.shaderSource(vertexShader, vertex);
context.compileShader(shader); context.compileShader(vertexShader);
success = context.getShaderParameter(shader, context.COMPILE_STATUS); if (!context.getShaderParameter(vertexShader, context.COMPILE_STATUS)){
if (!success){ context.deleteShader(vertexShader);
context.deleteShader(shader);
logging.warning("webgl: failed to compile vertex shader."); logging.warning("webgl: failed to compile vertex shader.");
return {canvas: false, context: false}; return {canvas: false, context: false};
} }
context.attachShader(program, shader); context.attachShader(program, vertexShader);
shader = context.createShader(context.FRAGMENT_SHADER); const fragmentShader = context.createShader(context.FRAGMENT_SHADER);
var fragmenter = "precision mediump float;\nuniform sampler2D u_image;\nvarying vec2 v_texCoord;\n" + const fragmenter = "precision mediump float;\nuniform sampler2D u_image;\nvarying vec2 v_texCoord;\n" +
"void main(){\n\tgl_FragColor = texture2D(u_image, v_texCoord);\n}"; "void main(){\n\tgl_FragColor = texture2D(u_image, v_texCoord);\n}";
context.shaderSource(shader, fragmenter); context.shaderSource(fragmentShader, fragmenter);
context.compileShader(shader); context.compileShader(fragmentShader);
success = context.getShaderParameter(shader, context.COMPILE_STATUS); if (!context.getShaderParameter(fragmentShader, context.COMPILE_STATUS)){
if (!success){ context.deleteShader(fragmentShader);
context.deleteShader(shader);
logging.warning("webgl: failed to compile fragmenter shader."); logging.warning("webgl: failed to compile fragmenter shader.");
return {canvas: false, context: false}; return {canvas: false, context: false};
} }
context.attachShader(program, shader); context.attachShader(program, fragmentShader);
context.linkProgram(program); context.linkProgram(program);
success = context.getProgramParameter(program, context.LINK_STATUS); if (!context.getProgramParameter(program, context.LINK_STATUS)){
if (!success){
context.deleteProgram(program); context.deleteProgram(program);
logging.warning("webgl: failed to link program."); logging.warning("webgl: failed to link program.");
return {canvas: false, context: false}; return {canvas: false, context: false};
@ -66,8 +62,7 @@
context.useProgram(program); context.useProgram(program);
var positionAttributeLocation = context.getAttribLocation(program, "a_position"); const positionBuffer = context.createBuffer();
var positionBuffer = context.createBuffer();
context.bindBuffer(context.ARRAY_BUFFER, positionBuffer); context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
context.bufferData(context.ARRAY_BUFFER, new Float32Array([ context.bufferData(context.ARRAY_BUFFER, new Float32Array([
-1, -1, -1, -1,
@ -76,21 +71,21 @@
1, 1, 1, 1,
-1, 1, -1, 1,
1, -1 1, -1
]), context.STATIC_DRAW); ]), context.STATIC_DRAW);
const positionAttributeLocation = context.getAttribLocation(program, "a_position");
context.enableVertexAttribArray(positionAttributeLocation); context.enableVertexAttribArray(positionAttributeLocation);
var size = 2; // 2 components per iteration const size = 2; // 2 components per iteration
var type = context.FLOAT; // the data is 32bit floats const type = context.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data const normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer const offset = 0; // start at the beginning of the buffer
context.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset); context.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);
var texCoordLocation = context.getAttribLocation(program, "a_texCoord"); const texCoordLocation = context.getAttribLocation(program, "a_texCoord");
// provide texture coordinates for the rectangle. // provide texture coordinates for the rectangle.
var texCoordBuffer = context.createBuffer(); const texCoordBuffer = context.createBuffer();
context.bindBuffer(context.ARRAY_BUFFER, texCoordBuffer); context.bindBuffer(context.ARRAY_BUFFER, texCoordBuffer);
context.bufferData(context.ARRAY_BUFFER, new Float32Array([ context.bufferData(context.ARRAY_BUFFER, new Float32Array([
0, 1, 0, 1,
@ -102,19 +97,15 @@
]), context.STATIC_DRAW); ]), context.STATIC_DRAW);
context.enableVertexAttribArray(texCoordLocation); context.enableVertexAttribArray(texCoordLocation);
context.vertexAttribPointer(texCoordLocation, 2, context.FLOAT, false, 0, 0); context.vertexAttribPointer(texCoordLocation, 2, context.FLOAT, false, 0, 0);
var texture = context.createTexture(); context.bindTexture(context.TEXTURE_2D, context.createTexture());
context.bindTexture(context.TEXTURE_2D, texture);
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_S, context.CLAMP_TO_EDGE); context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_S, context.CLAMP_TO_EDGE);
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_T, context.CLAMP_TO_EDGE); context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_T, context.CLAMP_TO_EDGE);
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER, context.NEAREST); context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER, context.NEAREST);
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MAG_FILTER, context.NEAREST); context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MAG_FILTER, context.NEAREST);
context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, context.RGBA, context.UNSIGNED_BYTE, canvas); context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, context.RGBA, context.UNSIGNED_BYTE, canvas);
var primitiveType = context.TRIANGLES; context.drawArrays(context.TRIANGLES /*primitiveType*/, 0 /*triangleOffset*/, 6 /*count*/);
var triangleOffset = 0;
var count = 6;
context.drawArrays(primitiveType, triangleOffset, count);
return {webGlCanvas, context}; return {webGlCanvas, context};
}; };

View File

@ -10,7 +10,7 @@
require("../lib/theme").init(); require("../lib/theme").init();
const input = document.getElementById("settings"); const input = document.getElementById("settings");
settings.onloaded(function(){ settings.onloaded(function(){
var data = {}; const data = {};
settings.forEach(function(def){ settings.forEach(function(def){
data[def.name] = def.get(); data[def.name] = def.get();
}); });
@ -18,8 +18,8 @@
input.addEventListener("input", function(){ input.addEventListener("input", function(){
try { try {
var newSettings = JSON.parse(this.value); let newSettings = JSON.parse(this.value);
var isValid = true; let isValid = true;
while (settingsMigration.transitions.hasOwnProperty(newSettings.storageVersion)){ while (settingsMigration.transitions.hasOwnProperty(newSettings.storageVersion)){
let oldVersion = newSettings.storageVersion; let oldVersion = newSettings.storageVersion;
@ -57,14 +57,14 @@
this.classList.add("invalid"); this.classList.add("invalid");
} }
} }
catch (e){ catch (error){
logging.warning("Invalid JSON:", e); logging.warning("Invalid JSON:", error);
this.classList.add("invalid"); this.classList.add("invalid");
} }
}); });
input.addEventListener("blur", function(){ input.addEventListener("blur", function(){
if (!this.classList.contains("invalid")){ if (!this.classList.contains("invalid")){
var data = {}; const data = {};
settings.forEach(function(def){ settings.forEach(function(def){
data[def.name] = def.get(); data[def.name] = def.get();
}); });

View File

@ -18,7 +18,7 @@
require("./theme").init("options"); require("./theme").init("options");
const modal = require("../lib/modal"); const modal = require("../lib/modal");
var callbacks = { const callbacks = {
openNavigatorSettings: function(){ openNavigatorSettings: function(){
logging.verbose("open navigator settings"); logging.verbose("open navigator settings");
window.open("navigator.html", "_blank"); window.open("navigator.html", "_blank");
@ -36,7 +36,7 @@
}, },
clearPersistentRndForContainer: function(){ clearPersistentRndForContainer: function(){
browser.contextualIdentities.query({}).then(function(identities){ browser.contextualIdentities.query({}).then(function(identities){
modal.select( return modal.select(
extension.getTranslation("clearPersistentRndForContainer_title"), extension.getTranslation("clearPersistentRndForContainer_title"),
identities.map(function(identity){ identities.map(function(identity){
return { return {
@ -44,9 +44,12 @@
object: identity object: identity
}; };
}) })
).then(function(identity){ );
extension.message.send({"canvasBlocker-clear-container-rnd": identity.cookieStoreId}); }).then(function(identity){
}, ()=>{}); extension.message.send({"canvasBlocker-clear-container-rnd": identity.cookieStoreId});
return;
}).catch(function(error){
logging.warning("Unable to clear persistent rnd for container:", error);
}); });
}, },
inspectSettings: function(){ inspectSettings: function(){
@ -73,7 +76,7 @@
link.target = "_blank"; link.target = "_blank";
const now = new Date(); const now = new Date();
function format(number, digits){ function format(number, digits){
var str = number.toFixed(0); const str = number.toFixed(0);
return "0".repeat(digits - str.length) + str; return "0".repeat(digits - str.length) + str;
} }
link.download = "CanvasBlocker-settings_" + link.download = "CanvasBlocker-settings_" +
@ -99,13 +102,12 @@
input.type = "file"; input.type = "file";
input.addEventListener("change", function(){ input.addEventListener("change", function(){
if (this.files.length){ if (this.files.length){
var file = this.files[0]; const reader = new FileReader();
var reader = new FileReader(); reader.onload = function(){
reader.onload = function(result){
resolve(this.result); resolve(this.result);
}; };
reader.onerror = function(err){ reader.onerror = function(error){
reject(err); reject(error);
}; };
reader.readAsText(this.files[0]); reader.readAsText(this.files[0]);
} }
@ -134,8 +136,9 @@
keys.forEach(function(key){ keys.forEach(function(key){
settings[key] = json[key]; settings[key] = json[key];
}); });
}).catch(function(err){ return;
alert(err); }).catch(function(error){
alert(error);
}); });
}, },
resetSettings: function(){ resetSettings: function(){
@ -149,6 +152,9 @@
if (clear){ if (clear){
browser.storage.local.clear(); browser.storage.local.clear();
} }
return;
}).catch(function(error){
logging.warning("Unable to reset settings:", error);
}); });
} }
}; };
@ -224,22 +230,25 @@
linkDiv.appendChild(link); linkDiv.appendChild(link);
head.appendChild(linkDiv); head.appendChild(linkDiv);
} }
return;
}).catch(function(error){
logging.warning("Unable to identify tab:", error);
}); });
var groupTabs = document.createElement("div"); const groupTabs = document.createElement("div");
groupTabs.classList = "groupTabs"; groupTabs.classList = "groupTabs";
document.body.appendChild(groupTabs); document.body.appendChild(groupTabs);
var groups = document.createElement("ul"); const groups = document.createElement("ul");
groups.className = "groups"; groups.className = "groups";
groupTabs.appendChild(groups); groupTabs.appendChild(groups);
var table = document.createElement("table"); const table = document.createElement("table");
table.className = "settings " + (settings.displayDescriptions? "display": "hide") + "Descriptions"; table.className = "settings " + (settings.displayDescriptions? "display": "hide") + "Descriptions";
settings.on("displayDescriptions", function(){ settings.on("displayDescriptions", function(){
table.className = "settings " + (settings.displayDescriptions? "display": "hide") + "Descriptions"; table.className = "settings " + (settings.displayDescriptions? "display": "hide") + "Descriptions";
}); });
var tableContainer = document.createElement("div"); const tableContainer = document.createElement("div");
tableContainer.classList = "tabContents"; tableContainer.classList = "tabContents";
groupTabs.appendChild(tableContainer); groupTabs.appendChild(tableContainer);
@ -277,41 +286,6 @@
const {hide: hideContainer, expand: expandContainer} = settings.getContainers(); const {hide: hideContainer, expand: expandContainer} = settings.getContainers();
const addGroup = function addGroup(groupDefinition){
const sections = [];
const group = {
select: function(){
groups.querySelectorAll(".selected").forEach(function(group){
group.classList.remove("selected");
});
table.querySelectorAll("tbody").forEach(function(section){
section.classList.remove("selectedGroup");
});
sections.forEach(function(section){
section.node.classList.add("selectedGroup");
});
name.classList.add("selected");
},
addSection: function(sectionDefinition){
const section = addSection(sectionDefinition.name);
sections.push(section);
return section;
}
};
const groupIndex = groups.childNodes.length;
const name = document.createElement("li");
name.textContent = extension.getTranslation("group_" + groupDefinition.name);
name.className = "groupName group" + groupIndex;
name.addEventListener("click", group.select);
groups.appendChild(name);
return group;
};
const addSection = function addSection(name){ const addSection = function addSection(name){
const body = document.createElement("tbody"); const body = document.createElement("tbody");
body.className = "sectionBody"; body.className = "sectionBody";
@ -356,9 +330,9 @@
}, },
updateDisplay: function(){ updateDisplay: function(){
const searchMode = document.body.classList.contains("searching"); const searchMode = document.body.classList.contains("searching");
var anyVisible = false; let anyVisible = false;
rows.forEach(function(row){ rows.forEach(function(row){
var isHidden = row.classList.contains("hidden"); const isHidden = row.classList.contains("hidden");
if (!isHidden){ if (!isHidden){
if (searchMode){ if (searchMode){
if (!row.classList.contains("found")){ if (!row.classList.contains("found")){
@ -382,13 +356,160 @@
return section; return section;
}; };
const addGroup = function addGroup(groupDefinition){
const sections = [];
const groupIndex = groups.childNodes.length;
const name = document.createElement("li");
name.textContent = extension.getTranslation("group_" + groupDefinition.name);
name.className = "groupName group" + groupIndex;
const group = {
select: function(){
groups.querySelectorAll(".selected").forEach(function(group){
group.classList.remove("selected");
});
table.querySelectorAll("tbody").forEach(function(section){
section.classList.remove("selectedGroup");
});
sections.forEach(function(section){
section.node.classList.add("selectedGroup");
});
name.classList.add("selected");
},
addSection: function(sectionDefinition){
const section = addSection(sectionDefinition.name);
sections.push(section);
return section;
}
};
name.addEventListener("click", group.select);
groups.appendChild(name);
return group;
};
const beforeChangeEventListeners = {}; const beforeChangeEventListeners = {};
function setupSetterForDisplay(setting){
let originalSet = setting.set;
setting.originalSet = originalSet;
if (originalSet){
const eventListeners = [];
beforeChangeEventListeners[setting.name] = eventListeners;
setting.set = function(...args){
if (eventListeners.every(function(listener){
return listener.call(setting, ...args);
})){
return originalSet.apply(this, args);
}
else {
return false;
}
};
}
}
function setupHideForDisplay(setting){
const display = setting.display;
const hideChangeListeners = [];
setting.setHide = function setHide(value){
if (hideContainer){
hideContainer.setHideByName(display.name, value);
if (setting.computeDependencies){
setting.computeDependencies();
}
}
};
setting.onHideChange = function(listener){
hideChangeListeners.push(listener);
};
setting.getHide = function getHide(){
if (hideContainer){
return hideContainer.getHideByName(display.name);
}
else {
return false;
}
};
if (hideContainer){
hideContainer.onHideChange(display.name, function(value){
if (setting.computeDependencies){
setting.computeDependencies();
}
hideChangeListeners.forEach(function(listener){
listener(value);
});
});
}
}
function setupExpandForDisplay(setting){
const display = setting.display;
const expandChangeListeners = [];
setting.setExpand = function setExpand(value){
if (expandContainer){
expandContainer.setExpandByName(display.name, value);
}
};
setting.onExpandChange = function(listener){
expandChangeListeners.push(listener);
};
setting.getExpand = function getExpand(){
if (expandContainer){
return expandContainer.getExpandByName(display.name);
}
else {
return false;
}
};
if (expandContainer){
expandContainer.onExpandChange(display.name, function(value){
expandChangeListeners.forEach(function(listener){
listener(value);
});
});
}
}
function setupComputeDependenciesForDisplay(setting, section, row){
let displayDependencies = setting.display.displayDependencies || [{}];
displayDependencies = Array.isArray(displayDependencies)?
displayDependencies:
[displayDependencies];
setting.computeDependencies = function computeDependencies(){
logging.verbose("evaluate display dependencies for", setting);
row.classList[(
(
displayHidden.get() ||
!setting.getHide()
) &&
displayDependencies.some(function(displayDependency){
return Object.keys(displayDependency).every(function(key){
return displayDependency[key].indexOf(settings[key]) !== -1;
});
})
)? "remove": "add"]("hidden");
section.updateDisplay();
};
displayDependencies.forEach(function(displayDependency){
Object.keys(displayDependency).forEach(function(name){
settings.on(name, setting.computeDependencies);
});
});
setting.computeDependencies();
displayHidden.on(setting.computeDependencies);
}
settingsDisplay.map(function(groupDefinition){ settingsDisplay.map(function(groupDefinition){
const group = addGroup(groupDefinition); const group = addGroup(groupDefinition);
groupDefinition.sections.forEach(function(sectionDefinition){ groupDefinition.sections.forEach(function(sectionDefinition){
const section = group.addSection(sectionDefinition); const section = group.addSection(sectionDefinition);
sectionDefinition.settings.forEach(function(display){ sectionDefinition.settings.forEach(function(display){
var setting = settings.getDefinition(display.name); let setting = settings.getDefinition(display.name);
if (!setting){ if (!setting){
if (display.inputs){ if (display.inputs){
setting = { setting = {
@ -419,113 +540,17 @@
if (setting){ if (setting){
setting.display = display; setting.display = display;
let originalSet = setting.set; setupSetterForDisplay(setting);
setting.originalSet = originalSet; setupHideForDisplay(setting);
if (originalSet){ setupExpandForDisplay(setting);
const eventListeners = [];
beforeChangeEventListeners[setting.name] = eventListeners;
setting.set = function(...args){
if (eventListeners.every(function(listener){
return listener.call(setting, ...args);
})){
return originalSet.apply(this, args);
}
else {
return false;
}
};
}
let hideChangeListeners = []; const row = optionsGui.createSettingRow(setting);
setting.setHide = function setHide(value){
if (hideContainer){
hideContainer.setHideByName(display.name, value);
if (computeDependencies){
computeDependencies();
}
}
};
setting.onHideChange = function(listener){
hideChangeListeners.push(listener);
};
setting.getHide = function getHide(){
if (hideContainer){
return hideContainer.getHideByName(display.name);
}
else {
return false;
}
};
if (hideContainer){
hideContainer.onHideChange(display.name, function(value){
if (computeDependencies){
computeDependencies();
}
hideChangeListeners.forEach(function(listener){
listener(value);
});
});
}
let expandChangeListeners = [];
setting.setExpand = function setExpand(value){
if (expandContainer){
expandContainer.setExpandByName(display.name, value);
}
};
setting.onExpandChange = function(listener){
expandChangeListeners.push(listener);
};
setting.getExpand = function getExpand(){
if (expandContainer){
return expandContainer.getExpandByName(display.name);
}
else {
return false;
}
};
if (expandContainer){
expandContainer.onExpandChange(display.name, function(value){
expandChangeListeners.forEach(function(listener){
listener(value);
});
});
}
var row = optionsGui.createSettingRow(setting);
settingStrings.getStrings(setting).forEach(function(string){ settingStrings.getStrings(setting).forEach(function(string){
search.register(string, row); search.register(string, row);
}); });
section.addRow(row); section.addRow(row);
if (!display.displayDependencies){
display.displayDependencies = {}; setupComputeDependenciesForDisplay(setting, section, row);
}
var displayDependencies = display.displayDependencies;
displayDependencies = Array.isArray(displayDependencies)?
displayDependencies:
[displayDependencies];
var computeDependencies = function(){
logging.verbose("evaluate display dependencies for", setting);
row.classList[(
(
displayHidden.get() ||
!setting.getHide()
) &&
displayDependencies.some(function(displayDependency){
return Object.keys(displayDependency).every(function(key){
return displayDependency[key].indexOf(settings[key]) !== -1;
});
})
)? "remove": "add"]("hidden");
section.updateDisplay();
};
computeDependencies();
displayDependencies.forEach(function(displayDependency){
Object.keys(displayDependency).forEach(function(name){
settings.on(name, computeDependencies);
});
});
displayHidden.on(computeDependencies);
} }
}); });
}); });
@ -538,6 +563,9 @@
return response.json(); return response.json();
}).then(function(manifest){ }).then(function(manifest){
version.textContent = "Version " + manifest.version; version.textContent = "Version " + manifest.version;
return;
}).catch(function(error){
version.textContent = "Unable to get version: " + error;
}); });
document.body.appendChild(version); document.body.appendChild(version);
@ -567,6 +595,9 @@
if (addException){ if (addException){
settings.set("protectWindow", false, reCaptchaEntry); settings.set("protectWindow", false, reCaptchaEntry);
} }
return;
}).catch(function(error){
logging.warning("Error while adding reCaptcha exception:", error);
}); });
} }
} }
@ -581,8 +612,11 @@
} }
).then((reallyShare) => { ).then((reallyShare) => {
if (reallyShare){ if (reallyShare){
this.originalSet(value, ...args); return this.originalSet(value, ...args);
} }
return;
}).catch(function(error){
logging.warning("Unable to set sharePersistentRndBetweenDomains:", error);
}); });
return false; return false;
} }

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -16,15 +16,15 @@
const logging = require("../lib/logging"); const logging = require("../lib/logging");
function createDescription(setting){ function createDescription(setting){
var c = document.createElement("div"); const c = document.createElement("div");
c.className = "content"; c.className = "content";
var title = document.createElement("span"); const title = document.createElement("span");
title.className = "title"; title.className = "title";
title.textContent = extension.getTranslation(setting.name + "_title"); title.textContent = extension.getTranslation(setting.name + "_title");
c.appendChild(title); c.appendChild(title);
var descriptionText = extension.getTranslation(setting.name + "_description"); let descriptionText = extension.getTranslation(setting.name + "_description");
if (setting.urlSpecific){ if (setting.urlSpecific){
const urlSpecificDescription = extension.getTranslation(setting.name + "_urlSpecific"); const urlSpecificDescription = extension.getTranslation(setting.name + "_urlSpecific");
if (urlSpecificDescription){ if (urlSpecificDescription){
@ -32,11 +32,11 @@
} }
} }
if (descriptionText){ if (descriptionText){
var info = document.createElement("div"); const info = document.createElement("div");
info.className = "info"; info.className = "info";
c.appendChild(info); c.appendChild(info);
var description = document.createElement("div"); const description = document.createElement("div");
description.className = "description"; description.className = "description";
description.textContent = descriptionText; description.textContent = descriptionText;
info.appendChild(description); info.appendChild(description);
@ -45,10 +45,10 @@
} }
function createSelect(setting){ function createSelect(setting){
var select = document.createElement("select"); const select = document.createElement("select");
select.dataset.type = typeof setting.defaultValue; select.dataset.type = typeof setting.defaultValue;
setting.options.forEach(function(value){ setting.options.forEach(function(value){
var option = document.createElement("option"); const option = document.createElement("option");
if (typeof value === typeof setting.defaultValue){ if (typeof value === typeof setting.defaultValue){
option.value = value; option.value = value;
if (setting.defaultValue === value){ if (setting.defaultValue === value){
@ -65,7 +65,7 @@
return select; return select;
} }
var inputTypes = { const inputTypes = {
number: { number: {
input: function(value){ input: function(value){
const input = document.createElement("input"); const input = document.createElement("input");
@ -121,10 +121,192 @@
}, },
object: false object: false
}; };
function createKeyInput(setting, url){
const input = document.createElement("table");
let inSection = false;
setting.keys.forEach(function(key){
if (setting.display.displayedSection){
if (typeof key === "object"){
if (key.level === 1){
inSection = key.name === setting.display.displayedSection;
return;
}
}
if (!inSection){
return;
}
}
let row = document.createElement("tr");
if (typeof key === "object"){
let cell = document.createElement("td");
cell.colSpan = 2;
let h = document.createElement("h" + (2 + (key.level || 1)));
h.textContent = key.message? extension.getTranslation(key.message): key.name;
cell.appendChild(h);
row.appendChild(cell);
input.appendChild(row);
return;
}
let nameCell = document.createElement("td");
nameCell.textContent = setting.display.replaceKeyPattern?
key.replace(setting.display.replaceKeyPattern, ""):
key;
row.appendChild(nameCell);
let keyType = inputTypes[typeof setting.defaultKeyValue];
let keyInput = keyType.input(setting.defaultKeyValue);
let inputCell = document.createElement("td");
inputCell.appendChild(keyInput);
row.appendChild(inputCell);
setting.on(function(){
const container = setting.get(url);
keyType.updateCallback(
keyInput,
container && container.hasOwnProperty(key)?
container[key]:
setting.defaultKeyValue,
url
);
});
keyInput.addEventListener("change", function(){
const value = keyType.getValue(keyInput);
let container = setting.get(url);
if (!container){
container = setting.defaultValue;
}
container[key] = value;
if (setting.set(container, url)){
logging.message("changed setting", setting.name, "(", key, "):", value);
}
else {
container = setting.get(url);
keyType.updateCallback(
keyInput,
container && container.hasOwnProperty(key)?
container[key]:
setting.defaultKeyValue,
url
);
logging.message("setting", setting.name, "(", key, ") was not changed");
}
});
input.appendChild(row);
});
return input;
}
function getPopulateUrlTable(setting, type, body){
return function populateUrlTable({newValue}){
body.innerHTML = "";
newValue.forEach(function(entry){
let row = document.createElement("tr");
let urlCell = document.createElement("td");
urlCell.classList.add("url");
urlCell.addEventListener("click", function(){
const input = document.createElement("input");
input.classList.add("urlInput");
input.style.width = urlCell.clientWidth + "px";
input.style.height = urlCell.clientHeight + "px";
urlCell.innerHTML = "";
urlCell.appendChild(input);
input.title = extension.getTranslation("inputURL");
input.value = entry.url;
input.focus();
input.addEventListener("blur", function(){
const url = input.value.trim();
if (url){
entry.url = url;
setting.urlContainer.refresh();
}
urlCell.removeChild(input);
urlCell.textContent = entry.url;
});
});
urlCell.textContent = entry.url;
row.appendChild(urlCell);
let input = createInput(setting, entry.url);
type.updateCallback(input, setting.get(entry.url));
if (!entry.hasOwnProperty(setting.name)){
input.classList.add("notSpecifiedForUrl");
}
let inputCell = document.createElement("td");
inputCell.appendChild(input);
row.appendChild(inputCell);
let clearCell = document.createElement("td");
let clearButton = document.createElement("button");
clearButton.className = "reset";
clearButton.textContent = "\xD7";
clearButton.addEventListener("click", function(){
setting.reset(entry.url);
});
clearCell.appendChild(clearButton);
row.appendChild(clearCell);
body.appendChild(row);
});
};
}
function createUrlSpecificInput(setting, input, type){
const container = document.createElement("div");
container.className = "urlValues " + (setting.getExpand()? "expanded": "collapsed");
container.appendChild(input);
const collapser = document.createElement("button");
collapser.classList.add("collapser");
container.appendChild(collapser);
collapser.addEventListener("click", function(){
setting.setExpand(!setting.getExpand());
});
setting.onExpandChange(function(value){
container.classList[value? "remove": "add"]("collapsed");
container.classList[value? "add": "remove"]("expanded");
});
let urlTable = document.createElement("table");
let caption = document.createElement("caption");
caption.textContent = extension.getTranslation(setting.urlContainer.name + "_title");
urlTable.appendChild(caption);
let body = document.createElement("tbody");
urlTable.appendChild(body);
let foot = document.createElement("tfoot");
let footRow = document.createElement("tr");
let footCell = document.createElement("td");
footCell.colSpan = 3;
let newInput = document.createElement("input");
newInput.className = "inputURL";
newInput.title = extension.getTranslation("inputURL");
const addURLSetting = function(){
const url = newInput.value.trim();
if (url){
setting.set(setting.get(url), url);
newInput.value = "";
newInput.focus();
}
};
newInput.addEventListener("keypress", function(event){
if ([10, 13].indexOf(event.keyCode) !== -1){
addURLSetting();
}
});
footCell.appendChild(newInput);
let footPlus = document.createElement("button");
footPlus.classList.add("add");
footPlus.textContent = "+";
footPlus.addEventListener("click", addURLSetting);
footCell.appendChild(footPlus);
footRow.appendChild(footCell);
foot.appendChild(footRow);
urlTable.appendChild(foot);
container.appendChild(urlTable);
setting.urlContainer.on(getPopulateUrlTable(setting, type, body));
return container;
}
function createInput(setting, url = ""){ function createInput(setting, url = ""){
var type = inputTypes[typeof setting.defaultValue]; const type = inputTypes[typeof setting.defaultValue];
var input; let input;
if (setting.options){ if (setting.options){
input = createSelect(setting); input = createSelect(setting);
} }
@ -136,7 +318,7 @@
if (type){ if (type){
setting.on(function(){type.updateCallback(input, setting.get(url));}, url); setting.on(function(){type.updateCallback(input, setting.get(url));}, url);
input.addEventListener("change", function(){ input.addEventListener("change", function(){
var value = type.getValue(input); const value = type.getValue(input);
if (setting.set(value, url)){ if (setting.set(value, url)){
logging.message("changed setting", setting.name, ":", value); logging.message("changed setting", setting.name, ":", value);
} }
@ -147,211 +329,41 @@
}); });
} }
else if (setting.keys){ else if (setting.keys){
input = document.createElement("table"); input = createKeyInput(setting, url);
let inSection = false;
setting.keys.forEach(function(key){
if (setting.display.displayedSection){
if (typeof key === "object"){
if (key.level === 1){
inSection = key.name === setting.display.displayedSection;
return;
}
}
if (!inSection){
return;
}
}
let row = document.createElement("tr");
if (typeof key === "object"){
let cell = document.createElement("td");
cell.colSpan = 2;
let h = document.createElement("h" + (2 + (key.level || 1)));
h.textContent = key.message? extension.getTranslation(key.message): key.name;
cell.appendChild(h);
row.appendChild(cell);
input.appendChild(row);
return;
}
let nameCell = document.createElement("td");
nameCell.textContent = setting.display.replaceKeyPattern?
key.replace(setting.display.replaceKeyPattern, ""):
key;
row.appendChild(nameCell);
let keyType = inputTypes[typeof setting.defaultKeyValue];
let keyInput = keyType.input(setting.defaultKeyValue);
let inputCell = document.createElement("td");
inputCell.appendChild(keyInput);
row.appendChild(inputCell);
setting.on(function(){
var container = setting.get(url);
keyType.updateCallback(
keyInput,
container && container.hasOwnProperty(key)?
container[key]:
setting.defaultKeyValue,
url
);
});
keyInput.addEventListener("change", function(){
var value = keyType.getValue(keyInput);
var container = setting.get(url);
if (!container){
container = setting.defaultValue;
}
container[key] = value;
if (setting.set(container, url)){
logging.message("changed setting", setting.name, "(", key, "):", value);
}
else {
container = setting.get(url);
keyType.updateCallback(
keyInput,
container && container.hasOwnProperty(key)?
container[key]:
setting.defaultKeyValue,
url
);
logging.message("setting", setting.name, "(", key, ") was not changed");
}
});
input.appendChild(row);
});
} }
if (setting.urlSpecific && url === ""){ if (setting.urlSpecific && url === ""){
let container = document.createElement("div"); return createUrlSpecificInput(setting, input, type);
container.className = "urlValues " + (setting.getExpand()? "expanded": "collapsed");
container.appendChild(input);
var collapser = document.createElement("button");
collapser.classList.add("collapser");
container.appendChild(collapser);
collapser.addEventListener("click", function(){
setting.setExpand(!setting.getExpand());
});
setting.onExpandChange(function(value){
container.classList[value? "remove": "add"]("collapsed");
container.classList[value? "add": "remove"]("expanded");
});
let urlTable = document.createElement("table");
let caption = document.createElement("caption");
caption.textContent = extension.getTranslation(setting.urlContainer.name + "_title");
urlTable.appendChild(caption);
let body = document.createElement("tbody");
urlTable.appendChild(body);
let foot = document.createElement("tfoot");
let footRow = document.createElement("tr");
let footCell = document.createElement("td");
footCell.colSpan = 3;
let newInput = document.createElement("input");
newInput.className = "inputURL";
newInput.title = extension.getTranslation("inputURL");
const addURLSetting = function(){
var url = newInput.value.trim();
if (url){
setting.set(setting.get(url), url);
newInput.value = "";
newInput.focus();
}
};
newInput.addEventListener("keypress", function(event){
if ([10, 13].indexOf(event.keyCode) !== -1){
addURLSetting();
}
});
footCell.appendChild(newInput);
let footPlus = document.createElement("button");
footPlus.classList.add("add");
footPlus.textContent = "+";
footPlus.addEventListener("click", addURLSetting);
footCell.appendChild(footPlus);
footRow.appendChild(footCell);
foot.appendChild(footRow);
urlTable.appendChild(foot);
container.appendChild(urlTable);
setting.urlContainer.on(function({newValue}){
body.innerHTML = "";
newValue.forEach(function(entry){
let row = document.createElement("tr");
let urlCell = document.createElement("td");
urlCell.classList.add("url");
urlCell.addEventListener("click", function(){
var input = document.createElement("input");
input.classList.add("urlInput");
input.style.width = urlCell.clientWidth + "px";
input.style.height = urlCell.clientHeight + "px";
urlCell.innerHTML = "";
urlCell.appendChild(input);
input.title = extension.getTranslation("inputURL");
input.value = entry.url;
input.focus();
input.addEventListener("blur", function(){
var url = input.value.trim();
if (url){
entry.url = url;
setting.urlContainer.refresh();
}
urlCell.removeChild(input);
urlCell.textContent = entry.url;
});
});
urlCell.textContent = entry.url;
row.appendChild(urlCell);
let input = createInput(setting, entry.url);
type.updateCallback(input, setting.get(entry.url));
if (!entry.hasOwnProperty(setting.name)){
input.classList.add("notSpecifiedForUrl");
}
let inputCell = document.createElement("td");
inputCell.appendChild(input);
row.appendChild(inputCell);
let clearCell = document.createElement("td");
let clearButton = document.createElement("button");
clearButton.className = "reset";
clearButton.textContent = "\xD7";
clearButton.addEventListener("click", function(){
setting.reset(entry.url);
});
clearCell.appendChild(clearButton);
row.appendChild(clearCell);
body.appendChild(row);
});
});
return container;
} }
return input || document.createElement("span"); return input || document.createElement("span");
} }
function createButton(setting){ function createButton(setting){
var button = document.createElement("button"); const button = document.createElement("button");
button.textContent = extension.getTranslation(setting.name + "_label"); button.textContent = extension.getTranslation(setting.name + "_label");
button.addEventListener("click", setting.action); button.addEventListener("click", setting.action);
return button; return button;
} }
function createInteraction(setting){ function createInteraction(setting){
var c = document.createElement("div"); const c = document.createElement("div");
c.className = "content"; c.className = "content";
var interaction; let interaction;
if (setting.action){ if (setting.action){
interaction = createButton(setting); interaction = createButton(setting);
} }
else if (setting.actions){ else if (setting.actions){
interaction = document.createElement("span"); interaction = document.createElement("span");
setting.actions.forEach(function(action){ setting.actions.forEach(function(action){
var button = createButton(action); const button = createButton(action);
interaction.appendChild(button); interaction.appendChild(button);
}); });
} }
else if (setting.inputs){ else if (setting.inputs){
interaction = document.createElement("span"); interaction = document.createElement("span");
setting.inputs.forEach(function(inputSetting){ setting.inputs.forEach(function(inputSetting){
var input = createInput(inputSetting); const input = createInput(inputSetting);
input.classList.add("multiple" + setting.inputs.length); input.classList.add("multiple" + setting.inputs.length);
interaction.appendChild(input); interaction.appendChild(input);
}); });
@ -369,10 +381,10 @@
} }
function createHide(setting){ function createHide(setting){
var label = document.createElement("label"); const label = document.createElement("label");
label.className = "content hideContent"; label.className = "content hideContent";
label.title = extension.getTranslation("hideSetting"); label.title = extension.getTranslation("hideSetting");
var input = document.createElement("input"); const input = document.createElement("input");
input.type = "checkbox"; input.type = "checkbox";
input.className = "hide"; input.className = "hide";
input.checked = setting.getHide(); input.checked = setting.getHide();
@ -384,26 +396,26 @@
}); });
label.appendChild(input); label.appendChild(input);
var display = document.createElement("span"); const display = document.createElement("span");
display.className = "display"; display.className = "display";
label.appendChild(display); label.appendChild(display);
return label; return label;
} }
function createSettingRow(setting){ function createSettingRow(setting){
var tr = document.createElement("tr"); const tr = document.createElement("tr");
tr.className = "settingRow"; tr.className = "settingRow";
var hide = document.createElement("td"); const hide = document.createElement("td");
hide.className = "hideColumn"; hide.className = "hideColumn";
hide.appendChild(createHide(setting)); hide.appendChild(createHide(setting));
tr.appendChild(hide); tr.appendChild(hide);
var left = document.createElement("td"); const left = document.createElement("td");
left.appendChild(createDescription(setting)); left.appendChild(createDescription(setting));
tr.appendChild(left); tr.appendChild(left);
var right = document.createElement("td"); const right = document.createElement("td");
right.appendChild(createInteraction(setting)); right.appendChild(createInteraction(setting));
tr.appendChild(right); tr.appendChild(right);
@ -434,7 +446,7 @@
displayHiddenDescription.appendChild(createDescription(displayHidden)); displayHiddenDescription.appendChild(createDescription(displayHidden));
displayHiddenRow.appendChild(displayHiddenDescription); displayHiddenRow.appendChild(displayHiddenDescription);
var displayHiddenInteraction = document.createElement("td"); const displayHiddenInteraction = document.createElement("td");
displayHiddenInteraction.appendChild(createInteraction(displayHidden)); displayHiddenInteraction.appendChild(createInteraction(displayHidden));
displayHiddenRow.appendChild(displayHiddenInteraction); displayHiddenRow.appendChild(displayHiddenInteraction);
tHead.appendChild(displayHiddenRow); tHead.appendChild(displayHiddenRow);

View File

@ -12,93 +12,103 @@
const searchParameters = new URLSearchParams(window.location.search); const searchParameters = new URLSearchParams(window.location.search);
require("./theme").init("presets"); require("./theme").init("presets");
function buildPresetSettingGui(setting, value){
function valueToText(value){
switch (typeof value){
case "string":
return extension.getTranslation(`${setting}_options.${value}`);
case "boolean":
return value? "\u2713": "\u00D7";
default:
return value.toString();
}
}
const container = document.createElement("li");
container.textContent = extension.getTranslation(`${setting}_title`) + ": ";
if ((typeof value) === "object"){
const urlValues = document.createElement("ul");
Object.keys(value).map(function(url){
const container = document.createElement("li");
container.className = "urlValue";
container.textContent = url + ": " +
valueToText(value[url]) +
" (" + valueToText(settings.get(setting, url)) +")";
return container;
}).forEach(function(node){
urlValues.appendChild(node);
});
container.appendChild(urlValues);
}
else {
container.appendChild(document.createTextNode(
`${valueToText(value)} (${valueToText(settings.get(setting))})`
));
}
return container;
}
function buildPresetGui(presetName, preset){
const container = document.createElement("div");
container.className = "preset " + presetName;
const title = document.createElement("h1");
title.className = "title";
title.textContent = extension.getTranslation(`preset_${presetName}_title`);
container.appendChild(title);
const description = document.createElement("div");
description.className = "description";
description.textContent = extension.getTranslation(`preset_${presetName}_description`);
container.appendChild(description);
const settingsList = document.createElement("ul");
settingsList.className = "settings";
container.appendChild(settingsList);
Object.keys(preset).map(function(settingName){
return buildPresetSettingGui(settingName, preset[settingName]);
}).forEach(function(node){
settingsList.appendChild(node);
});
if (settingsList.childNodes.length){
const button = document.createElement("button");
button.textContent = extension.getTranslation("apply");
button.addEventListener("click", function(){
Promise.all(Object.keys(preset).map(function(settingName){
const value = preset[settingName];
if ((typeof value) === "object"){
return Promise.all(Object.keys(value).map(function(url){
return settings.set(settingName, value[url], url);
}));
}
else {
return settings.set(settingName, value);
}
})).then(function(){
window.location.reload();
return;
}).catch(function(error){
logging.warning("Unable to apply preset:", error);
});
});
container.appendChild(button);
}
return container;
}
Promise.all([ Promise.all([
settings.loaded, settings.loaded,
fetch("presets.json").then(function(data){ fetch("presets.json").then(function(data){
return data.json(); return data.json();
}) })
// eslint-disable-next-line no-unused-vars
]).then(function([settingsLoaded, presets]){ ]).then(function([settingsLoaded, presets]){
Object.keys(presets).map(function(presetName){ Object.keys(presets).map(function(presetName){
const preset = presets[presetName]; return buildPresetGui(presetName, presets[presetName]);
const container = document.createElement("div");
container.className = "preset " + presetName;
const title = document.createElement("h1");
title.className = "title";
title.textContent = extension.getTranslation(`preset_${presetName}_title`);
container.appendChild(title);
const description = document.createElement("div");
description.className = "description";
description.textContent = extension.getTranslation(`preset_${presetName}_description`);
container.appendChild(description);
const settingsList = document.createElement("ul");
settingsList.className = "settings";
container.appendChild(settingsList);
Object.keys(preset).map(function(settingName){
function valueToText(value){
switch (typeof value){
case "string":
return extension.getTranslation(`${settingName}_options.${value}`);
case "boolean":
return value? "\u2713": "\u00D7";
default:
return value.toString();
}
}
const value = preset[settingName];
const container = document.createElement("li");
container.textContent = extension.getTranslation(`${settingName}_title`) + ": ";
if ((typeof value) === "object"){
const urlValues = document.createElement("ul");
Object.keys(value).map(function(url){
var container = document.createElement("li");
container.className = "urlValue";
container.textContent = url + ": " +
valueToText(value[url]) +
" (" + valueToText(settings.get(settingName, url)) +")";
return container;
}).forEach(function(node){
urlValues.appendChild(node);
});
container.appendChild(urlValues);
}
else {
container.appendChild(document.createTextNode(
`${valueToText(value)} (${valueToText(settings.get(settingName))})`
));
}
return container;
}).forEach(function(node){
settingsList.appendChild(node);
});
if (settingsList.childNodes.length){
const button = document.createElement("button");
button.textContent = extension.getTranslation("apply");
button.addEventListener("click", function(){
Promise.all(Object.keys(preset).map(function(settingName){
const value = preset[settingName];
if ((typeof value) === "object"){
return Promise.all(Object.keys(value).map(function(url){
return settings.set(settingName, value[url], url);
}));
}
else {
return settings.set(settingName, value);
}
})).then(function(){
window.location.reload();
});
});
container.appendChild(button);
}
return container;
}).forEach(function(node){ }).forEach(function(node){
document.body.appendChild(node); document.body.appendChild(node);
}); });
@ -131,6 +141,9 @@
document.body.style.fontSize = fontSize + "px"; document.body.style.fontSize = fontSize + "px";
} }
} }
return;
}).catch(function(error){
logging.warning("Unable to setup presets:", error);
}); });
document.querySelector("head title").textContent = extension.getTranslation("presets_title"); document.querySelector("head title").textContent = extension.getTranslation("presets_title");

View File

@ -4,7 +4,7 @@
(function(){ (function(){
"use strict"; "use strict";
var scope; let scope;
if ((typeof exports) !== "undefined"){ if ((typeof exports) !== "undefined"){
scope = exports; scope = exports;
} }
@ -84,8 +84,6 @@
{mainFlag: "protectScreen", section: "Screen-API"}, {mainFlag: "protectScreen", section: "Screen-API"},
].forEach(function(api){ ].forEach(function(api){
if (settings.get(api.mainFlag) !== (api.mainFlagDisabledValue || false)){ if (settings.get(api.mainFlag) !== (api.mainFlagDisabledValue || false)){
let inSection = false;
let anyActive = false;
if (getSectionKeys(api.section).every(function(key){ if (getSectionKeys(api.section).every(function(key){
return protectedFeaturesValue.hasOwnProperty(key) && return protectedFeaturesValue.hasOwnProperty(key) &&
!protectedFeaturesValue[key]; !protectedFeaturesValue[key];

View File

@ -9,12 +9,12 @@
require("../lib/theme").init("sanitize"); require("../lib/theme").init("sanitize");
const sanitationRules = require("./sanitationRules"); const sanitationRules = require("./sanitationRules");
var title = document.createElement("h1"); const title = document.createElement("h1");
title.className = "title"; title.className = "title";
title.textContent = extension.getTranslation("sanitation_title"); title.textContent = extension.getTranslation("sanitation_title");
document.body.appendChild(title); document.body.appendChild(title);
var description = document.createElement("div"); const description = document.createElement("div");
description.className = "description"; description.className = "description";
description.textContent = extension.getTranslation("sanitation_description"); description.textContent = extension.getTranslation("sanitation_description");
document.body.appendChild(description); document.body.appendChild(description);

View File

@ -1,10 +1,9 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint max-lines: off*/
(function(){ (function(){
"use strict"; "use strict";
var settingsDisplay = [ const settingsDisplay = [
{ {
name: "general", name: "general",
sections: [ sections: [

View File

@ -11,13 +11,59 @@
const searchParameters = new URLSearchParams(window.location.search); const searchParameters = new URLSearchParams(window.location.search);
var title = document.createElement("h1"); const title = document.createElement("h1");
title.className = "title"; title.className = "title";
title.textContent = extension.getTranslation("whitelist_inspection_title"); title.textContent = extension.getTranslation("whitelist_inspection_title");
document.body.appendChild(title); document.body.appendChild(title);
document.querySelector("head title").textContent = title.textContent; document.querySelector("head title").textContent = title.textContent;
const whitelistSettings = [
{
title: extension.getTranslation("whitelist_all_apis"),
name: "blockMode",
whitelistValue: "allow",
protectedValue: "fake"
},
{
title: extension.getTranslation("section_canvas-api"),
name: "protectedCanvasPart",
whitelistValue: "nothing",
protectedValue: "readout"
},
{
title: extension.getTranslation("section_audio-api"),
name: "protectAudio",
whitelistValue: false,
protectedValue: true
},
{
title: extension.getTranslation("section_history-api"),
name: "historyLengthThreshold",
whitelistValue: 10000,
protectedValue: 2
},
{
title: extension.getTranslation("section_window-api"),
name: "protectWindow",
whitelistValue: false,
protectedValue: true
},
{
title: extension.getTranslation("section_DOMRect-api"),
name: "protectDOMRect",
whitelistValue: false,
protectedValue: true
},
{
title: extension.getTranslation("section_navigator-api"),
name: "protectNavigator",
whitelistValue: false,
protectedValue: true
},
];
settings.onloaded(function(){ settings.onloaded(function(){
const sets = settingContainers.urlContainer.get(); const sets = settingContainers.urlContainer.get();
@ -47,51 +93,6 @@
} }
} }
const whitelistSettings = [
{
title: extension.getTranslation("whitelist_all_apis"),
name: "blockMode",
whitelistValue: "allow",
protectedValue: "fake"
},
{
title: extension.getTranslation("section_canvas-api"),
name: "protectedCanvasPart",
whitelistValue: "nothing",
protectedValue: "readout"
},
{
title: extension.getTranslation("section_audio-api"),
name: "protectAudio",
whitelistValue: false,
protectedValue: true
},
{
title: extension.getTranslation("section_history-api"),
name: "historyLengthThreshold",
whitelistValue: 10000,
protectedValue: 2
},
{
title: extension.getTranslation("section_window-api"),
name: "protectWindow",
whitelistValue: false,
protectedValue: true
},
{
title: extension.getTranslation("section_DOMRect-api"),
name: "protectDOMRect",
whitelistValue: false,
protectedValue: true
},
{
title: extension.getTranslation("section_navigator-api"),
name: "protectNavigator",
whitelistValue: false,
protectedValue: true
},
];
const table = document.createElement("table"); const table = document.createElement("table");
whitelistSettings.forEach(function(setting){ whitelistSettings.forEach(function(setting){
const row = document.createElement("tr"); const row = document.createElement("tr");

View File

@ -15,7 +15,7 @@
const addToContainer = function(){ const addToContainer = function(){
const container = document.getElementById("prints"); const container = document.getElementById("prints");
container.querySelector("li").textContent = extension.getTranslation("pleaseWait"); container.querySelector("li").textContent = extension.getTranslation("pleaseWait");
var first = true; let first = true;
return function addToContainer(domainNotification){ return function addToContainer(domainNotification){
if (first){ if (first){
@ -105,10 +105,10 @@
this.textNode = function(){ this.textNode = function(){
return node; return node;
}; };
var messageParts = extension.getTranslation(this.messageId).split(/\{url\}/g); const messageParts = extension.getTranslation(this.messageId).split(/\{url\}/g);
node.appendChild(document.createTextNode(messageParts.shift())); node.appendChild(document.createTextNode(messageParts.shift()));
while (messageParts.length){ while (messageParts.length){
var urlSpan = document.createElement("span"); const urlSpan = document.createElement("span");
urlSpan.textContent = this.domain || extension.getTranslation("localFile"); urlSpan.textContent = this.domain || extension.getTranslation("localFile");
urlSpan.className = "url hasHiddenActions"; urlSpan.className = "url hasHiddenActions";
urlSpan.appendChild(this.actionsNode()); urlSpan.appendChild(this.actionsNode());
@ -116,7 +116,7 @@
node.appendChild(document.createTextNode(messageParts.shift())); node.appendChild(document.createTextNode(messageParts.shift()));
} }
node.appendChild(document.createTextNode(" (")); node.appendChild(document.createTextNode(" ("));
var countSpan = document.createElement("span"); const countSpan = document.createElement("span");
countSpan.className = "count"; countSpan.className = "count";
countSpan.textContent = "0"; countSpan.textContent = "0";
node.appendChild(countSpan); node.appendChild(countSpan);
@ -168,7 +168,7 @@
const domains = new Map(); const domains = new Map();
const domainNotification = function(url, messageId, count = 0, api = ""){ const domainNotification = function(url, messageId, count = 0, api = ""){
const domain = url.hostname; const domain = url.hostname;
var domainNotification = domains.get(domain + messageId); let domainNotification = domains.get(domain + messageId);
if (!domainNotification){ if (!domainNotification){
domainNotification = new DomainNotification(url, messageId, count, api); domainNotification = new DomainNotification(url, messageId, count, api);
domains.set(domain + messageId, domainNotification); domains.set(domain + messageId, domainNotification);

View File

@ -13,7 +13,7 @@
scope = require.register("./gui", {}); scope = require.register("./gui", {});
} }
const {error, warning, message, notice, verbose, setPrefix: setLogPrefix} = require("../lib/logging"); const logging = require("../lib/logging");
const extension = require("../lib/extension"); const extension = require("../lib/extension");
scope.createCollapser = function(){ scope.createCollapser = function(){
@ -23,11 +23,11 @@
}; };
return function createCollapser(container){ return function createCollapser(container){
var collapser = document.createElement("span"); const collapser = document.createElement("span");
collapser.className = "collapser"; collapser.className = "collapser";
["more", "less"].forEach(function(type){ ["more", "less"].forEach(function(type){
var span = document.createElement("span"); const span = document.createElement("span");
span.className = type; span.className = type;
span.textContent = messages[type]; span.textContent = messages[type];
collapser.appendChild(span); collapser.appendChild(span);
@ -44,13 +44,13 @@
scope.createActionButtons = function createActionButtons(container, actions, data, horizontal){ scope.createActionButtons = function createActionButtons(container, actions, data, horizontal){
actions.forEach(function(action, i){ actions.forEach(function(action){
var button = document.createElement("button"); const button = document.createElement("button");
button.className = action.name + " action"; button.className = action.name + " action";
button.title = extension.getTranslation(action.name); button.title = extension.getTranslation(action.name);
if (action.isIcon || action.icon){ if (action.isIcon || action.icon){
button.classList.add("isIcon"); button.classList.add("isIcon");
var img = document.createElement("img"); const img = document.createElement("img");
button.appendChild(img); button.appendChild(img);
img.src = "../icons/" + (action.icon || `pageAction-${action.name}.svg`); img.src = "../icons/" + (action.icon || `pageAction-${action.name}.svg`);
} }
@ -66,8 +66,8 @@
}; };
scope.modalChoice = function modalChoice(messageText, choices){ scope.modalChoice = function modalChoice(messageText, choices){
message("open modal choice"); logging.message("open modal choice");
return new Promise(function(resolve, reject){ return new Promise(function(resolve){
document.body.innerHTML = ""; document.body.innerHTML = "";
document.body.className = "modal"; document.body.className = "modal";
document.body.appendChild(document.createTextNode(messageText)); document.body.appendChild(document.createTextNode(messageText));
@ -77,7 +77,7 @@
const button = document.createElement("button"); const button = document.createElement("button");
button.addEventListener("click", function(){ button.addEventListener("click", function(){
resolve(choice.value || choice); resolve(choice.value || choice);
message("modal choice closed with value", choice.value || choice); logging.message("modal choice closed with value", choice.value || choice);
}); });
button.appendChild(document.createTextNode(choice.text || choice)); button.appendChild(document.createTextNode(choice.text || choice));
stack.appendChild(button); stack.appendChild(button);
@ -87,8 +87,8 @@
}; };
scope.modalPrompt = function modalPrompt(messageText, defaultValue){ scope.modalPrompt = function modalPrompt(messageText, defaultValue){
message("open modal prompt"); logging.message("open modal prompt");
return new Promise(function(resolve, reject){ return new Promise(function(resolve){
document.body.innerHTML = ""; document.body.innerHTML = "";
document.body.className = "modal"; document.body.className = "modal";
document.body.appendChild(document.createTextNode(messageText)); document.body.appendChild(document.createTextNode(messageText));
@ -101,7 +101,7 @@
button.textContent = "OK"; button.textContent = "OK";
button.addEventListener("click", function(){ button.addEventListener("click", function(){
resolve(input.value); resolve(input.value);
message("modal prompt closed with value", input.value); logging.message("modal prompt closed with value", input.value);
}); });
stack.appendChild(button); stack.appendChild(button);
document.body.append(stack); document.body.append(stack);

View File

@ -7,22 +7,17 @@
const extension = require("../lib/extension"); const extension = require("../lib/extension");
const settings = require("../lib/settings"); const settings = require("../lib/settings");
const {parseErrorStack} = require("../lib/callingStack"); const {parseErrorStack} = require("../lib/callingStack");
const {error, warning, message, notice, verbose, setPrefix: setLogPrefix} = require("../lib/logging"); const logging = require("../lib/logging");
setLogPrefix("page action script"); logging.setPrefix("page action script");
const domainNotification = require("./domainNotification"); const domainNotification = require("./domainNotification");
const Notification = require("./Notification"); const Notification = require("./Notification");
const {createActionButtons, modalPrompt, modalChoice} = require("./gui"); const {createActionButtons, modalPrompt, modalChoice} = require("./gui");
const lists = require("../lib/lists"); const lists = require("../lib/lists");
require("../lib/theme").init("pageAction"); require("../lib/theme").init("pageAction");
Promise.all([ function registerActionButtons(){
browser.tabs.query({active: true, currentWindow: true}), logging.notice("create global action buttons");
settings.loaded
]).then(function(values){
const tabs = values[0];
notice("create global action buttons");
createActionButtons( createActionButtons(
document.getElementById("globalActions"), document.getElementById("globalActions"),
@ -44,7 +39,9 @@
isIcon: true, isIcon: true,
callback: function(){ callback: function(){
settings.set("showNotifications", false).then(function(){ settings.set("showNotifications", false).then(function(){
window.close(); return window.close();
}).catch(function(error){
logging.warning("Unable to disable notifications:", error);
}); });
} }
} }
@ -52,164 +49,130 @@
undefined, undefined,
true true
); );
}
if (!tabs.length){
throw new Error("noTabsFound"); const domainActions = [
} {
else if (tabs.length > 1){ name: "ignorelist",
error(tabs); isIcon: true,
throw new Error("tooManyTabsFound"); callback: function({domain, urls}){
} return domainOrUrlPicker(
domain,
function domainOrUrlPicker(domain, urls, selectText, urlInputText){ urls,
const choices = Array.from(urls).map(function(url){ extension.getTranslation("selectIgnore"),
return { extension.getTranslation("inputIgnoreURL")
text: url, ).then(function(choice){
value: "^" + url.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "$" if (choice){
return settings.set("showNotifications", false, choice);
}
return;
}).then(function(){
return window.close();
});
}
},
{
name: "whitelist",
isIcon: true,
callback: function({domain, urls, api}){
const whitelistingSettings = {
all: {name: "blockMode", value: "allow"},
canvas: {name: "protectedCanvasPart", value: "nothing"},
audio: {name: "protectAudio", value: false},
domRect: {name: "protectDOMRect", value: false},
history: {name: "historyLengthThreshold", value: 10000},
navigator: {name: "protectNavigator", value: false},
windows: {name: "protectWindow", value: false}
}; };
}); return domainOrUrlPicker(
if (domain){ domain,
choices.unshift(domain); urls,
extension.getTranslation("selectWhitelist"),
extension.getTranslation("inputWhitelistURL")
).then(function(choice){
if (
api &&
whitelistingSettings[api]
){
// eslint-disable-next-line promise/no-nesting
return modalChoice(
extension.getTranslation("selectWhitelistScope"),
[
{
text: extension.getTranslation("whitelistOnlyAPI")
.replace(
/\{api\}/g,
extension.getTranslation("section_" + api + "-api")
),
value: api
},
{
text: extension.getTranslation("whitelistAllAPIs"),
value: "all"
}
]
).then(function(selection){
return {choice, setting: whitelistingSettings[selection]};
});
}
else {
return {choice, setting: whitelistingSettings.all};
}
}).then(function({choice, setting}){
if (choice){
return settings.set(setting.name, setting.value, choice);
}
return;
}).then(function(){
return window.close();
});
}
},
{
name: "whitelistTemporarily",
isIcon: true,
callback: function({domain, urls}){
return domainOrUrlPicker(
domain,
urls,
extension.getTranslation("selectSessionWhitelist"),
extension.getTranslation("inputSessionWhitelistURL")
).then(function(choice){
if (choice){
return lists.appendTo("sessionWhite", choice);
}
return;
}).then(function(){
return window.close();
});
}
},
{
name: "inspectWhitelist",
isIcon: true,
callback: function({domain, urls}){
window.open(
browser.extension.getURL(
"options/whitelist.html?domain=" +
encodeURIComponent(domain) +
"&urls=" +
encodeURIComponent(JSON.stringify(Array.from(urls.values())))
),
"_blank"
);
} }
return modalChoice(
selectText,
choices
).then(function(choice){
if (choice.startsWith("^")){
return modalPrompt(
urlInputText,
choice
);
}
else {
return choice;
}
});
} }
];
verbose("registering domain actions"); function registerDomainActions(){
[ logging.verbose("registering domain actions");
{ domainActions.forEach(function(domainAction){
name: "ignorelist",
isIcon: true,
callback: function({domain, urls}){
domainOrUrlPicker(
domain,
urls,
extension.getTranslation("selectIgnore"),
extension.getTranslation("inputIgnoreURL")
).then(function(choice){
if (choice){
settings.set("showNotifications", false, choice).then(function(){
window.close();
});
}
else {
window.close();
}
});
}
},
{
name: "whitelist",
isIcon: true,
callback: function({domain, urls, api}){
const whitelistingSettings = {
all: {name: "blockMode", value: "allow"},
canvas: {name: "protectedCanvasPart", value: "nothing"},
audio: {name: "protectAudio", value: false},
domRect: {name: "protectDOMRect", value: false},
history: {name: "historyLengthThreshold", value: 10000},
navigator: {name: "protectNavigator", value: false},
windows: {name: "protectWindow", value: false}
};
domainOrUrlPicker(
domain,
urls,
extension.getTranslation("selectWhitelist"),
extension.getTranslation("inputWhitelistURL")
).then(function(choice){
if (
api &&
whitelistingSettings[api]
){
return modalChoice(
extension.getTranslation("selectWhitelistScope"),
[
{
text: extension.getTranslation("whitelistOnlyAPI")
.replace(
/\{api\}/g,
extension.getTranslation("section_" + api + "-api")
),
value: api
},
{
text: extension.getTranslation("whitelistAllAPIs"),
value: "all"
}
]
).then(function(selection){
return {choice, setting: whitelistingSettings[selection]};
});
}
else {
return {choice, setting: whitelistingSettings.all};
}
}).then(function({choice, setting}){
if (choice){
settings.set(setting.name, setting.value, choice).then(function(){
window.close();
});
}
else {
window.close();
}
});
}
},
{
name: "whitelistTemporarily",
isIcon: true,
callback: function({domain, urls}){
domainOrUrlPicker(
domain,
urls,
extension.getTranslation("selectSessionWhitelist"),
extension.getTranslation("inputSessionWhitelistURL")
).then(function(choice){
if (choice){
lists.appendTo("sessionWhite", choice).then(function(){
window.close();
});
}
else {
window.close();
}
});
}
},
{
name: "inspectWhitelist",
isIcon: true,
callback: function({domain, urls}){
window.open(
browser.extension.getURL(
"options/whitelist.html?domain=" +
encodeURIComponent(domain) +
"&urls=" +
encodeURIComponent(JSON.stringify(Array.from(urls.values())))
),
"_blank"
);
}
}
].forEach(function(domainAction){
domainNotification.addAction(domainAction); domainNotification.addAction(domainAction);
}); });
}
verbose("registering notification actions");
function registerNotificationActions(){
logging.verbose("registering notification actions");
[ [
{ {
name: "displayFullURL", name: "displayFullURL",
@ -228,13 +191,60 @@
].forEach(function(action){ ].forEach(function(action){
Notification.addAction(action); Notification.addAction(action);
}); });
}
function domainOrUrlPicker(domain, urls, selectText, urlInputText){
const choices = Array.from(urls).map(function(url){
return {
text: url,
value: "^" + url.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "$"
};
});
if (domain){
choices.unshift(domain);
}
return modalChoice(
selectText,
choices
).then(function(choice){
if (choice.startsWith("^")){
return modalPrompt(
urlInputText,
choice
);
}
else {
return choice;
}
});
}
Promise.all([
browser.tabs.query({active: true, currentWindow: true}),
settings.loaded
]).then(function(values){
const tabs = values[0];
var tab = tabs[0]; if (!tabs.length){
throw new Error("noTabsFound");
}
else if (tabs.length > 1){
logging.error(tabs);
throw new Error("tooManyTabsFound");
}
registerActionButtons();
registerDomainActions();
registerNotificationActions();
const tab = tabs[0];
extension.message.on(function(data){ extension.message.on(function(data){
if (data["canvasBlocker-notificationCounter"]){ if (data["canvasBlocker-notificationCounter"]){
const url = new URL(data.url); const url = new URL(data.url);
Object.keys(data["canvasBlocker-notificationCounter"]).forEach(function(key){ Object.keys(data["canvasBlocker-notificationCounter"]).forEach(function(key){
const notification = domainNotification( domainNotification(
url, url,
key, key,
data["canvasBlocker-notificationCounter"][key].count, data["canvasBlocker-notificationCounter"][key].count,
@ -246,7 +256,7 @@
Array.isArray(data["canvasBlocker-notifications"]) && Array.isArray(data["canvasBlocker-notifications"]) &&
data["canvasBlocker-notifications"].length data["canvasBlocker-notifications"].length
){ ){
message("got notifications"); logging.message("got notifications");
const notifications = data["canvasBlocker-notifications"]; const notifications = data["canvasBlocker-notifications"];
let i = 0; let i = 0;
const length = notifications.length; const length = notifications.length;
@ -255,13 +265,14 @@
window.clearInterval(tick); window.clearInterval(tick);
} }
else { else {
for (var delta = 0; delta < 20 && i + delta < length; delta += 1){ let delta = 0;
for (; delta < 20 && i + delta < length; delta += 1){
let notification = notifications[i + delta]; let notification = notifications[i + delta];
verbose(notification); logging.verbose(notification);
if (settings.ignoredAPIs[notification.api]){ if (settings.ignoredAPIs[notification.api]){
continue; continue;
} }
verbose(notification); logging.verbose(notification);
notification.url = new URL(notification.url); notification.url = new URL(notification.url);
domainNotification( domainNotification(
notification.url, notification.url,
@ -275,15 +286,16 @@
}, 1); }, 1);
} }
}); });
message("request notifications from tab", tab.id); logging.message("request notifications from tab", tab.id);
browser.tabs.sendMessage( browser.tabs.sendMessage(
tab.id, tab.id,
{ {
"canvasBlocker-sendNotifications": tab.id "canvasBlocker-sendNotifications": tab.id
} }
); );
notice("waiting for notifications"); logging.notice("waiting for notifications");
}).catch(function(e){ return;
error(e); }).catch(function(error){
error(error);
}); });
}()); }());

View File

@ -43,7 +43,8 @@
crypto.subtle.digest("SHA-256", data).then(function(hash){ crypto.subtle.digest("SHA-256", data).then(function(hash){
hashNode.textContent = byteArrayToHex(hash); hashNode.textContent = byteArrayToHex(hash);
}, function(error){ return;
}).catch(function(error){
hashNode.textContent = error; hashNode.textContent = error;
}); });
hashSets[set].appendChild(container); hashSets[set].appendChild(container);

View File

@ -1,4 +1,3 @@
/* eslint no-console: off, max-lines: off */
var addTest = (function(){ var addTest = (function(){
"use strict"; "use strict";
@ -18,8 +17,9 @@ var addTest = (function(){
try { try {
status = func(log)? 1: 2; status = func(log)? 1: 2;
} }
catch (e){ catch (error){
console.log(e); // eslint-disable-next-line no-console
console.log(error);
status = 3; status = 3;
} }
var li = document.createElement("li"); var li = document.createElement("li");
@ -214,6 +214,7 @@ 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,
@ -255,12 +256,12 @@ addTest("error provocation 1", function(log){
try{ try{
ctx.getImageData(0, 0, 0, 0); ctx.getImageData(0, 0, 0, 0);
} }
catch (err){ catch (error){
try { try {
log(err.name); log(error.name);
log(err.toString()); log(error.toString());
} }
catch (e){ catch (error){
canvasBlocker = true; canvasBlocker = true;
} }
} }
@ -277,12 +278,12 @@ addTest("error provocation 2", function(log){
ctx.getImageData(0, 0, 1, 1); ctx.getImageData(0, 0, 1, 1);
log("no error provoked"); log("no error provoked");
} }
catch (err){ catch (error){
try { try {
log(err.name); log(error.name);
log(err.toString()); log(error.toString());
} }
catch (e){ catch (error){
canvasBlocker = true; canvasBlocker = true;
} }
} }
@ -295,12 +296,12 @@ addTest("error provocation 3", function(log){
try{ try{
CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]); CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]);
} }
catch (err){ catch (error){
try { try {
log(err.name); log(error.name);
log(err.toString()); log(error.toString());
} }
catch (e){ catch (error){
canvasBlocker = true; canvasBlocker = true;
} }
} }
@ -313,26 +314,26 @@ addTest("error properties", function(log){
try{ try{
CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]); CanvasRenderingContext2D.prototype.getImageData.apply(undefined, [0, 0, 1, 1]);
} }
catch (err){ catch (error){
try { try {
var name = "TypeError"; var name = "TypeError";
if (err.name !== name && err instanceof TypeError){ if (error.name !== name && error instanceof TypeError){
log("Error name wrong. Expected: ", name, "- got:", err.name); log("Error name wrong. Expected: ", name, "- got:", error.name);
canvasBlocker = true; canvasBlocker = true;
} }
var start = "@" + location.href.replace(/\.html$/, ".js"); var start = "@" + location.href.replace(/\.html$/, ".js");
if (!err.stack.startsWith(start)){ if (!error.stack.startsWith(start)){
log("Error stack starts wrong. Expected:", start, "- got :", err.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 " + var message = "'getImageData' called on an object that " +
"does not implement interface CanvasRenderingContext2D."; "does not implement interface CanvasRenderingContext2D.";
if (err.message !== message){ if (error.message !== message){
log("Error message wrong. Expected: ", message, "- got:", err.message); log("Error message wrong. Expected: ", message, "- got:", error.message);
canvasBlocker = true; canvasBlocker = true;
} }
} }
catch (e){ catch (error){
canvasBlocker = true; canvasBlocker = true;
} }
} }

View File

@ -21,66 +21,78 @@
return Array.from(doc.querySelectorAll(".testRect")); return Array.from(doc.querySelectorAll(".testRect"));
} }
function formatNumber(number){
const str = number.toString();
return "<span class=small>" + str.substring(0, str.length - 2) + "</span>" +
str.substring(str.length - 2);
}
const properties = ["x", "y", "width", "height", "top", "left", "right", "bottom"];
function performTest(output, callback){
const rects = getElements().map(function(element){
return {
name: element.dataset.name,
data: callback(element)
};
});
const data = new Float64Array(rects.length * properties.length);
rects.forEach(function(rect, i){
properties.forEach(function(property, j){
data[i * properties.length + j] = rect.data[property];
});
});
crypto.subtle.digest("SHA-256", data)
.then(function(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");
dataNode.innerHTML = "<table><tr><th></th>" +
rects.map(function(rect){
return "<th>" + rect.name + "</th>";
}).join("") +
"</tr><tr><th>hash</th>" +
rects.map(function(rect){
return "<td class=\"rectHash\" data-name=\"" + rect.name + "\"></td>";
}).join("") +
"</tr>" +
properties.map(function(property){
return "<tr><th>" + property + "</th>" + rects.map(function(rect){
return "<td class=\"value\" title=\"" + rect.data[property] + "\">" +
formatNumber(rect.data[property]) +
"</td>";
}).join("") + "</tr>";
}).join("") +
"</table>";
rects.forEach(function(rect){
const data = new Float64Array(properties.length);
properties.forEach(function(property, i){
data[i] = rect.data[property];
});
crypto.subtle.digest("SHA-256", data).then(function(hash){
dataNode.querySelector(
".rectHash[data-name=\"" + rect.name + "\"]"
).textContent = byteArrayToHex(hash);
return;
}).catch(function(error){
dataNode.querySelector(
".rectHash[data-name=\"" + rect.name + "\"]"
).textContent = "Unable to compute hash: " + error;
});
});
}
function createTest(title, callback){ function createTest(title, callback){
const properties = ["x", "y", "width", "height", "top", "left", "right", "bottom"];
function performTest(){
const rects = getElements().map(function(element){
return {
name: element.dataset.name,
data: callback(element)
};
});
const data = new Float64Array(rects.length * properties.length);
rects.forEach(function(rect, i){
properties.forEach(function(property, j){
data[i * properties.length + j] = rect.data[property];
});
});
crypto.subtle.digest("SHA-256", data)
.then(function(hash){
output.querySelector(".hash").textContent = byteArrayToHex(hash);
});
function formatNumber(number){
const str = number.toString();
return "<span class=small>" + str.substring(0, str.length - 2) + "</span>" +
str.substring(str.length - 2);
}
var dataNode = output.querySelector(".data");
dataNode.innerHTML = "<table><tr><th></th>" +
rects.map(function(rect){
return "<th>" + rect.name + "</th>";
}).join("") +
"</tr><tr><th>hash</th>" +
rects.map(function(rect){
return "<td class=\"rectHash\" data-name=\"" + rect.name + "\"></td>";
}).join("") +
"</tr>" +
properties.map(function(property){
return "<tr><th>" + property + "</th>" + rects.map(function(rect){
return "<td class=\"value\" title=\"" + rect.data[property] + "\">" +
formatNumber(rect.data[property]) +
"</td>";
}).join("") + "</tr>";
}).join("") +
"</table>";
rects.forEach(function(rect){
const data = new Float64Array(properties.length);
properties.forEach(function(property, i){
data[i] = rect.data[property];
});
crypto.subtle.digest("SHA-256", data).then(function(hash){
dataNode.querySelector(
".rectHash[data-name=\"" + rect.name + "\"]"
).textContent = byteArrayToHex(hash);
});
});
}
const output = template.cloneNode(true); const output = template.cloneNode(true);
output.querySelector(".title").textContent = title; output.querySelector(".title").textContent = title;
output.querySelector(".refresh").addEventListener("click", performTest); output.querySelector(".refresh").addEventListener("click", function(){
performTest(output, callback);
});
output.querySelector(".performance").addEventListener("click", function(){ output.querySelector(".performance").addEventListener("click", function(){
let count = 200; let count = 200;
let totalCount = 0; let totalCount = 0;
@ -122,7 +134,7 @@
}()); }());
container.appendChild(output); container.appendChild(output);
performTest(); performTest(output, callback);
} }
iframe.addEventListener("load", function(){ iframe.addEventListener("load", function(){
createTest("Element.getClientRects", function(element){ createTest("Element.getClientRects", function(element){

View File

@ -1,2 +1,2 @@
/* eslint no-console: off */ // eslint-disable-next-line no-console
console.log("first possible call"); console.log("first possible call");

View File

@ -1,6 +1,14 @@
var log = function(){ var log = function(){
"use strict"; "use strict";
return function log(...str){ return function log(...str){
if (str[str.length - 1] === "match"){
str.unshift("color: green");
str.unshift("%cOK");
}
else if (str[str.length - 1].substr(0, 9) === "missmatch"){
str.unshift("color: red");
str.unshift("%cX");
}
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(...str); console.log(...str);
}; };
@ -32,7 +40,7 @@ function test(window){
// create window canvas // create window canvas
var canvas = document.createElement("canvas"); var canvas = document.createElement("canvas");
// draw image in window canvas // draw image in window canvas
var ctx = draw(canvas); draw(canvas);
return window.HTMLCanvasElement.prototype.toDataURL.call(canvas); return window.HTMLCanvasElement.prototype.toDataURL.call(canvas);
} }
@ -55,12 +63,13 @@ function hash(string){
function compare(string1, string2, alwaysOutputHashes){ function compare(string1, string2, alwaysOutputHashes){
"use strict"; "use strict";
function outputHashes(message){ function outputHashes(message){
Promise.all([ return Promise.all([
hash(string1), hash(string1),
hash(string2) hash(string2)
]).then(function(hashes){ ]).then(function(hashes){
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(message, ...hashes); console.log(message, ...hashes);
return;
}); });
} }
@ -98,4 +107,9 @@ hash(reference).then(function(hash){
"use strict"; "use strict";
log("reference hash:", hash); log("reference hash:", hash);
return;
}).catch(function(error){
"use strict";
log("%cX", "color: red", "Unable to compute reference hash:", error);
}); });

View File

@ -36,6 +36,7 @@ var performTest = function(){
var log = createLog(); var log = createLog();
log.createLine("test " + name, "h3"); log.createLine("test " + name, "h3");
var line = log.createLine(""); var line = log.createLine("");
var line2;
var time = 0; var time = 0;
var time2 = 0; var time2 = 0;
var min = Number.POSITIVE_INFINITY; var min = Number.POSITIVE_INFINITY;
@ -80,7 +81,7 @@ var performTest = function(){
} }
window.setTimeout(run, 10); window.setTimeout(run, 10);
}); });
var line2 = log.createLine(""); line2 = log.createLine("");
}; };
}(); }();

View File

@ -34,6 +34,7 @@ function addConsistencyTest(title, callback){
consistent.textContent = "computing"; consistent.textContent = "computing";
callback().then(function(value){ callback().then(function(value){
consistent.textContent = value? "OK": "not OK"; consistent.textContent = value? "OK": "not OK";
return;
}).catch(function(error){ }).catch(function(error){
consistent.classList.add("failed"); consistent.classList.add("failed");
if (Array.isArray(error)){ if (Array.isArray(error)){
@ -141,6 +142,7 @@ function addResolutionTest(title, callback){
number.textContent = "computing"; number.textContent = "computing";
callback(type).then(function(value){ callback(type).then(function(value){
number.textContent = value; number.textContent = value;
return;
}).catch(function(error){ }).catch(function(error){
number.classList.add("failed"); number.classList.add("failed");
number.textContent = error; number.textContent = error;
@ -214,15 +216,14 @@ function searchValue(tester){
return minValue; return minValue;
} }
else { else {
// eslint-disable-next-line promise/no-nesting
return tester(maxValue).then(function(testResult){ return tester(maxValue).then(function(testResult){
if (testResult.isEqual){ if (testResult.isEqual){
return maxValue; return maxValue;
} }
else { else {
return Promise.reject( throw "Search could not find exact value." +
"Search could not find exact value." + " It's between " + minValue + " and " + maxValue + ".";
" It's between " + minValue + " and " + maxValue + "."
);
} }
}); });
} }

View File

@ -42,8 +42,8 @@
try { try {
var firstFingerprint = fingerPrint(); var firstFingerprint = fingerPrint();
} }
catch (e){ catch (error){
console.log(new Date(), e); console.log(new Date(), error);
var firstFingerprint = false; var firstFingerprint = false;
} }
</script> </script>

View File

@ -1,4 +1,3 @@
/* eslint no-console: off */
(function(){ (function(){
"use strict"; "use strict";
@ -24,25 +23,35 @@
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;
} }
if (location.search !== "?notInitial"){ if (location.search !== "?notInitial"){
try {show(document.getElementById("top"), topTest());} try {show(document.getElementById("top"), topTest());}
catch (e){console.error(e);} // eslint-disable-next-line no-console
catch (error){console.error(error);}
try {show(document.getElementById("iframe"), iframeTest(document.querySelector("#iframe iframe")));} try {show(document.getElementById("iframe"), iframeTest(document.querySelector("#iframe iframe")));}
catch (e){console.error(e);} // eslint-disable-next-line no-console
catch (error){console.error(error);}
try {show(document.getElementById("iframe2"), iframeTest(document.querySelector("#iframe2 iframe")));} try {show(document.getElementById("iframe2"), iframeTest(document.querySelector("#iframe2 iframe")));}
catch (e){console.error(e);} // eslint-disable-next-line no-console
catch (error){console.error(error);}
try {show(document.getElementById("iframe3"), iframeTest(document.querySelector("#iframe3 iframe")));} try {show(document.getElementById("iframe3"), iframeTest(document.querySelector("#iframe3 iframe")));}
catch (e){console.error(e);} // eslint-disable-next-line no-console
catch (error){console.error(error);}
try {show(document.getElementById("iframe4"), dynamicIframeTest1());} try {show(document.getElementById("iframe4"), dynamicIframeTest1());}
catch (e){console.error(e);} // eslint-disable-next-line no-console
catch (error){console.error(error);}
try {show(document.getElementById("iframe5"), dynamicIframeTest2());} try {show(document.getElementById("iframe5"), dynamicIframeTest2());}
catch (e){console.error(e);} // eslint-disable-next-line no-console
catch (error){console.error(error);}
try {show(document.getElementById("iframe6"), dynamicIframeTest3());} try {show(document.getElementById("iframe6"), dynamicIframeTest3());}
catch (e){console.error(e);} // eslint-disable-next-line no-console
catch (error){console.error(error);}
} }
document.querySelector("#top button").addEventListener("click", function(){ document.querySelector("#top button").addEventListener("click", function(){
show(document.getElementById("top"), topTest()); show(document.getElementById("top"), topTest());

View File

@ -1,6 +1,50 @@
(function(){ (function(){
"use strict"; "use strict";
function getParameters(context){
const parameters = [];
for (var name in context){
if (name.toUpperCase() === name){
var value = context.getParameter(context[name]);
if (value !== null){
parameters.push({name: name, value: value});
}
}
}
const debugExtension = context.getExtension("WEBGL_debug_renderer_info");
for (name in debugExtension){
if (name.toUpperCase() === name){
value = context.getParameter(debugExtension[name]);
if (value !== null){
parameters.push({name: name, value: value});
}
}
}
var frontParameters = ["VENDOR", "RENDERER", "UNMASKED_VENDOR_WEBGL", "UNMASKED_RENDERER_WEBGL"];
parameters.sort(function(a, b){
var frontA = frontParameters.indexOf(a.name);
var frontB = frontParameters.indexOf(b.name);
if (frontA !== -1){
if (frontB !== -1){
return frontA - frontB;
}
else {
return -1;
}
}
else {
if (frontB !== -1){
return 1;
}
else {
return a.name < b.name? -1: 1;
}
}
});
return parameters;
}
["webgl", "webgl2"].forEach(function(context, index){ ["webgl", "webgl2"].forEach(function(context, index){
var output = document.createElement("div"); var output = document.createElement("div");
document.getElementById("output").appendChild(output); document.getElementById("output").appendChild(output);
@ -22,46 +66,8 @@
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 = [];
for (var name in gl){
if (name.toUpperCase() === name){
var value = gl.getParameter(gl[name]);
if (value !== null){
parameters.push({name: name, value: value});
}
}
}
const debugExtension = gl.getExtension("WEBGL_debug_renderer_info");
for (name in debugExtension){ const parameters = getParameters(gl);
if (name.toUpperCase() === name){
value = gl.getParameter(debugExtension[name]);
if (value !== null){
parameters.push({name: name, value: value});
}
}
}
var frontParameters = ["VENDOR", "RENDERER", "UNMASKED_VENDOR_WEBGL", "UNMASKED_RENDERER_WEBGL"];
parameters.sort(function(a, b){
var frontA = frontParameters.indexOf(a.name);
var frontB = frontParameters.indexOf(b.name);
if (frontA !== -1){
if (frontB !== -1){
return frontA - frontB;
}
else {
return -1;
}
}
else {
if (frontB !== -1){
return 1;
}
else {
return a.name < b.name? -1: 1;
}
}
});
if (context === "webgl2"){ if (context === "webgl2"){
var parameterOutput = document.createElement("table"); var parameterOutput = document.createElement("table");
document.getElementById("parameters").appendChild(parameterOutput); document.getElementById("parameters").appendChild(parameterOutput);
@ -87,11 +93,14 @@
(max !== 3 * values[255]? "": "not ") + "supported " + (max !== 3 * values[255]? "": "not ") + "supported " +
"(parameter hash: " + hash + ")"; "(parameter hash: " + hash + ")";
output.title = JSON.stringify(values); output.title = JSON.stringify(values);
return;
}).catch(function(error){
output.textContent = "Error while calculating hash: " + error;
}); });
} }
catch (e){ catch (error){
output.textContent = context + ": ERROR"; output.textContent = context + ": ERROR";
output.title = e; output.title = error;
} }
}); });
}()); }());