1
0
mirror of https://github.com/kkapsner/CanvasBlocker synced 2025-05-25 09:13:27 +02:00

Changed to getter approach

- no "visible vs. invisible" possible
This commit is contained in:
kkapsner 2014-10-09 00:26:36 +02:00
parent b2f6aee8f9
commit 147a2893c4
6 changed files with 196 additions and 309 deletions

Binary file not shown.

View File

@ -2,77 +2,101 @@
(function(){ (function(){
"use strict"; "use strict";
var originalGetContext = unsafeWindow.HTMLCanvasElement.prototype.getContext; var blockMode = {
var originalToDataURL = unsafeWindow.HTMLCanvasElement.prototype.toDataURL; getContext: {
var originalGetImageData = unsafeWindow.CanvasRenderingContext2D.prototype.getImageData; status: "block",
var askFunctionName = Math.random().toString(16); askStatus: {
askOnce: false,
alreadyAsked: false,
answer: null
}
},
readAPI: {
status: "allow"
}
};
function transformFunctionToUnsafeWindow(func, name){ var undef;
var funcString = func.toString(); var originalGetContext = unsafeWindow.HTMLCanvasElement.prototype.getContext;
var parameter = funcString.match(/^function\s*\(([^\)]*)\)\s*\{/)[1];
funcString = funcString
.replace(/^function\s*\(([^\)]*)\)\s*\{|\}\s*$/g, "")
.replace(/(^|\n|\r)\t{3}/g, "$1")
.replace(/askFunctionName/g, JSON.stringify(askFunctionName))
.replace(/askForPermission/g, _("askForPermission"))
.replace(/askForInvisiblePermission/g, _("askForInvisiblePermission"));
var unsafeFunction = new unsafeWindow.Function(parameter, funcString);
unsafeFunction.toString =
unsafeFunction.toLocaleString =
unsafeFunction.toSource = new unsafeWindow.Function(
"return \"function " + name + "() {\\n [native code]\\n}\";"
);
return unsafeFunction;
}
function setAPIFunctions(getContext, toDataURL, getImageData){
delete unsafeWindow.HTMLCanvasElement.prototype[askFunctionName];
if (getContext){
if (getContext === true){
getContext = originalGetContext;
}
else {
var secretObject = new unsafeWindow.Object();
Object.defineProperties(
secretObject,
{
getContext: {value: originalGetContext},
confirm: {value: unsafeWindow.confirm}
}
);
Object.defineProperty( Object.defineProperty(
unsafeWindow.HTMLCanvasElement.prototype, unsafeWindow.HTMLCanvasElement.prototype,
askFunctionName, "getContext",
{ {
value: secretObject, enumerable: true,
configurable: true, configureable: false,
enumerable: false get: exportFunction(function(){
switch (blockMode.getContext.status){
case "allow":
// console.log("allow");
return originalGetContext;
case "ask":
// console.log("ask");
var status = blockMode.getContext.askStatus;
var allow;
if (status.askOnce && status.alreadyAsked){
// console.log("already asked");
allow = status.answer;
}
else {
// console.log("asking");
allow = window.confirm(_("askForPermission"));
status.alreadyAsked = true;
status.answer = allow;
}
return allow? originalGetContext: undef;
case "block":
default:
// console.log("block");
return undef;
}
}, unsafeWindow)
} }
); );
getContext = transformFunctionToUnsafeWindow(getContext, "getContext");
}
}
unsafeWindow.HTMLCanvasElement.prototype.getContext = getContext;
if (toDataURL){ var originalToDataURL = unsafeWindow.HTMLCanvasElement.prototype.toDataURL;
if (toDataURL === true){ Object.defineProperty(
toDataURL = originalToDataURL; unsafeWindow.HTMLCanvasElement.prototype,
"toDataURL",
{
enumerable: true,
configureable: false,
get: exportFunction(function(){
switch (blockMode.readAPI.status){
case "allow":
return originalToDataURL;
case "block":
default:
return undef;
} }
else { }, unsafeWindow)
toDataURL = transformFunctionToUnsafeWindow(toDataURL, "toDataURL");
} }
} );
unsafeWindow.HTMLCanvasElement.prototype.toDataURL = toDataURL;
if (getImageData){ var originalGetImageData = unsafeWindow.CanvasRenderingContext2D.prototype.getImageData;
if (getImageData === true){ Object.defineProperty(
getImageData = originalGetImageData; unsafeWindow.CanvasRenderingContext2D.prototype,
"getImageData",
{
enumerable: true,
configureable: false,
get: exportFunction(function(){
switch (blockMode.readAPI.status){
case "allow":
return originalGetImageData;
case "block":
default:
return undef;
} }
else { }, unsafeWindow)
getImageData = transformFunctionToUnsafeWindow(getImageData, "getImageData");
}
}
unsafeWindow.CanvasRenderingContext2D.prototype.getImageData = getImageData;
} }
);
var _ = function(name){
return _[name] || name;
};
self.port.on("setTranslation", function(name, translation){
_[name] = translation;
});
function checkPDF(blocking){ function checkPDF(blocking){
if (document.contentType.match(/\/pdf$/i)){ if (document.contentType.match(/\/pdf$/i)){
@ -82,148 +106,31 @@
return false; return false;
} }
function block(force){ self.port.on("block", function(force){
if (force || !checkPDF("block")){ if (force || !checkPDF("block")){
setAPIFunctions(null, null, null); blockMode.getContext.status = "block";
blockMode.readAPI.status = "allow";
} }
}
function askVisible(force, askOnlyOnce){
if (force || !checkPDF("askVisible")){
setAPIFunctions(
askOnlyOnce?
function(){
if (this.parentNode){
var oldBorder = this.style.border;
this.style.border = "2px dashed red";
var confirmText = "askForPermission";
// try {throw new Error();}
// catch (e){
// console.log(e.stack.split(/\s*(?:-?>|@)\s*/));
// }
var allow = this[askFunctionName].confirm.call(window, confirmText);
this.style.border = oldBorder;
if (allow){
HTMLCanvasElement.prototype.getContext = this[askFunctionName].getContext;
delete HTMLCanvasElement.prototype[askFunctionName];
return this.getContext.apply(this, arguments);
}
else {
HTMLCanvasElement.prototype.getContext = null;
delete HTMLCanvasElement.prototype[askFunctionName];
return null;
}
}
else {
return null;
}
}:
function(){
if (this.parentNode){
var oldBorder = this.style.border;
this.style.border = "2px dashed red";
var confirmText = "askForPermission";
// try {throw new Error();}
// catch (e){
// console.log(e.stack.split(/\s*(?:-?>|@)\s*/));
// }
var allow = this[askFunctionName].confirm.call(window, confirmText);
this.style.border = oldBorder;
if (allow){
this.getContext = this[askFunctionName].getContext;
return this.getContext.apply(this, arguments);
}
else {
this.getContext = null;
return null;
}
}
else {
return null;
}
},
true,
true
);
}
}
function askInvisible(force, askOnlyOnce){
if (force || !checkPDF("askInvisible")){
setAPIFunctions(
askOnlyOnce?
function(){
var oldBorder = this.style.border;
this.style.border = "2px dashed red";
var confirmText =
this.parentNode?
"askForPermission":
"askForInvisiblePermission";
var allow = this[askFunctionName].confirm.call(window, confirmText);
this.style.border = oldBorder;
if (allow){
HTMLCanvasElement.prototype.getContext = this[askFunctionName].getContext;
delete HTMLCanvasElement.prototype[askFunctionName];
return this.getContext.apply(this, arguments);
}
else {
HTMLCanvasElement.prototype.getContext = null;
delete HTMLCanvasElement.prototype[askFunctionName];
return null;
}
}:
function(){
var oldBorder = this.style.border;
this.style.border = "2px dashed red";
var confirmText =
this.parentNode?
"askForPermission":
"askForInvisiblePermission";
var allow = this[askFunctionName].confirm.call(window, confirmText);
this.style.border = oldBorder;
if (allow){
this.getContext = this[askFunctionName].getContext;
return this.getContext.apply(this, arguments);
}
else {
this.getContext = null;
return null;
}
},
true,
true
);
}
}
function blockReadout(force){
if (force || !checkPDF("blockReadout")){
setAPIFunctions(
true,
function(){
return "data:image/png;base64";
},
function(sx, sy, sw, sh){
var imageData = this.createImageData(sw, sh);
return imageData;
}
);
}
}
function unblock(){
setAPIFunctions(true, true, true);
}
var _ = function(name){
return _[name] || name;
};
self.port.on("setTranslation", function(name, translation){
_[name] = translation;
}); });
self.port.on("ask", function(force, askOnce){
block(); if (force || !checkPDF("askVisible")){
self.port.on("block", block); blockMode.getContext.status = "ask";
self.port.on("askVisible", askVisible); blockMode.getContext.askStatus.askOnce = askOnce;
self.port.on("askInvisible", askInvisible); blockMode.readAPI.status = "allow";
self.port.on("blockReadout", blockReadout); }
self.port.on("unblock", unblock); });
//self.port.on("detach", unblock); // produces memory leak due to the reference to unsafeWindow self.port.on("blockReadout", function(force){
if (force || !checkPDF("blockReadout")){
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "block";
}
});
self.port.on("unblock", function(){
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "allow";
});
self.port.on("detach", function(force){
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "allow";
});
}()); }());

