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

Added askOnlyOnce and blockReadout and major code changes

This commit is contained in:
kkapsner 2014-10-08 03:16:23 +02:00
parent 4c2596f880
commit b2f6aee8f9
6 changed files with 199 additions and 59 deletions

Binary file not shown.

View File

@ -1,9 +1,79 @@
/* global self, window, console, unsafeWindow */
(function(){ (function(){
"use strict"; "use strict";
var getContext = unsafeWindow.HTMLCanvasElement.prototype.getContext; var originalGetContext = unsafeWindow.HTMLCanvasElement.prototype.getContext;
var originalToDataURL = unsafeWindow.HTMLCanvasElement.prototype.toDataURL;
var originalGetImageData = unsafeWindow.CanvasRenderingContext2D.prototype.getImageData;
var askFunctionName = Math.random().toString(16); var askFunctionName = Math.random().toString(16);
function transformFunctionToUnsafeWindow(func, name){
var funcString = func.toString();
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(
unsafeWindow.HTMLCanvasElement.prototype,
askFunctionName,
{
value: secretObject,
configurable: true,
enumerable: false
}
);
getContext = transformFunctionToUnsafeWindow(getContext, "getContext");
}
}
unsafeWindow.HTMLCanvasElement.prototype.getContext = getContext;
if (toDataURL){
if (toDataURL === true){
toDataURL = originalToDataURL;
}
else {
toDataURL = transformFunctionToUnsafeWindow(toDataURL, "toDataURL");
}
}
unsafeWindow.HTMLCanvasElement.prototype.toDataURL = toDataURL;
if (getImageData){
if (getImageData === true){
getImageData = originalGetImageData;
}
else {
getImageData = transformFunctionToUnsafeWindow(getImageData, "getImageData");
}
}
unsafeWindow.CanvasRenderingContext2D.prototype.getImageData = getImageData;
}
function checkPDF(blocking){ function checkPDF(blocking){
if (document.contentType.match(/\/pdf$/i)){ if (document.contentType.match(/\/pdf$/i)){
self.port.emit("isPDF", blocking); self.port.emit("isPDF", blocking);
@ -14,24 +84,14 @@
function block(force){ function block(force){
if (force || !checkPDF("block")){ if (force || !checkPDF("block")){
// consoe.log("block"); setAPIFunctions(null, null, null);
delete unsafeWindow.HTMLCanvasElement.prototype[askFunctionName];
unsafeWindow.HTMLCanvasElement.prototype.getContext = null;
} }
} }
function askVisible(force){ function askVisible(force, askOnlyOnce){
if (force || !checkPDF("askVisible")){ if (force || !checkPDF("askVisible")){
setAPIFunctions(
Object.defineProperty( askOnlyOnce?
unsafeWindow.HTMLCanvasElement.prototype,
askFunctionName,
{
value: getContext,
enumerable: false
}
);
unsafeWindow.HTMLCanvasElement.prototype.getContext = new unsafeWindow.Function(
function(){ function(){
if (this.parentNode){ if (this.parentNode){
var oldBorder = this.style.border; var oldBorder = this.style.border;
@ -41,11 +101,37 @@
// catch (e){ // catch (e){
// console.log(e.stack.split(/\s*(?:-?>|@)\s*/)); // console.log(e.stack.split(/\s*(?:-?>|@)\s*/));
// } // }
var allow = confirm(confirmText); var allow = this[askFunctionName].confirm.call(window, confirmText);
this.style.border = oldBorder; this.style.border = oldBorder;
if (allow){ if (allow){
this.getContext = this["askFunctionName"]; HTMLCanvasElement.prototype.getContext = this[askFunctionName].getContext;
return this["askFunctionName"].apply(this, arguments); 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 { else {
this.getContext = null; this.getContext = null;
@ -55,25 +141,16 @@
else { else {
return null; return null;
} }
}.toString() },
.replace(/^function\s*\(\)\s*\{|\}\s*$/g, "") true,
.replace(/askFunctionName/g, askFunctionName) true
.replace(/askForPermission/g, _("askForPermission"))
); );
} }
} }
function askInvisible(force){ function askInvisible(force, askOnlyOnce){
if (force || !checkPDF("askInvisible")){ if (force || !checkPDF("askInvisible")){
setAPIFunctions(
Object.defineProperty( askOnlyOnce?
unsafeWindow.HTMLCanvasElement.prototype,
askFunctionName,
{
value: getContext,
enumerable: false
}
);
unsafeWindow.HTMLCanvasElement.prototype.getContext = new unsafeWindow.Function(
function(){ function(){
var oldBorder = this.style.border; var oldBorder = this.style.border;
this.style.border = "2px dashed red"; this.style.border = "2px dashed red";
@ -81,32 +158,63 @@
this.parentNode? this.parentNode?
"askForPermission": "askForPermission":
"askForInvisiblePermission"; "askForInvisiblePermission";
var allow = confirm(confirmText); var allow = this[askFunctionName].confirm.call(window, confirmText);
this.style.border = oldBorder; this.style.border = oldBorder;
if (allow){ if (allow){
this.getContext = this["askFunctionName"]; HTMLCanvasElement.prototype.getContext = this[askFunctionName].getContext;
return this["askFunctionName"].apply(this, arguments); 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 { else {
this.getContext = null; this.getContext = null;
return null; return null;
} }
}.toString() },
.replace(/^function\s*\(\)\s*\{|\}\s*$/g, "") true,
.replace(/askFunctionName/g, askFunctionName) true
.replace(/askForPermission/g, _("askForPermission")) );
.replace(/askForInvisiblePermission/g, _("askForInvisiblePermission")) }
}
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(){ function unblock(){
// console.log("unblock"); setAPIFunctions(true, true, true);
unsafeWindow.HTMLCanvasElement.prototype.getContext = getContext;
} }
var _ = function(name){ var _ = function(name){
return _[name] || name; return _[name] || name;
} };
self.port.on("setTranslation", function(name, translation){ self.port.on("setTranslation", function(name, translation){
_[name] = translation; _[name] = translation;
}); });
@ -115,6 +223,7 @@
self.port.on("block", block); self.port.on("block", block);
self.port.on("askVisible", askVisible); self.port.on("askVisible", askVisible);
self.port.on("askInvisible", askInvisible); self.port.on("askInvisible", askInvisible);
self.port.on("blockReadout", blockReadout);
self.port.on("unblock", unblock); self.port.on("unblock", unblock);
//self.port.on("detach", unblock); // produces memory leak due to the reference to unsafeWindow //self.port.on("detach", unblock); // produces memory leak due to the reference to unsafeWindow
}()); }());

View File

@ -85,54 +85,67 @@
// } // }
function checkWorker(worker){ function checkWorker(worker){
var url = new URL(worker.url); var url = new URL(worker.url);
var mode = "block";
switch (prefs.blockMode){ switch (prefs.blockMode){
case "blockEverything": case "blockEverything":
worker.port.emit("block"); mode = "block";
break; break;
case "allowOnlyWhiteList": case "allowOnlyWhiteList":
if (whiteList.match(url)){ if (whiteList.match(url)){
worker.port.emit("unblock"); mode = "unblock";
} }
else { else {
worker.port.emit("block"); mode = "block";
} }
break; break;
case "askVisible": case "askVisible":
if (whiteList.match(url)){ if (whiteList.match(url)){
worker.port.emit("unblock"); mode = "unblock";
} }
else if (blackList.match(url)){ else if (blackList.match(url)){
worker.port.emit("block"); mode = "block";
} }
else { else {
worker.port.emit("askVisible"); mode = "askVisible";
} }
break; break;
case "askInvisible": case "askInvisible":
if (whiteList.match(url)){ if (whiteList.match(url)){
worker.port.emit("unblock"); mode = "unblock";
} }
else if (blackList.match(url)){ else if (blackList.match(url)){
worker.port.emit("block"); mode = "block";
} }
else { else {
worker.port.emit("askInvisible"); mode = "askInvisible";
}
break;
case "blockReadout":
if (whiteList.match(url)){
mode = "unblock";
}
else if (blackList.match(url)){
mode = "block";
}
else {
mode = "blockReadout";
} }
break; break;
case "blockOnlyBlackList": case "blockOnlyBlackList":
if (blackList.match(url)){ if (blackList.match(url)){
worker.port.emit("block"); mode = "block";
} }
else { else {
worker.port.emit("unblock"); mode = "unblock";
} }
break; break;
case "allowEverything": case "allowEverything":
worker.port.emit("unblock"); mode = "unblock";
break; break;
default: default:
console.log("Unknown blocking mode."); console.log("Unknown blocking mode. Default to block everything.");
} }
worker.port.emit(mode, false, prefs.askOnlyOnce);
} }
@ -151,7 +164,7 @@
this.emit("unblock"); this.emit("unblock");
} }
else { else {
this.emit(blocking, true); this.emit(blocking, true, prefs.askOnlyOnce);
} }
}); });
worker.port.emit("setTranslation", "askForPermission", _("askForPermission")); worker.port.emit("setTranslation", "askForPermission", _("askForPermission"));

View File

@ -11,9 +11,13 @@ 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 for visible <canvas>= bei sichtbaren <canvas> um Erlaubnis fragen
blockMode_options.ask for permision for invisible <canvas>= bei unsichtbaren <canvas> 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 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
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.
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.

View File

@ -11,9 +11,13 @@ 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 for visible <canvas>= ask for permission for visible <canvas>
blockMode_options.ask for permision for invisible <canvas>= ask for permision for invisible <canvas> 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 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
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.
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.

View File

@ -38,6 +38,10 @@
"value": "askInvisible", "value": "askInvisible",
"label": "ask for permision for invisible <canvas>" "label": "ask for permision for invisible <canvas>"
}, },
{
"value": "blockReadout",
"label": "block readout API"
},
{ {
"value": "blockOnlyBlackList", "value": "blockOnlyBlackList",
"label": "block only black list" "label": "block only black list"
@ -48,6 +52,12 @@
} }
] ]
}, },
{
"name": "askOnlyOnce",
"title": "Ask only once",
"type": "bool",
"value": false
},
{ {
"name": "allowPDFCanvas", "name": "allowPDFCanvas",
"title": "Allow canvas in PDFs", "title": "Allow canvas in PDFs",
@ -57,6 +67,6 @@
], ],
"author": "Korbinian Kapsner", "author": "Korbinian Kapsner",
"license": "MPL 2.0", "license": "MPL 2.0",
"version": "0.1.3", "version": "0.1.4",
"permissions": {"private-browsing": true} "permissions": {"private-browsing": true}
} }