mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2025-03-13 11:44:12 +01:00
Merge branch 'master' into android
Conflicts: canvasblocker.xpi
This commit is contained in:
commit
d807702033
10
.jpmignore
Normal file
10
.jpmignore
Normal file
@ -0,0 +1,10 @@
|
||||
*.svg
|
||||
*.png
|
||||
*.xpi
|
||||
*.zip
|
||||
.*
|
||||
*.txt
|
||||
*.md
|
||||
test/
|
||||
addon description/
|
||||
doc/
|
15
README.md
15
README.md
@ -0,0 +1,15 @@
|
||||
This add-on allows users to prevent websites from using the Javascript <canvas> API to fingerprint them. Users can choose to block the <canvas> API entirely on some or all websites (which may break some websites) or just block or fake its fingerprinting-friendly readout API. More information on <canvas> fingerprinting can be found at http://www.browserleaks.com/canvas.
|
||||
|
||||
The different block modes are:
|
||||
<ul>
|
||||
<li>block readout API: All websites not on the white list or black list can use the <canvas> API to display something on the page, but the readout API is not allowed to return values to the website.</li>
|
||||
<li>fake readout API: Canvas Blocker's default setting, and my favorite! All websites not on the white list or black list can use the <canvas> API to display something on the page, but the readout API is forced to return a new random value each time it is called.</li>
|
||||
<li>ask for readout API permission: All websites not on the white list or black list can use the <canvas> API to display something on the page, but the user will be asked if the website should be allowed to use the readout API each time it is called.</li>
|
||||
<li>block everything: Ignore all lists and block the <canvas> API on all websites.</li>
|
||||
<li>allow only white list: Only websites in the white list are allowed to use the <canvas> API.</li>
|
||||
<li>ask for permission: If a website is not listed on the white list or black list, the user will be asked if the website should be allowed to use the <canvas> API each time it is called.</li>
|
||||
<li>block only black list: Block the <canvas> API only for websites on the black list.</li>
|
||||
<li>allow everything: Ignore all lists and allow the <canvas> API on all websites.</li>
|
||||
</ul>
|
||||
|
||||
At present, only my domain (kkapsner.de) is whitelisted by default.
|
19
addon description/de/description.txt
Normal file
19
addon description/de/description.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Dieses Add-on ermöglicht es Nutzer, Webseiten davon abzuhalten, sie über die Javascript <canvas>-API zu identifizieren. Nutzer können auswählen, ob die <canvas>-API komplett auf bestimmten oder allen Seiten blockiert wird (dies wird die Funktionalität einiger Seiten beeinträchtigen) oder nur die identifikationsfreundliche Auslese-API zu blockieren oder dort falsche Werte vorzutäuschen. Nähere Informationenen zum <canvas>-fingerprinting können Sie auf http://www.browserleaks.com/canvas finden.
|
||||
|
||||
Die verschiedenen Blockiermoden sind:
|
||||
<ul>
|
||||
<li>Auslese-API blockieren: Alle Webseiten, die nicht auf der Whitelist oder Blacklist gelistet sind, können die <canvas>-API zur Darstellung verwendet werden, aber die Auslese-API darf nicht verwendet werden.</li>
|
||||
<li>Auslese-API vortäuschen: Standardeinstellung und mein Favorit! Alle Webseiten, die nicht auf der Whitelist oder Blacklist gelistet sind, können die <canvas>-API zur Darstellung verwendet werden, aber die Auslese-API gibt zufällige Werte zurück, so dass das Fingerprinting immer einen anderen Wert liefert.</li>
|
||||
<li>bei Auslese-API um Erlaubnis fragen: Alle Webseiten, die nicht auf der Whitelist oder Blacklist gelistet sind, können die <canvas>-API zur Darstellung verwendet werden, aber der Nutzer wird jedesmal um Erlaubnis gefragt, wenn die Webseite die Readout-API verwenden möchte.</li>
|
||||
<li>alles blockieren: Ignoriert alle Listen und blockiert die <canvas>-API auf allen Webseiten.</li>
|
||||
<li>nur Einträge der Whitelist erlauben: Nur Seiten, die in der Whitelist gelistet sind, dürfen die <canvas>-API verwenden.</li>
|
||||
<li>um Erlaubnis fragen: Wenn eine Seite weder auf der Whitelist noch auf der Blacklist gelistet ist, wird der Benutzer gefragt, ob die Webseite die <canvas>-API verwenden darf, wenn sie benutzt wird.</li>
|
||||
<li>nur Einträge der Blacklist blockieren: Blockiere die <canvas>-API nur auf den Seiten der Blacklist.</li>
|
||||
<li>alles erlauben: Ignoriere alle Listen und erlaube die <canvas>-API auf allen Webseiten.</li>
|
||||
</ul>
|
||||
|
||||
Derzeit ist als Standard nur meine Domain (kkapsner.de) auf der Whitelist.
|
||||
|
||||
Falls Sie Fehler finden oder Verbesserungvorschläge haben, teilen Sie mir das bitte auf https://github.com/kkapsner/CanvasBlocker/issues mit.
|
||||
|
||||
Eine hochgradig experimentelle Version für Android ist verfügbar unter https://github.com/kkapsner/CanvasBlocker/tree/android
|
19
addon description/en/description.txt
Normal file
19
addon description/en/description.txt
Normal file
@ -0,0 +1,19 @@
|
||||
This add-on allows users to prevent websites from using the Javascript <canvas> API to fingerprint them. Users can choose to block the <canvas> API entirely on some or all websites (which may break some websites) or just block or fake its fingerprinting-friendly readout API. More information on <canvas> fingerprinting can be found at http://www.browserleaks.com/canvas.
|
||||
|
||||
The different block modes are:
|
||||
<ul>
|
||||
<li>block readout API: All websites not on the white list or black list can use the <canvas> API to display something on the page, but the readout API is not allowed to return values to the website.</li>
|
||||
<li>fake readout API: Canvas Blocker's default setting, and my favorite! All websites not on the white list or black list can use the <canvas> API to display something on the page, but the readout API is forced to return a new random value each time it is called.</li>
|
||||
<li>ask for readout API permission: All websites not on the white list or black list can use the <canvas> API to display something on the page, but the user will be asked if the website should be allowed to use the readout API each time it is called.</li>
|
||||
<li>block everything: Ignore all lists and block the <canvas> API on all websites.</li>
|
||||
<li>allow only white list: Only websites in the white list are allowed to use the <canvas> API.</li>
|
||||
<li>ask for permission: If a website is not listed on the white list or black list, the user will be asked if the website should be allowed to use the <canvas> API each time it is called.</li>
|
||||
<li>block only black list: Block the <canvas> API only for websites on the black list.</li>
|
||||
<li>allow everything: Ignore all lists and allow the <canvas> API on all websites.</li>
|
||||
</ul>
|
||||
|
||||
At present, only my domain (kkapsner.de) is whitelisted by default.
|
||||
|
||||
Please report issues and feature requests at https://github.com/kkapsner/CanvasBlocker/issues
|
||||
|
||||
A highly experimental version for Android is available at https://github.com/kkapsner/CanvasBlocker/tree/android
|
316
data/inject.js
316
data/inject.js
@ -1,316 +0,0 @@
|
||||
/* global self, window, CanvasRenderingContext2D, WebGLRenderingContext, console, unsafeWindow, exportFunction, cloneInto, checkURL, getDomainRegExpList */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var settings = {
|
||||
showCallingFile: false,
|
||||
showCompleteCallingStack: false
|
||||
};
|
||||
var blockMode = {
|
||||
getContext: {
|
||||
name: "getContext",
|
||||
status: "block",
|
||||
askText: {
|
||||
visible: "askForVisiblePermission",
|
||||
invisible: "askForInvisiblePermission",
|
||||
nocanvas: "askForPermission"
|
||||
},
|
||||
askStatus: {
|
||||
askOnce: false,
|
||||
alreadyAsked: {},
|
||||
answer: {}
|
||||
}
|
||||
},
|
||||
readAPI: {
|
||||
name: "readAPI",
|
||||
status: "allow",
|
||||
askText: {
|
||||
visible: "askForVisibleReadoutPermission",
|
||||
invisible: "askForInvisibleReadoutPermission",
|
||||
nocanvas: "askForReadoutPermission"
|
||||
},
|
||||
askStatus: {
|
||||
askOnce: false,
|
||||
alreadyAsked: {},
|
||||
answer: {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var undef;
|
||||
var randomImage = (function(){
|
||||
var length = Math.floor(20 + Math.random() * 100);
|
||||
var bytes = "";
|
||||
for (var i = 0; i < length; i += 1){
|
||||
bytes += String.fromCharCode(Math.floor(Math.random() * 256));
|
||||
}
|
||||
return bytes;
|
||||
}());
|
||||
|
||||
// parse calling stack
|
||||
function errorToCallingStackMsg(error){
|
||||
var msg = "";
|
||||
var callers = error.stack.trim().split("\n");
|
||||
//console.log(callers);
|
||||
var findme = callers.shift(); // Remove us from the stack
|
||||
findme = findme.replace(/(:[0-9]+){1,2}$/, ""); // rm line & column
|
||||
// Eliminate squashed stack. stack may contain 2+ stacks, but why...
|
||||
var inDoubleStack = false;
|
||||
callers = callers.filter(function(caller){
|
||||
var doubleStackStart = caller.search(findme) !== -1;
|
||||
inDoubleStack = inDoubleStack || doubleStackStart;
|
||||
return !inDoubleStack;
|
||||
});
|
||||
msg += "\n\n" + _("sourceOutput") + ": ";
|
||||
if (settings.showCompleteCallingStack){
|
||||
msg += callers.reduce(function(stack, c){
|
||||
return stack + "\n\t" + _("stackEntryOutput", parseStackEntry(c));
|
||||
}, "");
|
||||
}
|
||||
else{
|
||||
msg += _("stackEntryOutput", parseStackEntry(callers[0]));
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Check canvas appearance
|
||||
function canvasAppearance(context){
|
||||
var oldBorder = false;
|
||||
var canvas = false;
|
||||
var inDOM = null;
|
||||
if (context){
|
||||
if (context.nodeName === "CANVAS"){
|
||||
canvas = context;
|
||||
}
|
||||
else if (
|
||||
context instanceof CanvasRenderingContext2D ||
|
||||
context instanceof WebGLRenderingContext
|
||||
){
|
||||
canvas = context.canvas;
|
||||
}
|
||||
}
|
||||
if (canvas){
|
||||
oldBorder = canvas.style.border;
|
||||
canvas.style.border = "2px solid red";
|
||||
inDOM = canvas.ownerDocument.contains(canvas);
|
||||
}
|
||||
return {
|
||||
canvas: canvas,
|
||||
askCategory: canvas? (inDOM? "visible": "invisible"): "nocanvas",
|
||||
get text(){
|
||||
var text = canvas? (this.visible? "visible": "invisible"): "nocanvas";
|
||||
Object.defineProperty(this, "text", {value: text});
|
||||
return text;
|
||||
},
|
||||
inDom: inDOM,
|
||||
get visible(){
|
||||
var visible = inDOM;
|
||||
if (inDOM){
|
||||
canvas.scrollIntoView();
|
||||
var rect = canvas.getBoundingClientRect();
|
||||
var foundEl = document.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
|
||||
visible = (foundEl === canvas);
|
||||
}
|
||||
Object.defineProperty(this, "visible", {value: visible});
|
||||
return visible;
|
||||
},
|
||||
reset: function(){
|
||||
if (canvas){
|
||||
canvas.style.border = oldBorder;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// changed functions
|
||||
var changedFunctions = {
|
||||
getContext: {
|
||||
mode: blockMode.getContext,
|
||||
object: unsafeWindow.HTMLCanvasElement
|
||||
},
|
||||
toDataURL: {
|
||||
mode: blockMode.readAPI,
|
||||
object: unsafeWindow.HTMLCanvasElement,
|
||||
fake: function(){
|
||||
var type = arguments[0] || "image/png";
|
||||
return "data:" + type + ";base64," + btoa(randomImage);
|
||||
}
|
||||
},
|
||||
toBlob: {
|
||||
mode: blockMode.readAPI,
|
||||
object: unsafeWindow.HTMLCanvasElement,
|
||||
fake: function(callback){
|
||||
var type = arguments[0] || "image/png";
|
||||
var blob = new window.Blob(randomImage, {type: type});
|
||||
callback(blob);
|
||||
},
|
||||
exportOptions: {allowCallbacks: true}
|
||||
},
|
||||
mozGetAsFile: {
|
||||
mode: blockMode.readAPI,
|
||||
object: unsafeWindow.HTMLCanvasElement
|
||||
},
|
||||
getImageData: {
|
||||
mode: blockMode.readAPI,
|
||||
object: unsafeWindow.CanvasRenderingContext2D,
|
||||
fake: function(sx, sy, sw, sh){
|
||||
var l = sw * sh * 4;
|
||||
var data = new Uint8ClampedArray(l);
|
||||
for (var i = 0; i < l; i += 1){
|
||||
data[i] = Math.floor(
|
||||
Math.random() * 256
|
||||
);
|
||||
}
|
||||
var imageData = new window.ImageData(sw, sh);
|
||||
imageData.data.set(cloneInto(data, unsafeWindow));
|
||||
return imageData;
|
||||
}
|
||||
},
|
||||
readPixels: {
|
||||
mode: blockMode.readAPI,
|
||||
object: unsafeWindow.WebGLRenderingContext,
|
||||
fake: function(x, y, width, height, format, type, pixels){
|
||||
// fake not working due to XRay copy restrictions...
|
||||
// for (var i = 0; i < pixels.length; i += 1){
|
||||
// pixels[i] = Math.floor(
|
||||
// Math.random() * 256
|
||||
// );
|
||||
// }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(changedFunctions).forEach(function(name){
|
||||
var changedFunction = changedFunctions[name];
|
||||
var original = changedFunction.object.prototype[name];
|
||||
Object.defineProperty(
|
||||
changedFunction.object.prototype,
|
||||
name,
|
||||
{
|
||||
enumerable: true,
|
||||
configureable: false,
|
||||
get: exportFunction(function(){
|
||||
var status = changedFunction.mode.status;
|
||||
var callingStackMsg = errorToCallingStackMsg(new Error());
|
||||
if (status === "ask"){
|
||||
var askStatus = changedFunction.mode.askStatus;
|
||||
var appearance = canvasAppearance(this);
|
||||
if (askStatus.askOnce && askStatus.alreadyAsked[appearance.askCategory]){
|
||||
// console.log("already asked");
|
||||
status = askStatus.answer[appearance.askCategory];
|
||||
}
|
||||
else {
|
||||
//console.log("asking");
|
||||
var msg = _(changedFunction.mode.askText[appearance.text]);
|
||||
if (settings.showCallingFile){
|
||||
msg += callingStackMsg;
|
||||
}
|
||||
status = window.confirm(msg) ? "allow": "block";
|
||||
askStatus.alreadyAsked[appearance.text] = true;
|
||||
askStatus.answer[appearance.text] = status;
|
||||
//console.log("asking (done)");
|
||||
appearance.reset();
|
||||
}
|
||||
}
|
||||
self.port.emit("accessed " + changedFunction.mode.name, status, callingStackMsg);
|
||||
switch (status){
|
||||
case "allow":
|
||||
return original;
|
||||
case "fake":
|
||||
return changedFunction.fake? exportFunction(
|
||||
changedFunction.fake,
|
||||
unsafeWindow,
|
||||
changedFunction.exportOptions
|
||||
): undef;
|
||||
//case "block":
|
||||
default:
|
||||
return undef;
|
||||
}
|
||||
}, unsafeWindow)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Stack parsing
|
||||
function parseStackEntry(entry){
|
||||
var m = /@(.*):(\d*):(\d*)$/.exec(entry) || ["", entry, "--", "--"];
|
||||
return {
|
||||
url: m[1],
|
||||
line: m[2],
|
||||
column: m[3],
|
||||
raw: entry
|
||||
};
|
||||
}
|
||||
|
||||
// Translation
|
||||
var _ = function(name, replace){
|
||||
var str = self.options.translations[name] || name;
|
||||
if (replace){
|
||||
Object.keys(replace).forEach(function(name){
|
||||
str = str.replace(new RegExp("{" + name + "}", "g"), replace[name]);
|
||||
});
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
// Communication with main.js
|
||||
|
||||
function setStatus(mode, askOnce){
|
||||
switch (mode){
|
||||
case "block":
|
||||
blockMode.getContext.status = "block";
|
||||
blockMode.readAPI.status = "block";
|
||||
break;
|
||||
case "ask":
|
||||
blockMode.getContext.status = "ask";
|
||||
blockMode.getContext.askStatus.askOnce = askOnce;
|
||||
blockMode.readAPI.status = "allow";
|
||||
break;
|
||||
case "blockReadout":
|
||||
blockMode.getContext.status = "allow";
|
||||
blockMode.readAPI.status = "block";
|
||||
break;
|
||||
case "fakeReadout":
|
||||
blockMode.getContext.status = "allow";
|
||||
blockMode.readAPI.status = "fake";
|
||||
break;
|
||||
case "askReadout":
|
||||
blockMode.getContext.status = "allow";
|
||||
blockMode.readAPI.status = "ask";
|
||||
blockMode.readAPI.askStatus.askOnce = askOnce;
|
||||
break;
|
||||
case "unblock":
|
||||
blockMode.getContext.status = "allow";
|
||||
blockMode.readAPI.status = "allow";
|
||||
break;
|
||||
case "detach":
|
||||
blockMode.getContext.status = "allow";
|
||||
blockMode.readAPI.status = "allow";
|
||||
break;
|
||||
}
|
||||
}
|
||||
["block", "ask", "blockReadout", "fakeReadout", "askReadout", "unblock", "detach"].forEach(function(mode){
|
||||
self.port.on(mode, function(askOnce){
|
||||
setStatus(mode, askOnce);
|
||||
});
|
||||
});
|
||||
|
||||
setStatus(
|
||||
checkURL(
|
||||
location,
|
||||
self.options.blockMode,
|
||||
getDomainRegExpList(self.options.whiteList),
|
||||
getDomainRegExpList(self.options.blackList)
|
||||
),
|
||||
self.options.askOnce
|
||||
);
|
||||
|
||||
// settings passthrough
|
||||
self.port.on("set", function(name, value){
|
||||
settings[name] = value;
|
||||
});
|
||||
}());
|
20
data/options.css
Normal file
20
data/options.css
Normal file
@ -0,0 +1,20 @@
|
||||
setting[pref-name="showNotifications"] {
|
||||
border-bottom: 0px transparent none;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
setting[pref-name="ignoreList"]{
|
||||
border-top: 0px transparent none;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
setting[pref-name="showCallingFile"]{
|
||||
border-bottom: 0px transparent none;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
setting[pref-name="showCompleteCallingStack"]{
|
||||
border-top: 0px transparent none;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
setting[pref-name="stackList"]{
|
||||
border-top: 0px transparent none;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
120
lib/askForPermission.js
Normal file
120
lib/askForPermission.js
Normal file
@ -0,0 +1,120 @@
|
||||
/* jslint moz: true */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
const _ = require("sdk/l10n").get;
|
||||
const preferences = require("sdk/simple-prefs");
|
||||
const prefs = preferences.prefs;
|
||||
|
||||
// Check canvas appearance
|
||||
function canvasAppearance(window, context){
|
||||
var oldBorder = false;
|
||||
var canvas = false;
|
||||
var inDOM = null;
|
||||
if (context){
|
||||
if (context.nodeName === "CANVAS"){
|
||||
canvas = context;
|
||||
}
|
||||
else if (
|
||||
context instanceof window.CanvasRenderingContext2D ||
|
||||
context instanceof window.WebGLRenderingContext
|
||||
){
|
||||
canvas = context.canvas;
|
||||
}
|
||||
}
|
||||
if (canvas){
|
||||
oldBorder = canvas.style.border;
|
||||
canvas.style.border = "2px solid red";
|
||||
inDOM = canvas.ownerDocument.contains(canvas);
|
||||
}
|
||||
return {
|
||||
canvas: canvas,
|
||||
askCategory: canvas? (inDOM? "visible": "invisible"): "nocanvas",
|
||||
get text(){
|
||||
var text = canvas? (this.visible? "visible": "invisible"): "nocanvas";
|
||||
Object.defineProperty(this, "text", {value: text});
|
||||
return text;
|
||||
},
|
||||
inDom: inDOM,
|
||||
get visible(){
|
||||
var visible = inDOM;
|
||||
if (inDOM){
|
||||
canvas.scrollIntoView();
|
||||
var rect = canvas.getBoundingClientRect();
|
||||
var foundEl = window.document.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
|
||||
visible = (foundEl === canvas);
|
||||
}
|
||||
Object.defineProperty(this, "visible", {value: visible});
|
||||
return visible;
|
||||
},
|
||||
reset: function(){
|
||||
if (canvas){
|
||||
canvas.style.border = oldBorder;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var modes = new WeakMap();
|
||||
function getAskMode(window, type){
|
||||
var mode = modes.get(window);
|
||||
if (mode){
|
||||
return mode[type];
|
||||
}
|
||||
else {
|
||||
mode = {
|
||||
context: {
|
||||
askText: {
|
||||
visible: _("askForVisiblePermission"),
|
||||
invisible: _("askForInvisiblePermission"),
|
||||
nocanvas: _("askForPermission")
|
||||
},
|
||||
askStatus: {
|
||||
alreadyAsked: {},
|
||||
answer: {}
|
||||
}
|
||||
},
|
||||
readout: {
|
||||
askText: {
|
||||
visible: _("askForVisibleReadoutPermission"),
|
||||
invisible: _("askForInvisibleReadoutPermission"),
|
||||
nocanvas: _("askForReadoutPermission")
|
||||
},
|
||||
askStatus: {
|
||||
alreadyAsked: {},
|
||||
answer: {}
|
||||
}
|
||||
}
|
||||
};
|
||||
modes.set(window, mode);
|
||||
return mode[type];
|
||||
}
|
||||
}
|
||||
|
||||
exports.ask = function(window, type, canvas, callingStackMsg){
|
||||
var answer;
|
||||
var askMode = getAskMode(window, type);
|
||||
var askStatus = askMode.askStatus;
|
||||
var appearance = canvasAppearance(window, canvas);
|
||||
if (prefs.askOnlyOnce && askStatus.alreadyAsked[appearance.askCategory]){
|
||||
// already asked
|
||||
appearance.reset();
|
||||
return askStatus.answer[appearance.askCategory];
|
||||
}
|
||||
else {
|
||||
// asking
|
||||
var msg = _(askMode.askText[appearance.text]);
|
||||
if (prefs.showCallingFile){
|
||||
msg += callingStackMsg;
|
||||
}
|
||||
answer = window.confirm(msg)? "allow": "block";
|
||||
askStatus.alreadyAsked[appearance.text] = true;
|
||||
askStatus.answer[appearance.text] = answer;
|
||||
appearance.reset();
|
||||
return answer;
|
||||
}
|
||||
};
|
||||
}());
|
110
lib/lists.js
Normal file
110
lib/lists.js
Normal file
@ -0,0 +1,110 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
var preferences = require("sdk/simple-prefs");
|
||||
var prefService = require("sdk/preferences/service");
|
||||
var prefs = preferences.prefs;
|
||||
|
||||
|
||||
function getDomainRegExpList(domainList){
|
||||
"use strict";
|
||||
|
||||
var list = domainList
|
||||
.split(",")
|
||||
.map(function(entry){
|
||||
return entry.replace(/^\s+|\s+$/g, "");
|
||||
})
|
||||
.filter(function(entry){
|
||||
return !!entry.length;
|
||||
})
|
||||
.map(function(entry){
|
||||
var regExp;
|
||||
var domain = !!entry.match(/^[\w.]+$/);
|
||||
if (domain){
|
||||
regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\\+\*\?\[\^\]\$\(\)\{\}\=\!\|\.])/g, "\\$1") + "\\.?$", "i");
|
||||
}
|
||||
else {
|
||||
regExp = new RegExp(entry, "i");
|
||||
}
|
||||
return {
|
||||
match: function(url){
|
||||
if (domain){
|
||||
return url.hostname.match(regExp);
|
||||
}
|
||||
else {
|
||||
return url.href.match(regExp);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
list.match = function(url){
|
||||
return this.some(function(entry){
|
||||
return entry.match(url);
|
||||
});
|
||||
};
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
var lists = {
|
||||
white: [],
|
||||
"ignore": [],
|
||||
black: []
|
||||
};
|
||||
|
||||
function updateList(type){
|
||||
"use strict";
|
||||
|
||||
lists[type] = getDomainRegExpList(prefs[type + "List"]);
|
||||
}
|
||||
Object.keys(lists).forEach(function(type){
|
||||
"use strict";
|
||||
|
||||
preferences.on(type + "List", function(){
|
||||
updateList(type);
|
||||
});
|
||||
updateList(type);
|
||||
});
|
||||
|
||||
function updateStackList(){
|
||||
try {
|
||||
var data = JSON.parse(prefs.stackList);
|
||||
if (!Array.isArray(data)){
|
||||
data = [data];
|
||||
}
|
||||
var list = data.filter(function(entry){
|
||||
return typeof entry === "object" && typeof entry.url === "string";
|
||||
});
|
||||
}
|
||||
catch(e){
|
||||
var list = [];
|
||||
}
|
||||
list.match = function(stack){
|
||||
return this.some(function(stackRule){
|
||||
return stack.match(stackRule);
|
||||
});
|
||||
};
|
||||
lists.stack = list;
|
||||
}
|
||||
lists.stack = [];
|
||||
preferences.on("stackList", function(){
|
||||
updateStackList();
|
||||
});
|
||||
updateStackList();
|
||||
|
||||
exports.get = function getList(type){
|
||||
"use strict";
|
||||
|
||||
return lists[type];
|
||||
};
|
||||
exports.appendTo = function appendToList(type, entry){
|
||||
"use strict";
|
||||
|
||||
prefs[type + "List"] += (prefs[type + "List"]? ",": "") + entry;
|
||||
prefService.set("extensions.CanvasBlocker@kkapsner.de." + type + "List", prefs[type + "List"]);
|
||||
updateList(type);
|
||||
};
|
||||
exports.update = updateList;
|
267
lib/main.js
267
lib/main.js
@ -1,219 +1,86 @@
|
||||
/* global console */
|
||||
/* jslint moz: true */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var self = require("sdk/self");
|
||||
var pageMod = require("sdk/page-mod");
|
||||
var array = require("sdk/util/array");
|
||||
var preferences = require("sdk/simple-prefs");
|
||||
var prefService = require("sdk/preferences/service");
|
||||
var prefs = preferences.prefs;
|
||||
var URL = require("sdk/url").URL;
|
||||
var _ = require("sdk/l10n").get;
|
||||
var tabUtils = require("sdk/tabs/utils");
|
||||
require("./stylePreferencePane");
|
||||
const {changedFunctions} = require("./modifiedAPI");
|
||||
const {notify} = require("./notifications");
|
||||
const {ask} = require("./askForPermission");
|
||||
const lists = require("./lists");
|
||||
|
||||
var sharedFunctions = require("./sharedFunctions.js");
|
||||
var getDomainRegExpList = sharedFunctions.getDomainRegExpList;
|
||||
// preferences
|
||||
Object.keys(prefs).forEach(function(pref){
|
||||
preferences.on(pref, function(){
|
||||
workers.forEach(checkWorker);
|
||||
});
|
||||
});
|
||||
var whiteList;
|
||||
function updateWhiteList(){
|
||||
whiteList = getDomainRegExpList(prefs.whiteList);
|
||||
}
|
||||
updateWhiteList();
|
||||
preferences.on("whiteList", function(){
|
||||
updateWhiteList();
|
||||
});
|
||||
|
||||
var blackList;
|
||||
function updateBlackList(){
|
||||
blackList = getDomainRegExpList(prefs.blackList);
|
||||
}
|
||||
updateBlackList();
|
||||
preferences.on("blackList", function(){
|
||||
updateBlackList();
|
||||
});
|
||||
|
||||
var ignoreList;
|
||||
function updateIgnoreList(){
|
||||
ignoreList = getDomainRegExpList(prefs.ignoreList);
|
||||
}
|
||||
updateIgnoreList();
|
||||
preferences.on("ignoreList", function(){
|
||||
updateIgnoreList();
|
||||
});
|
||||
const sharedFunctions = require("./sharedFunctions");
|
||||
|
||||
// preferences for injected file
|
||||
var preferencesForInjected = ["showCallingFile", "showCompleteCallingStack"];
|
||||
preferencesForInjected.forEach(function(name){
|
||||
preferences.on(name, function(){
|
||||
workers.forEach(function(worker){
|
||||
worker.port.emit("set", name, prefs[name]);
|
||||
});
|
||||
});
|
||||
});
|
||||
const observers = require("sdk/system/events");
|
||||
const { when: unload } = require("sdk/system/unload");
|
||||
|
||||
function checkURL(url){
|
||||
return sharedFunctions.checkURL(url, prefs.blockMode, whiteList, blackList);
|
||||
}
|
||||
function checkWorker(worker){
|
||||
try {
|
||||
var mode;
|
||||
var url = new URL(worker.url);
|
||||
if (
|
||||
(url.protocol === "about:") ||
|
||||
(prefs.allowPDFCanvas && worker.tab.contentType.match(/\/pdf$/i))
|
||||
){
|
||||
mode = "unblock";
|
||||
}
|
||||
else {
|
||||
mode = checkURL(url);
|
||||
}
|
||||
worker.port.emit(mode, prefs.askOnlyOnce);
|
||||
const preferences = require("sdk/simple-prefs");
|
||||
const prefs = preferences.prefs;
|
||||
|
||||
function check(callingStack, url){
|
||||
var match = sharedFunctions.check(callingStack, url, prefs.blockMode).match(/^(block|allow|fake|ask)(|Readout|Everything|Context)$/);
|
||||
if (match){
|
||||
return {
|
||||
type: (match[2] === "Everything" || match[2] === "")?
|
||||
["context", "readout"]:
|
||||
[match[2].toLowerCase()],
|
||||
mode: match[1]
|
||||
};
|
||||
|
||||
}
|
||||
catch (e){
|
||||
console.log("Error updating " + worker.url + ": " + e.message);
|
||||
else {
|
||||
return {
|
||||
type: ["context", "readout"],
|
||||
mode: "block"
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var workers = [];
|
||||
var workerTranslations = {
|
||||
sourceOutput: _("sourceOutput"),
|
||||
stackEntryOutput: _("stackEntryOutput")
|
||||
};
|
||||
|
||||
["", "Readout"].forEach(function(type){
|
||||
["", "Visible", "Invisible"].forEach(function(visibility){
|
||||
var text = "askFor" + visibility + type + "Permission";
|
||||
workerTranslations[text] = _(text);
|
||||
});
|
||||
});
|
||||
var apiNames = Object.keys(changedFunctions);
|
||||
var undef;
|
||||
|
||||
function intercept({subject: window}){
|
||||
apiNames.forEach(function(name){
|
||||
var changedFunction = changedFunctions[name];
|
||||
var original = window.wrappedJSObject[changedFunction.object].prototype[name];
|
||||
|
||||
var workerOptions = {
|
||||
blockMode: checkURL(),
|
||||
whiteList: prefs.whiteList,
|
||||
blackList: prefs.blackList,
|
||||
askOnce: prefs.askOnce,
|
||||
translations: workerTranslations
|
||||
};
|
||||
preferences.on("blockMode", function(){
|
||||
workerOptions.blockMode = checkURL();
|
||||
});
|
||||
["whiteList", "blackList", "askOnce"].forEach(function(prefName){
|
||||
preferences.on(prefName, function(){
|
||||
workerOptions[prefName] = prefs[prefName];
|
||||
});
|
||||
});
|
||||
pageMod.PageMod({
|
||||
include: "*",
|
||||
contentScriptWhen: "start",
|
||||
contentScriptFile: [
|
||||
self.data.url("sharedFunctions.js").replace("/data/", "/lib/"),
|
||||
self.data.url("inject.js"),
|
||||
],
|
||||
contentScriptOptions: workerOptions,
|
||||
onAttach: function(worker){
|
||||
|
||||
array.add(workers, worker);
|
||||
worker.on("pageshow", function(){
|
||||
array.add(workers, this);
|
||||
});
|
||||
worker.on("pagehide", function(){
|
||||
array.remove(workers, this);
|
||||
});
|
||||
worker.on("detach", function(){
|
||||
array.remove(workers, this);
|
||||
});
|
||||
|
||||
preferencesForInjected.forEach(function(name){
|
||||
worker.port.emit("set", name, prefs[name]);
|
||||
});
|
||||
|
||||
checkWorker(worker);
|
||||
|
||||
// display notifications
|
||||
worker.port.on("accessed readAPI", function(status, callingStackMsg){
|
||||
switch (status){
|
||||
case "fake":
|
||||
|
||||
var contentURL = new URL(worker.contentURL);
|
||||
if (!ignoreList.match(contentURL)){
|
||||
var url = contentURL.href;
|
||||
var domain = contentURL.hostname;
|
||||
var message = _("fakedReadout").replace(/\{url\}/g, url);
|
||||
|
||||
var tab = tabUtils.getTabForId(worker.tab.id);
|
||||
var tabBrowser = tabUtils.getTabBrowserForTab(tab);
|
||||
var browser = tabUtils.getBrowserForTab(tab);
|
||||
|
||||
var notifyBox = tabBrowser.getNotificationBox(browser);
|
||||
var notification = notifyBox.getNotificationWithValue("fake-readout");
|
||||
if (notification){
|
||||
notification.label = message;
|
||||
Object.defineProperty(
|
||||
window.wrappedJSObject[changedFunction.object].prototype,
|
||||
name,
|
||||
{
|
||||
enumerable: true,
|
||||
configureable: false,
|
||||
get: function(){
|
||||
var callingStack = sharedFunctions.errorToCallingStack(new Error());
|
||||
var status = check(callingStack, window.location);
|
||||
if (status.type.indexOf(changedFunction.type) !== -1){
|
||||
if (status.mode === "ask"){
|
||||
status.mode = ask(window, changedFunction.type, this, callingStack);
|
||||
}
|
||||
else {
|
||||
var buttons = [
|
||||
{
|
||||
label: _("displayCallingStack"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
browser.contentWindow.alert(callingStackMsg);
|
||||
// only way to prevent closing... see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/appendNotification#Notification_box_events
|
||||
throw new Error("Do not close notification.");
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("ignorelistDomain"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
prefs.ignoreList += "," + domain;
|
||||
prefService.set("extensions.CanvasBlocker@kkapsner.de.ignoreList", prefs.ignoreList);
|
||||
updateIgnoreList();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("whitelistURL"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
prefs.whiteList += "," + url;
|
||||
prefService.set("extensions.CanvasBlocker@kkapsner.de.whiteList", prefs.whiteList);
|
||||
updateWhiteList();
|
||||
workers.forEach(checkWorker);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("whitelistDomain"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
prefs.whiteList += "," + domain;
|
||||
prefService.set("extensions.CanvasBlocker@kkapsner.de.whiteList", prefs.whiteList);
|
||||
updateWhiteList();
|
||||
workers.forEach(checkWorker);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
var priority = notifyBox.PRIORITY_WARNING_MEDIUM;
|
||||
notification = notifyBox.appendNotification(
|
||||
message,
|
||||
"fake-readout",
|
||||
"chrome://browser/skin/Info.png",
|
||||
priority,
|
||||
buttons
|
||||
);
|
||||
switch (status.mode){
|
||||
case "allow":
|
||||
return original;
|
||||
case "fake":
|
||||
notify(window, callingStack);
|
||||
return changedFunction.fake || undef;
|
||||
//case "block":
|
||||
default:
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
break;
|
||||
else {
|
||||
return original;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
observers.on("content-document-global-created", intercept);
|
||||
unload(function(){
|
||||
observers.off("content-document-global-created", intercept);
|
||||
});
|
||||
|
||||
}());
|
119
lib/modifiedAPI.js
Normal file
119
lib/modifiedAPI.js
Normal file
@ -0,0 +1,119 @@
|
||||
/* jslint moz: true, bitwise: true */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
function getFakeCanvas(window, original){
|
||||
var context = window.HTMLCanvasElement.prototype.getContext.call(original, "2d");
|
||||
var imageData, data, source;
|
||||
if (context){
|
||||
imageData = window.CanvasRenderingContext2D.prototype.getImageData.call(context, 0, 0, original.width, original.height);
|
||||
source = imageData.data;
|
||||
}
|
||||
else {
|
||||
context =
|
||||
window.HTMLCanvasElement.prototype.getContext.call(original, "webgl") ||
|
||||
window.HTMLCanvasElement.prototype.getContext.call(original, "experimental-webgl") ||
|
||||
window.HTMLCanvasElement.prototype.getContext.call(original, "webgl2") ||
|
||||
window.HTMLCanvasElement.prototype.getContext.call(original, "experimental-webgl2");
|
||||
imageData = new window.wrappedJSObject.ImageData(original.width, original.height);
|
||||
source = new window.wrappedJSObject.Uint8Array(imageData.data.length);
|
||||
window.WebGLRenderingContext.prototype.readPixels.call(
|
||||
context,
|
||||
0, 0, original.width, original.height,
|
||||
context.RGBA, context.UNSIGNED_BYTE,
|
||||
source
|
||||
);
|
||||
}
|
||||
var data = imageData.data;
|
||||
|
||||
for (var i = 0, l = data.length; i < l; i += 1){
|
||||
var value = source[i];
|
||||
if (value >= 0x80){
|
||||
value = value ^ Math.floor(Math.random() * 0x20);
|
||||
}
|
||||
else if (value >= 0x40){
|
||||
value = value ^ Math.floor(Math.random() * 0x10);
|
||||
}
|
||||
else if (value >= 0x20){
|
||||
value = value ^ Math.floor(Math.random() * 0x08);
|
||||
}
|
||||
else if (value >= 0x10){
|
||||
value = value ^ Math.floor(Math.random() * 0x04);
|
||||
}
|
||||
else if (value >= 0x08){
|
||||
value = value ^ Math.floor(Math.random() * 0x02);
|
||||
}
|
||||
else if (value >= 0x04){
|
||||
value = value ^ Math.floor(Math.random() * 0x01);
|
||||
}
|
||||
data[i] = value;
|
||||
}
|
||||
var canvas = original.cloneNode(true);
|
||||
context = window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d");
|
||||
context.putImageData(imageData, 0, 0);
|
||||
return canvas;
|
||||
}
|
||||
function getWindow(canvas){
|
||||
return canvas.ownerDocument.defaultView;
|
||||
}
|
||||
// changed functions and their fakes
|
||||
exports.changedFunctions = {
|
||||
getContext: {
|
||||
type: "context",
|
||||
object: "HTMLCanvasElement"
|
||||
},
|
||||
toDataURL: {
|
||||
type: "readout",
|
||||
object: "HTMLCanvasElement",
|
||||
fake: function toDataURL(){
|
||||
var window = getWindow(this);
|
||||
return window.HTMLCanvasElement.prototype.toDataURL.apply(getFakeCanvas(window, this), arguments);
|
||||
}
|
||||
},
|
||||
toBlob: {
|
||||
type: "readout",
|
||||
object: "HTMLCanvasElement",
|
||||
fake: function toBlob(callback){
|
||||
var window = getWindow(this);
|
||||
return window.HTMLCanvasElement.prototype.toBlob.apply(getFakeCanvas(window, this), arguments);
|
||||
},
|
||||
exportOptions: {allowCallbacks: true}
|
||||
},
|
||||
mozGetAsFile: {
|
||||
type: "readout",
|
||||
object: "HTMLCanvasElement",
|
||||
mozGetAsFile: function mozGetAsFile(callbak){
|
||||
var window = getWindow(this);
|
||||
return window.HTMLCanvasElement.prototype.mozGetAsFile.apply(getFakeCanvas(window, this), arguments);
|
||||
}
|
||||
},
|
||||
getImageData: {
|
||||
type: "readout",
|
||||
object: "CanvasRenderingContext2D",
|
||||
fake: function getImageData(sx, sy, sw, sh){
|
||||
var window = getWindow(this.canvas);
|
||||
var context = window.HTMLCanvasElement.prototype.getContext.call(getFakeCanvas(window, this.canvas), "2d");
|
||||
var data = window.CanvasRenderingContext2D.prototype.getImageData.apply(context, arguments).data;
|
||||
|
||||
var imageData = new window.wrappedJSObject.ImageData(sw, sh);
|
||||
for (var i = 0, l = data.length; i < l; i += 1){
|
||||
imageData.data[i] = data[i];
|
||||
}
|
||||
return imageData;
|
||||
}
|
||||
},
|
||||
readPixels: {
|
||||
type: "readout",
|
||||
object: "WebGLRenderingContext",
|
||||
fake: function readPixels(x, y, width, height, format, type, pixels){
|
||||
var window = getWindow(this.canvas);
|
||||
var context = window.HTMLCanvasElement.prototype.getContext.call(getFakeCanvas(window, this.canvas), "webGL");
|
||||
return window.WebGLRenderingContext.prototype.readPixels.apply(context, arguments);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
117
lib/notifications.js
Normal file
117
lib/notifications.js
Normal file
@ -0,0 +1,117 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var _ = require("sdk/l10n").get;
|
||||
var preferences = require("sdk/simple-prefs");
|
||||
var prefService = require("sdk/preferences/service");
|
||||
var prefs = preferences.prefs;
|
||||
var tabUtils = require("sdk/tabs/utils");
|
||||
var lists = require("./lists");
|
||||
var URL = require("sdk/url").URL;
|
||||
|
||||
exports.notify = function(window, callingStackMsg){
|
||||
"use strict";
|
||||
|
||||
var contentURL = new URL(window.location);
|
||||
if (prefs.showNotifications && !lists.get("ignore").match(contentURL)){
|
||||
var url = contentURL.href;
|
||||
var domain = contentURL.hostname;
|
||||
var message = _("fakedReadout").replace(/\{url\}/g, domain);
|
||||
|
||||
var tab = tabUtils.getTabForContentWindow(window);
|
||||
var tabBrowser = tabUtils.getTabBrowserForTab(tab);
|
||||
var browser = tabUtils.getBrowserForTab(tab);
|
||||
|
||||
var notifyBox = tabBrowser.getNotificationBox(browser);
|
||||
var notification = notifyBox.getNotificationWithValue("fake-readout");
|
||||
if (notification){
|
||||
notification.label = message;
|
||||
notification.url = url;
|
||||
notification.domain = domain;
|
||||
notification.callingStackMsg = callingStackMsg;
|
||||
}
|
||||
else {
|
||||
var buttons = [
|
||||
{
|
||||
label: _("displayFullURL"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
browser.contentWindow.alert(notification.url);
|
||||
// only way to prevent closing... see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/appendNotification#Notification_box_events
|
||||
throw new Error("Do not close notification.");
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("displayCallingStack"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
browser.contentWindow.alert(notification.callingStackMsg);
|
||||
// only way to prevent closing... see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/appendNotification#Notification_box_events
|
||||
throw new Error("Do not close notification.");
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("ignorelistDomain"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
var domain = browser.contentWindow.prompt(
|
||||
_("inputIgnoreDomain"),
|
||||
notification.domain
|
||||
);
|
||||
if (domain){
|
||||
lists.appendTo("ignore", domain);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("whitelistURL"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
var url = browser.contentWindow.prompt(
|
||||
_("inputWhitelistDomain"),
|
||||
"^" + notification.url.replace(/([\\\+\*\?\[\^\]\$\(\)\{\}\=\!\|\.])/g, "\\$1") + "$"
|
||||
);
|
||||
if (url){
|
||||
lists.appendTo("white", url);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("whitelistDomain"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
var domain = browser.contentWindow.prompt(
|
||||
_("inputWhitelistURL"),
|
||||
notification.domain
|
||||
);
|
||||
if (domain){
|
||||
lists.appendTo("white", domain);
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
label: _("disableNotifications"),
|
||||
accessKey: "",
|
||||
callback: function(){
|
||||
prefs.showNotifications = false;
|
||||
prefService.set("extensions.CanvasBlocker@kkapsner.de.showNotifications", prefs.showNotifications);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
var priority = notifyBox.PRIORITY_WARNING_MEDIUM;
|
||||
notification = notifyBox.appendNotification(
|
||||
message,
|
||||
"fake-readout",
|
||||
"chrome://browser/skin/Info.png",
|
||||
priority,
|
||||
buttons
|
||||
);
|
||||
notification.url = url;
|
||||
notification.domain = domain;
|
||||
notification.callingStackMsg = callingStackMsg;
|
||||
}
|
||||
}
|
||||
};
|
@ -1,89 +1,78 @@
|
||||
/* global console,exports */
|
||||
/* jslint moz: true */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function getDomainRegExpList(domainList){
|
||||
const lists = require("./lists");
|
||||
const preferences = require("sdk/simple-prefs");
|
||||
const prefs = preferences.prefs;
|
||||
|
||||
// Translation
|
||||
var translate = require("sdk/l10n").get;
|
||||
var _ = function(name, replace){
|
||||
"use strict";
|
||||
|
||||
var list = domainList
|
||||
.split(",")
|
||||
.map(function(entry){
|
||||
return entry.replace(/^\s+|\s+$/g, "");
|
||||
})
|
||||
.filter(function(entry){
|
||||
return !!entry.length;
|
||||
})
|
||||
.map(function(entry){
|
||||
var regExp;
|
||||
var domain = !!entry.match(/^[\w.]+$/);
|
||||
if (domain){
|
||||
regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\\+\*\?\[\^\]\$\(\)\{\}\=\!\|\.])/g, "\\$1") + "\\.?$", "i");
|
||||
}
|
||||
else {
|
||||
regExp = new RegExp(entry, "i");
|
||||
}
|
||||
return {
|
||||
match: function(url){
|
||||
if (domain){
|
||||
return url.hostname.match(regExp);
|
||||
}
|
||||
else {
|
||||
return url.href.match(regExp);
|
||||
}
|
||||
}
|
||||
};
|
||||
var str = translate(name) || name;
|
||||
if (replace){
|
||||
// replace generic content in the transation by given parameter
|
||||
Object.keys(replace).forEach(function(name){
|
||||
str = str.replace(new RegExp("{" + name + "}", "g"), replace[name]);
|
||||
});
|
||||
|
||||
list.match = function(url){
|
||||
return this.some(function(entry){
|
||||
return entry.match(url);
|
||||
});
|
||||
};
|
||||
|
||||
return list;
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
function check(stack, url, blockMode){
|
||||
if (prefs.enableStackList && checkStack(stack)){
|
||||
return "allow";
|
||||
}
|
||||
else {
|
||||
return checkURL(url, blockMode);
|
||||
}
|
||||
}
|
||||
|
||||
function checkURL(url, blockMode, whiteList, blackList){
|
||||
function checkURL(url, blockMode){
|
||||
"use strict";
|
||||
|
||||
switch (url.protocol){
|
||||
case "about:":
|
||||
if (url.href === "about:blank"){
|
||||
break;
|
||||
}
|
||||
case "chrome:":
|
||||
return "allow";
|
||||
}
|
||||
|
||||
var mode = "block";
|
||||
switch (blockMode){
|
||||
case "blockEverything":
|
||||
mode = "block";
|
||||
break;
|
||||
case "allowOnlyWhiteList":
|
||||
if (url && whiteList.match(url)){
|
||||
mode = "unblock";
|
||||
}
|
||||
else {
|
||||
mode = "block";
|
||||
}
|
||||
break;
|
||||
case "ask":
|
||||
case "block":
|
||||
case "blockContext":
|
||||
case "blockReadout":
|
||||
case "fakeReadout":
|
||||
case "ask":
|
||||
case "askContext":
|
||||
case "askReadout":
|
||||
if (url && whiteList.match(url)){
|
||||
mode = "unblock";
|
||||
case "fake":
|
||||
case "fakeContext":
|
||||
case "fakeReadout":
|
||||
case "allow":
|
||||
case "allowContext":
|
||||
case "allowReadout":
|
||||
if (url && lists.get("white").match(url)){
|
||||
mode = "allow";
|
||||
}
|
||||
else if (url && blackList.match(url)){
|
||||
else if (url && lists.get("black").match(url)){
|
||||
mode = "block";
|
||||
}
|
||||
else {
|
||||
mode = blockMode;
|
||||
}
|
||||
break;
|
||||
case "blockOnlyBlackList":
|
||||
if (url && blackList.match(url)){
|
||||
mode = "block";
|
||||
}
|
||||
else {
|
||||
mode = "unblock";
|
||||
}
|
||||
break;
|
||||
case "allowEverything":
|
||||
mode = "unblock";
|
||||
mode = "allow";
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown blocking mode (" + blockMode + "). Default to block everything.");
|
||||
@ -91,8 +80,88 @@ function checkURL(url, blockMode, whiteList, blackList){
|
||||
return mode;
|
||||
}
|
||||
|
||||
try {
|
||||
exports.getDomainRegExpList = getDomainRegExpList;
|
||||
exports.checkURL = checkURL;
|
||||
function checkStack(stack){
|
||||
"use strict";
|
||||
|
||||
return lists.get("stack").match(stack);
|
||||
}
|
||||
catch(e){}
|
||||
|
||||
// Stack parsing
|
||||
function parseStackEntry(entry){
|
||||
"use strict";
|
||||
|
||||
var m = /@(.*):(\d*):(\d*)$/.exec(entry) || ["", entry, "--", "--"];
|
||||
return {
|
||||
url: m[1],
|
||||
line: parseInt(m[2], 10),
|
||||
column: parseInt(m[3], 10),
|
||||
raw: entry
|
||||
};
|
||||
}
|
||||
|
||||
function stackRuleMatch(stackEntry, stackRule){
|
||||
if (!stackEntry){
|
||||
return false;
|
||||
}
|
||||
if (stackEntry.url !== stackRule.url){
|
||||
return false;
|
||||
}
|
||||
if ((typeof stackRule.line) !== "undefined" && stackEntry.line !== stackRule.line){
|
||||
return false;
|
||||
}
|
||||
if ((typeof stackRule.column) !== "undefined" && stackEntry.column !== stackRule.column){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// parse calling stack
|
||||
function errorToCallingStack(error){
|
||||
"use strict";
|
||||
|
||||
var callers = error.stack.trim().split("\n");
|
||||
//console.log(callers);
|
||||
var findme = callers.shift(); // Remove us from the stack
|
||||
findme = findme.replace(/(:[0-9]+){1,2}$/, ""); // rm line & column
|
||||
// Eliminate squashed stack. stack may contain 2+ stacks, but why...
|
||||
var inDoubleStack = false;
|
||||
callers = callers.filter(function(caller){
|
||||
var doubleStackStart = caller.search(findme) !== -1;
|
||||
inDoubleStack = inDoubleStack || doubleStackStart;
|
||||
return !inDoubleStack;
|
||||
}).map(parseStackEntry);
|
||||
return {
|
||||
toString: function(){
|
||||
var msg = "";
|
||||
msg += "\n\n" + _("sourceOutput") + ": ";
|
||||
if (prefs.showCompleteCallingStack){
|
||||
msg += callers.reduce(function(stack, c){
|
||||
return stack + "\n\t" + _("stackEntryOutput", c);
|
||||
}, "");
|
||||
}
|
||||
else{
|
||||
msg += _("stackEntryOutput", callers[0]);
|
||||
}
|
||||
|
||||
return msg;
|
||||
},
|
||||
match: function(stackRule){
|
||||
if (typeof stackRule.stackPosition !== "undefined"){
|
||||
var pos = stackRule.stackPosition;
|
||||
if (pos < 0){
|
||||
pos += callers.length;
|
||||
}
|
||||
return stackRuleMatch(callers[pos], stackRule);
|
||||
}
|
||||
else {
|
||||
return callers.some(function(stackEntry){
|
||||
return stackRuleMatch(stackEntry, stackRule);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.check = check;
|
||||
exports.parseStackEntry = parseStackEntry;
|
||||
exports.errorToCallingStack = errorToCallingStack;
|
34
lib/stylePreferencePane.js
Normal file
34
lib/stylePreferencePane.js
Normal file
@ -0,0 +1,34 @@
|
||||
/* jslint moz: true */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
const { Cu } = require("chrome");
|
||||
const { on } = require("sdk/system/events");
|
||||
const self = require("sdk/self");
|
||||
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
const { loadSheet } = require("sdk/stylesheet/utils");
|
||||
AddonManager.getAddonByID(self.id, function(addon){
|
||||
on("addon-options-displayed", onAddonOptionsDisplayed, true);
|
||||
});
|
||||
|
||||
function onAddonOptionsDisplayed({ subject: doc, data }) {
|
||||
if (data === self.id) {
|
||||
loadSheet(doc.defaultView, self.data.url("options.css"));
|
||||
|
||||
// need to wait unttil the simple-prefs are inserted in the DOM
|
||||
setTimeout(function(){
|
||||
// replace empty menuitems with separators
|
||||
[].slice.call(doc.querySelectorAll("menuitem[value='']")).forEach(
|
||||
function(menuitem){
|
||||
var separator = doc.createElement("menuseparator");
|
||||
menuitem.parentNode.replaceChild(separator, menuitem);
|
||||
}
|
||||
);
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}());
|
52
locale/de-DE.json
Normal file
52
locale/de-DE.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"allowPDFCanvas_description": "Die native pdf.js verwendet <canvas> um den Inhalt von PDFs anzuzeigen. Wenn viele Nachfragedialoge erscheinen oder die PDF-Ansicht nicht funktioniert, müssen diese erlaubt werden.",
|
||||
"allowPDFCanvas_title": "<canvas> in PDFs erlauben",
|
||||
"askForInvisiblePermission": "Wollen Sie unsichtbare <canvas> erlauben?",
|
||||
"askForInvisibleReadoutPermission": "Wollen Sie das Auslesen von unsichtbaren <canvas> erlauben?",
|
||||
"askForPermission": "Wollen Sie <canvas> erlauben?",
|
||||
"askForReadoutPermission": "Wollen Sie das Auslesen von <canvas> erlauben?",
|
||||
"askForVisiblePermission": "Wollen Sie das rot umrandete <canvas> erlauben?",
|
||||
"askForVisibleReadoutPermission": "Wollen Sie das Auslesen des rot umrandeten <canvas> erlauben?",
|
||||
"askOnlyOnce_description": "Wenn der Blockiermodus des Canvas Blockers auf \"um Erlaubnis fragen\" oder \"bei Auslese-API um Erlaubnis fragen\" gesetzt ist, erscheint jedes mal ein Abfragedialog, wenn eine Seite versucht, die (Auslese-)API aufzurufen. Diese Einstellung versucht diese Abfrage nur einmal pro Seite anzuzeigen, unabhängig davon wie oft die API aufgerufen wird. Es können trotzdem mehrere Dialoge pro Seite erscheinen.",
|
||||
"askOnlyOnce_title": "Nur einmal nachfragen",
|
||||
"blackList_description": "Domänen oder URLs, die die <canvas>-API niemals verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt werden.",
|
||||
"blackList_title": "Blacklist",
|
||||
"blockMode_description": "",
|
||||
"blockMode_options.allow everything": "alles erlauben",
|
||||
"blockMode_options.allow only white list": "nur Einträge der Whitelist erlauben",
|
||||
"blockMode_options.ask for permission": "um Erlaubnis fragen",
|
||||
"blockMode_options.ask for readout API permission": "bei Auslese-API um Erlaubnis fragen",
|
||||
"blockMode_options.block everything": "alles blockieren",
|
||||
"blockMode_options.block only black list": "nur Einträge der Blacklist blockieren",
|
||||
"blockMode_options.block readout API": "Auslese-API blockieren",
|
||||
"blockMode_options.fake readout API": "Auslese-API vortäuschen",
|
||||
"blockMode_title": "Blockiermodus",
|
||||
"disableNotifications": "Benachrichtigungen deaktivieren",
|
||||
"displayCallingStack": "Aufrufestack anzeigen",
|
||||
"displayFullURL": "URL anzeigen",
|
||||
"enableStackList_description": "",
|
||||
"enableStackList_title": "Dateispezifische Whitelist verwenden",
|
||||
"fakedReadout": "Auslese vorgetäuscht auf {url}",
|
||||
"ignoreList_description": "Domänen oder URLs, bei denen keine Benachrichtigung angezeigt werden. Mehrere Einträge müssen durch ein Komma getrennt werden.",
|
||||
"ignoreList_title": "Ignorierliste",
|
||||
"ignorelistDomain": "ignoriere Domain",
|
||||
"ignorelistURL": "ignoriere URL",
|
||||
"inputIgnoreDomain": "Geben Sie die Domain ein, die ignoriert werden soll:",
|
||||
"inputWhitelistDomain": "Geben Sie die URL RegExp ein, die erlaubt werden soll:",
|
||||
"inputWhitelistURL": "Geben Sie die Domain ein, die erlaubt werden soll:",
|
||||
"settings": "Einstellungen",
|
||||
"showCallingFile_description": "",
|
||||
"showCallingFile_title": "Aufrufende Datei anzeigen",
|
||||
"showCompleteCallingStack_description": "",
|
||||
"showCompleteCallingStack_title": "Kompletten Aufrufestack anzeigen",
|
||||
"showNotifications_description": "Benachrichtigungen anzeigen, wenn der Blockiermodus auf \"Auslese-API vortäuschen\" gesetzt ist.",
|
||||
"showNotifications_title": "Benachrichtigungen anzeigen",
|
||||
"sourceOutput": "Aufrufende Datei",
|
||||
"stackEntryOutput": "{url} Zeile {line} Spalte {column}",
|
||||
"stackList_description": "JS-Dateien, die die <canvas>-API verwenden dürfen. Die Angabe muss hier im JSON-Format vorliegen. Beispiel: [{\"url\": \"http://domain/datei1.js\"}, {\"url\": \"http://domain/datei2.js\", \"line\": 1, \"column\": 4, \"stackPosition\": -3}]",
|
||||
"stackList_title": "Dateispezifische Whitelist",
|
||||
"whiteList_description": "Domänen oder URLs, die die <canvas>-API verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt werden.",
|
||||
"whiteList_title": "Whitelist",
|
||||
"whitelistDomain": "erlaube Domain",
|
||||
"whitelistURL": "erlaube URL"
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
whilteList_title= Whitelist
|
||||
whiteList_description= Domänen oder URLs, die die <canvas>-API verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt weren.
|
||||
|
||||
blackList_title= Blacklist
|
||||
blackList_description= Domänen oder URLs, die die <canvas>-API niemals verwenden dürfen. Mehrere Einträge müssen durch ein Komma getrennt weren.
|
||||
|
||||
ignoreList_title= Ignorierliste
|
||||
ignoreList_description= Domänen oder URLs, bei denen keine Benachrichtgung angezeigt werden. Mehrere Einträge müssen durch ein Komma getrennt weren.
|
||||
|
||||
blockMode_title= Blockiermodus
|
||||
blockMode_description=
|
||||
|
||||
blockMode_options.block everything= alles blockieren
|
||||
blockMode_options.allow only white list= nur Einträge der Whitelist erlauben
|
||||
blockMode_options.ask for permission= um Erlaubnis fragen
|
||||
blockMode_options.block readout API= Auslese-API blockieren
|
||||
blockMode_options.fake readout API= Auslese-API vortäuschen
|
||||
blockMode_options.ask for readout API permission= bei Auslese-API um Erlaubnis fragen
|
||||
blockMode_options.block only black list= nur Einträge der Blacklist blockieren
|
||||
blockMode_options.allow everything= alles erlauben
|
||||
|
||||
askOnlyOnce_title= Nur einmal nachfragen
|
||||
askOnlyOnce_description= Wenn eine Seite öfters versucht, die <canvas>-API abzurufen, erscheint jedes mal eine Nachfrage. Mit diesem Schalter wird pro Seitenbesuch nur einmal nachgefragt. Bei manchen Seiten kann es trotzdem zu mehrmaligem Nachfragen kommen.
|
||||
|
||||
showCallingFile_title= Aufrufende Datei anzeigen
|
||||
showCallingFile_description=
|
||||
|
||||
showCompleteCallingStack_title= Kompletten Aufrufestack anzeigen
|
||||
showCompleteCallingStack_description=
|
||||
|
||||
allowPDFCanvas_title= <canvas> in PDFs erlauben
|
||||
allowPDFCanvas_description= Die native pdf.js verwendet <canvas> um den Inhalt von PDFs anzuzeigen. Wenn dies nicht markiert ist, werden viele Nachfragedialoge erscheinen oder die PDF Ansicht nicht funktionieren.
|
||||
|
||||
askForPermission= Wollen Sie <canvas> erlauben?
|
||||
askForVisiblePermission= Wollen Sie das rot umrandete <canvas> erlauben?
|
||||
askForInvisiblePermission= Wollen Sie unsichtbare <canvas> erlauben?
|
||||
askForReadoutPermission= Wollen Sie das Auslesen von <canvas> erlauben?
|
||||
askForVisibleReadoutPermission= Wollen Sie das Auslesen des rot umrandeten <canvas> erlauben?
|
||||
askForInvisibleReadoutPermission= Wollen Sie das Auslesen von unsichtbaren <canvas> erlauben?
|
||||
|
||||
sourceOutput= Aufrufende Datei
|
||||
stackEntryOutput= {url} Zeile {line} Spalte {column}
|
||||
|
||||
fakedReadout = Auslese vorgetäuscht auf {url}
|
||||
settings = Einstellungen
|
||||
displayCallingStack = Aufrufestack anzeigen
|
||||
whitelistURL = erlaube URL
|
||||
whitelistDomain = erlaube Domain
|
||||
|
||||
ignorelistURL = ignoriere URL
|
||||
ignorelistDomain = ignoriere Domain
|
53
locale/en-US.json
Normal file
53
locale/en-US.json
Normal file
@ -0,0 +1,53 @@
|
||||
{
|
||||
"allowPDFCanvas_description": "Firefox's native PDF reader uses the API to display PDF content. If too many ask dialogs appear or the PDF reader does not work at all, these have to be allowed.",
|
||||
"allowPDFCanvas_title": "Allow canvas in PDFs",
|
||||
"askForInvisiblePermission": "Do you want to allow invisible <canvas>?",
|
||||
"askForInvisibleReadoutPermission": "Do you want to allow invisible <canvas> readout?",
|
||||
"askForPermission": "Do you want to allow <canvas>?",
|
||||
"askForReadoutPermission": "Do you want to allow <canvas> readout?",
|
||||
"askForVisiblePermission": "Do you want to allow the red bordered <canvas>?",
|
||||
"askForVisibleReadoutPermission": "Do you want to allow the readout of the red bordered <canvas>?",
|
||||
"askOnlyOnce_description": "When Canvas Blocker's Block mode is set to 'ask permission' or 'ask permission for readout API', a confirm message will appear every time a page tries to access the API or readout API. This setting tries to display the confirm message only once for each page regardless of how many times the page tries to access the API. Nevertheless, multiple confirm messages may still be displayed on some pages.",
|
||||
"askOnlyOnce_title": "Ask only once",
|
||||
"blackList_description": "Domains or URLs where the <canvas>-API should always be blocked. To add multiple entries, separate them by commas.",
|
||||
"blackList_title": "Black list",
|
||||
"blockMode_description": "",
|
||||
"blockMode_options.allow everything": "allow everything",
|
||||
"blockMode_options.allow only white list": "allow only white list",
|
||||
"blockMode_options.ask for permission": "ask for permission",
|
||||
"blockMode_options.ask for readout API permission": "ask for readout API permission",
|
||||
"blockMode_options.block everything": "block everything",
|
||||
"blockMode_options.block only black list": "block only black list",
|
||||
"blockMode_options.block readout API": "block readout API",
|
||||
"blockMode_options.fake readout API": "fake readout API",
|
||||
"blockMode_title": "Block mode",
|
||||
"disableNotifications": "disable notifications",
|
||||
"displayCallingStack": "display calling stack",
|
||||
"displayFullURL": "display full URL",
|
||||
"enableStackList_description": "",
|
||||
"enableStackList_title": "Use file specific white list",
|
||||
"fakedReadout": "Faked readout on {url}",
|
||||
"ignoreList_description": "Domains or URLs where no notification will be shown. To add multiple entries, separate them by commas.",
|
||||
"ignoreList_title": "Ignore list",
|
||||
"ignorelistDomain": "ignore domain",
|
||||
"ignorelistURL": "ignore URL",
|
||||
"inputIgnoreDomain": "Input domain to add to ignore list:",
|
||||
"inputWhitelistDomain": "Input URL RegExp to add to white list:",
|
||||
"inputWhitelistURL": "Input domain to add to white list:",
|
||||
"settings": "settings",
|
||||
"showCallingFile_description": "",
|
||||
"showCallingFile_title": "Show calling file",
|
||||
"showCompleteCallingStack_description": "",
|
||||
"showCompleteCallingStack_title": "Display complete calling stack",
|
||||
"showNotifications_description": "Show a notification when the block mode is set to \"fake readout API\".",
|
||||
"showNotifications_title": "Show notifications",
|
||||
"sourceOutput": "Calling file",
|
||||
"stackEntryOutput": "{url} line {line} column {column}",
|
||||
"stackList_description": "JS files which are allowed to use the <canvas>-API. The input has to be in JSON format. Example: [{\"url\": \"http://domain/file1.js\"}, {\"url\": \"http://domain/file2.js\", \"line\": 1, \"column\": 4, \"stackPosition\": -3}]",
|
||||
"stackList_title": "File specific white list",
|
||||
"whilteList_title": "White list",
|
||||
"whiteList_description": "Domains or URLs where the <canvas>-API should not be blocked. To add multiple entries, separate them by commas.",
|
||||
"whitelist": "whitelist",
|
||||
"whitelistDomain": "whitelist domain",
|
||||
"whitelistURL": "whitelist URL"
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
whilteList_title= White list
|
||||
whiteList_description= Domains or URLs where the <canvas>-API should not be blocked. To add multiple entries seperate them by comma.
|
||||
|
||||
blackList_title= Black list
|
||||
blackList_description= Domains or URLs where the <canvas>-API should always be blocked. To add multiple entries seperate them by comma.
|
||||
|
||||
ignoreList_title= Ignore list
|
||||
ignoreList_description= Domains or URLs where no notifications will be shown. To add multiple entries seperate them by comma.
|
||||
|
||||
blockMode_title= Block mode
|
||||
blockMode_description=
|
||||
|
||||
blockMode_options.block everything= block everything
|
||||
blockMode_options.allow only white list= allow only white list
|
||||
blockMode_options.ask for permission= ask for permission
|
||||
blockMode_options.block readout API= block readout API
|
||||
blockMode_options.fake readout API= fake readout API
|
||||
blockMode_options.ask for readout API permission= ask for readout API permission
|
||||
blockMode_options.block only black list= block only black list
|
||||
blockMode_options.allow everything= allow everything
|
||||
|
||||
askOnlyOnce_title= Ask only once
|
||||
askOnlyOnce_description= If a page tries to access the <canvas>-API several times a confirm message will appear every time. This switch tries to make only one confirmation. Never the less on some pages there will be more.
|
||||
|
||||
showCallingFile_title= Show calling file
|
||||
showCallingFile_description=
|
||||
|
||||
showCompleteCallingStack_title= Display complete calling stack
|
||||
showCompleteCallingStack_description=
|
||||
|
||||
allowPDFCanvas_title= Allow canvas in PDFs
|
||||
allowPDFCanvas_description= The native pdf.js uses <canvas> to display the PDF content. If this is unchecked there will lots of annoying ask dialogs or the PDF display will not work.
|
||||
|
||||
askForPermission= Do you want to allow <canvas>?
|
||||
askForVisiblePermission= Do you want to allow the red bordered <canvas>?
|
||||
askForInvisiblePermission= Do you want to allow invisible <canvas>?
|
||||
askForReadoutPermission= Do you want to allow <canvas> readout?
|
||||
askForVisibleReadoutPermission= Do you want to allow the readout of the red bordered <canvas>?
|
||||
askForInvisibleReadoutPermission= Do you want to allow invisible <canvas> readout?
|
||||
|
||||
sourceOutput= Calling file
|
||||
stackEntryOutput= {url} line {line} column {column}
|
||||
|
||||
fakedReadout = Faked readout on {url}
|
||||
settings = settings
|
||||
displayCallingStack = display calling stack
|
||||
whitelist = whitelist
|
||||
whitelistURL = whitelist URL
|
||||
whitelistDomain = whitelist domain
|
||||
|
||||
ignorelistURL = ignore URL
|
||||
ignorelistDomain = ignore domain
|
1
locales.json
Normal file
1
locales.json
Normal file
@ -0,0 +1 @@
|
||||
{"locales": ["de-DE", "en-US"]}
|
68
package.json
68
package.json
@ -2,7 +2,9 @@
|
||||
"name": "canvasblocker",
|
||||
"title": "CanvasBlocker",
|
||||
"id": "CanvasBlocker@kkapsner.de",
|
||||
"description": "Blocks the JS-API for modifying <canvas> to prevent Canvas-Fingerprinting.",
|
||||
"keywords": "privacy, canvas, fingerprinting",
|
||||
"description": "Changes the JS-API for modifying <canvas> to prevent Canvas-Fingerprinting.",
|
||||
"homepage": "https://github.com/kkapsner/CanvasBlocker/",
|
||||
"preferences": [
|
||||
{
|
||||
"name": "whiteList",
|
||||
@ -16,30 +18,12 @@
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "ignoreList",
|
||||
"title": "Ignore list",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "blockMode",
|
||||
"title": "block mode",
|
||||
"type": "menulist",
|
||||
"value": "fakeReadout",
|
||||
"options": [
|
||||
{
|
||||
"value": "blockEverything",
|
||||
"label": "block everything"
|
||||
},
|
||||
{
|
||||
"value": "allowOnlyWhiteList",
|
||||
"label": "allow only white list"
|
||||
},
|
||||
{
|
||||
"value": "ask",
|
||||
"label": "ask for permission"
|
||||
},
|
||||
{
|
||||
"value": "blockReadout",
|
||||
"label": "block readout API"
|
||||
@ -53,7 +37,23 @@
|
||||
"label": "ask for readout API permission"
|
||||
},
|
||||
{
|
||||
"value": "blockOnlyBlackList",
|
||||
"value": "",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"value": "blockEverything",
|
||||
"label": "block everything"
|
||||
},
|
||||
{
|
||||
"value": "block",
|
||||
"label": "allow only white list"
|
||||
},
|
||||
{
|
||||
"value": "ask",
|
||||
"label": "ask for permission"
|
||||
},
|
||||
{
|
||||
"value": "allow",
|
||||
"label": "block only black list"
|
||||
},
|
||||
{
|
||||
@ -68,6 +68,18 @@
|
||||
"type": "bool",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "showNotifications",
|
||||
"title": "Show notifications",
|
||||
"type": "bool",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "ignoreList",
|
||||
"title": "Ignore list",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "showCallingFile",
|
||||
"title": "Display calling file",
|
||||
@ -79,16 +91,22 @@
|
||||
"title": "Display complete calling stack",
|
||||
"type": "bool",
|
||||
"value": false
|
||||
},{
|
||||
"name": "enableStackList",
|
||||
"title": "Use file specific scoped white list",
|
||||
"type": "bool",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "allowPDFCanvas",
|
||||
"title": "Allow canvas in PDFs",
|
||||
"type": "bool",
|
||||
"value": true
|
||||
"name": "stackList",
|
||||
"title": "File specific white list",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"main": "lib/main.js",
|
||||
"author": "Korbinian Kapsner",
|
||||
"license": "MPL 2.0",
|
||||
"version": "0.1.6-Development",
|
||||
"version": "0.2.3-Development",
|
||||
"permissions": {"private-browsing": true}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user