View File

@ -42,12 +42,18 @@
var self = require("sdk/self"); var self = require("sdk/self");
var pageMod = require("sdk/page-mod"); var pageMod = require("sdk/page-mod");
var array = require("sdk/util/array");
var preferences = require("sdk/simple-prefs"); var preferences = require("sdk/simple-prefs");
var prefs = preferences.prefs; var prefs = preferences.prefs;
var {URL} = require("sdk/url"); var {URL} = require("sdk/url");
var _ = require("sdk/l10n").get; var _ = require("sdk/l10n").get;
// preferences // preferences
Object.keys(prefs).forEach(function(pref){
preferences.on(pref, function(){
workers.forEach(checkWorker);
});
});
var whiteList; var whiteList;
function updateWhiteList(){ function updateWhiteList(){
whiteList = getDomainRegExpList(prefs.whiteList); whiteList = getDomainRegExpList(prefs.whiteList);
@ -55,7 +61,6 @@
updateWhiteList(); updateWhiteList();
preferences.on("whiteList", function(){ preferences.on("whiteList", function(){
updateWhiteList(); updateWhiteList();
// workers.forEach(checkWorker);
}); });
var blackList; var blackList;
@ -65,25 +70,10 @@
updateBlackList(); updateBlackList();
preferences.on("blackList", function(){ preferences.on("blackList", function(){
updateBlackList(); updateBlackList();
// workers.forEach(checkWorker);
}); });
// preferences.on("blockMode", function(){
// workers.forEach(checkWorker);
// });
// preferences.on("allowPDFCanvas", function(){
// workers.forEach(checkWorker);
// });
// var workers = [];
// function detachWorker(worker, workerArray) {
// var index = workerArray.indexOf(worker);
// if (index !== -1){
// workerArray.splice(index, 1);
// }
// }
function checkWorker(worker){ function checkWorker(worker){
try {
var url = new URL(worker.url); var url = new URL(worker.url);
var mode = "block"; var mode = "block";
switch (prefs.blockMode){ switch (prefs.blockMode){
@ -98,7 +88,7 @@
mode = "block"; mode = "block";
} }
break; break;
case "askVisible": case "ask":
if (whiteList.match(url)){ if (whiteList.match(url)){
mode = "unblock"; mode = "unblock";
} }
@ -106,18 +96,7 @@
mode = "block"; mode = "block";
} }
else { else {
mode = "askVisible"; mode = "ask";
}
break;
case "askInvisible":
if (whiteList.match(url)){
mode = "unblock";
}
else if (blackList.match(url)){
mode = "block";
}
else {
mode = "askInvisible";
} }
break; break;
case "blockReadout": case "blockReadout":
@ -147,18 +126,28 @@
} }
worker.port.emit(mode, false, prefs.askOnlyOnce); worker.port.emit(mode, false, prefs.askOnlyOnce);
} }
catch (e){
console.log("Error updating " + worker.url + ": " + e.message);
}
}
var workers = [];
pageMod.PageMod({ pageMod.PageMod({
include: "*", include: "*",
contentScriptWhen: "start", contentScriptWhen: "start",
contentScriptFile: self.data.url("inject.js"), contentScriptFile: self.data.url("inject.js"),
onAttach: function(worker){ onAttach: function(worker){
// workers.push(worker); array.add(workers, worker);
// worker.on("detach", function(){ worker.on("pageshow", function(){
// detachWorker(this, workers); array.add(workers, this);
// }); });
worker.on("pagehide", function(){
array.remove(workers, this);
});
worker.on("detach", function(){
array.remove(workers, this);
});
worker.port.on("isPDF", function(blocking){ worker.port.on("isPDF", function(blocking){
if (prefs.allowPDFCanvas){ if (prefs.allowPDFCanvas){
this.emit("unblock"); this.emit("unblock");
@ -168,7 +157,6 @@
} }
}); });
worker.port.emit("setTranslation", "askForPermission", _("askForPermission")); worker.port.emit("setTranslation", "askForPermission", _("askForPermission"));
worker.port.emit("setTranslation", "askForInvisiblePermission", _("askForInvisiblePermission"));
checkWorker(worker); checkWorker(worker);
}, },
}); });

