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:
parent
4c2596f880
commit
b2f6aee8f9
Binary file not shown.
197
data/inject.js
197
data/inject.js
@ -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
|
||||||
}());
|
}());
|
||||||
|
41
lib/main.js
41
lib/main.js
@ -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"));
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
12
package.json
12
package.json
@ -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}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user