1
0
Fork 0
mirror of https://github.com/kkapsner/CanvasBlocker synced 2025-07-04 12:36:37 +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

View file

@ -2,215 +2,94 @@
(function(){
"use strict";
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 blockMode = {
getContext: {
status: "block",
askStatus: {
askOnce: false,
alreadyAsked: false,
answer: null
}
},
readAPI: {
status: "allow"
}
};
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){
if (document.contentType.match(/\/pdf$/i)){
self.port.emit("isPDF", blocking);
return true;
}
return false;
}
function block(force){
if (force || !checkPDF("block")){
setAPIFunctions(null, null, null);
}
}
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);
var undef;
var originalGetContext = unsafeWindow.HTMLCanvasElement.prototype.getContext;
Object.defineProperty(
unsafeWindow.HTMLCanvasElement.prototype,
"getContext",
{
enumerable: true,
configureable: 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 {
HTMLCanvasElement.prototype.getContext = null;
delete HTMLCanvasElement.prototype[askFunctionName];
return null;
// console.log("asking");
allow = window.confirm(_("askForPermission"));
status.alreadyAsked = true;
status.answer = allow;
}
}
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;
return allow? originalGetContext: undef;
case "block":
default:
// console.log("block");
return undef;
}
);
}, unsafeWindow)
}
}
function unblock(){
setAPIFunctions(true, true, true);
}
);
var originalToDataURL = unsafeWindow.HTMLCanvasElement.prototype.toDataURL;
Object.defineProperty(
unsafeWindow.HTMLCanvasElement.prototype,
"toDataURL",
{
enumerable: true,
configureable: false,
get: exportFunction(function(){
switch (blockMode.readAPI.status){
case "allow":
return originalToDataURL;
case "block":
default:
return undef;
}
}, unsafeWindow)
}
);
var originalGetImageData = unsafeWindow.CanvasRenderingContext2D.prototype.getImageData;
Object.defineProperty(
unsafeWindow.CanvasRenderingContext2D.prototype,
"getImageData",
{
enumerable: true,
configureable: false,
get: exportFunction(function(){
switch (blockMode.readAPI.status){
case "allow":
return originalGetImageData;
case "block":
default:
return undef;
}
}, unsafeWindow)
}
);
var _ = function(name){
return _[name] || name;
@ -218,12 +97,40 @@
self.port.on("setTranslation", function(name, translation){
_[name] = translation;
});
block();
self.port.on("block", block);
self.port.on("askVisible", askVisible);
self.port.on("askInvisible", askInvisible);
self.port.on("blockReadout", blockReadout);
self.port.on("unblock", unblock);
//self.port.on("detach", unblock); // produces memory leak due to the reference to unsafeWindow
function checkPDF(blocking){
if (document.contentType.match(/\/pdf$/i)){
self.port.emit("isPDF", blocking);
return true;
}
return false;
}
self.port.on("block", function(force){
if (force || !checkPDF("block")){
blockMode.getContext.status = "block";
blockMode.readAPI.status = "allow";
}
});
self.port.on("ask", function(force, askOnce){
if (force || !checkPDF("askVisible")){
blockMode.getContext.status = "ask";
blockMode.getContext.askStatus.askOnce = askOnce;
blockMode.readAPI.status = "allow";
}
});
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";
});
}());