View File

@ -9,8 +9,7 @@ blockMode_description=
blockMode_options.block everything= alles blockieren blockMode_options.block everything= alles blockieren
blockMode_options.allow only white list= nur Einträge der Whitelist erlauben blockMode_options.allow only white list= nur Einträge der Whitelist erlauben
blockMode_options.ask for permission for visible <canvas>= bei sichtbaren <canvas> um Erlaubnis fragen blockMode_options.ask for permission= um Erlaubnis fragen
blockMode_options.ask for permision for invisible <canvas>= bei unsichtbaren <canvas> um Erlaubnis fragen
blockMode_options.block readout API= Auslese-API blockieren blockMode_options.block readout API= Auslese-API blockieren
blockMode_options.block only black list= nur Einträge der Blacklist blockieren blockMode_options.block only black list= nur Einträge der Blacklist blockieren
blockMode_options.allow everything= alles erlauben blockMode_options.allow everything= alles erlauben
@ -21,5 +20,4 @@ askOnlyOnce_description= Wenn eine Seite öfters versucht, die <canvas>-API abzu
allowPDFCanvas_title= <canvas> in PDFs erlauben 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. 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 das rot umrandete <canvas> erlauben? askForPermission= Wollen Sie <canvas> erlauben?
askForInvisiblePermission= Wollen Sie ein verstecktes <canvas> erlauben?

View File

@ -9,8 +9,7 @@ blockMode_description=
blockMode_options.block everything= block everything blockMode_options.block everything= block everything
blockMode_options.allow only white list= allow only white list blockMode_options.allow only white list= allow only white list
blockMode_options.ask for permission for visible <canvas>= ask for permission for visible <canvas> blockMode_options.ask for permission= ask for permission
blockMode_options.ask for permision for invisible <canvas>= ask for permision for invisible <canvas>
blockMode_options.block readout API= block readout API blockMode_options.block readout API= block readout API
blockMode_options.block only black list= block only black list blockMode_options.block only black list= block only black list
blockMode_options.allow everything= allow everything blockMode_options.allow everything= allow everything
@ -21,5 +20,4 @@ askOnlyOnce_description= If a page tries to access the <canvas>-API several time
allowPDFCanvas_title= Allow canvas in PDFs 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. 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 the red bordered <canvas>? askForPermission= Do you want to allow <canvas>?
askForInvisiblePermission= Do you want to allow an invisibe <canvas>?

View File

@ -20,7 +20,7 @@
"name": "blockMode", "name": "blockMode",
"title": "block mode", "title": "block mode",
"type": "menulist", "type": "menulist",
"value": "askVisible", "value": "ask",
"options": [ "options": [
{ {
"value": "blockEverything", "value": "blockEverything",
@ -31,12 +31,8 @@
"label": "allow only white list" "label": "allow only white list"
}, },
{ {
"value": "askVisible", "value": "ask",
"label": "ask for permission for visible <canvas>" "label": "ask for permission"
},
{
"value": "askInvisible",
"label": "ask for permision for invisible <canvas>"
}, },
{ {
"value": "blockReadout", "value": "blockReadout",
@ -56,7 +52,7 @@
"name": "askOnlyOnce", "name": "askOnlyOnce",
"title": "Ask only once", "title": "Ask only once",
"type": "bool", "type": "bool",
"value": false "value": true
}, },
{ {
"name": "allowPDFCanvas", "name": "allowPDFCanvas",