1
0
mirror of https://github.com/kkapsner/CanvasBlocker synced 2024-12-23 05:10:27 +01:00
CanvasBlocker/data/inject.js

314 lines
8.3 KiB
JavaScript
Raw Normal View History

2014-12-04 23:34:41 +01:00
/* global self, window, console, unsafeWindow, exportFunction, cloneInto */
2015-01-16 13:01:01 +01:00
/* 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/. */
2014-08-20 10:21:38 +02:00
(function(){
"use strict";
2014-12-15 18:43:47 +01:00
var settings = {
showCallingFile: false
};
var blockMode = {
getContext: {
name: "getContext",
status: "block",
2014-12-04 23:34:41 +01:00
askText: {
visible: "askForVisiblePermission",
invisible: "askForInvisiblePermission",
nocanvas: "askForPermission"
},
askStatus: {
askOnce: false,
alreadyAsked: {},
answer: {}
}
},
readAPI: {
name: "readAPI",
2014-10-11 01:46:47 +02:00
status: "allow",
2014-12-04 23:34:41 +01:00
askText: {
visible: "askForVisibleReadoutPermission",
invisible: "askForInvisibleReadoutPermission",
nocanvas: "askForReadoutPermission"
},
2014-10-11 01:46:47 +02:00
askStatus: {
askOnce: false,
alreadyAsked: {},
answer: {}
2014-10-11 01:46:47 +02:00
}
}
};
var undef;
2014-10-11 01:17:49 +02:00
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;
}());
2015-04-15 12:02:21 +02:00
// 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;
}
2014-12-04 23:34:41 +01:00
// Check canvas appearance
function canvasAppearance(context){
var oldBorder = false;
var canvas = false;
var inDOM = null;
2014-12-04 23:34:41 +01:00
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);
2014-12-04 23:34:41 +01:00
}
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;
},
2014-12-04 23:34:41 +01:00
reset: function(){
if (canvas){
canvas.style.border = oldBorder;
}
}
};
}
2014-10-13 09:31:04 +02:00
// changed functions
var changedFunctions = {
getContext: {
mode: blockMode.getContext,
object: unsafeWindow.HTMLCanvasElement
},
2014-10-11 01:46:47 +02:00
toDataURL: {
2014-10-13 09:31:04 +02:00
mode: blockMode.readAPI,
2014-10-11 01:46:47 +02:00
object: unsafeWindow.HTMLCanvasElement,
2014-10-13 09:31:04 +02:00
fake: function(){
2014-10-11 01:46:47 +02:00
var type = arguments[0] || "image/png";
return "data:" + type + ";base64," + btoa(randomImage);
}
},
toBlob: {
2014-10-13 09:31:04 +02:00
mode: blockMode.readAPI,
2014-10-11 01:46:47 +02:00
object: unsafeWindow.HTMLCanvasElement,
2014-10-13 09:31:04 +02:00
fake: function(callback){
2014-10-11 01:46:47 +02:00
var type = arguments[0] || "image/png";
var blob = new window.Blob(randomImage, {type: type});
callback(blob);
},
exportOptions: {allowCallbacks: true}
},
mozGetAsFile: {
2014-10-13 09:31:04 +02:00
mode: blockMode.readAPI,
object: unsafeWindow.HTMLCanvasElement
2014-10-11 01:46:47 +02:00
},
getImageData: {
2014-10-13 09:31:04 +02:00
mode: blockMode.readAPI,
2014-10-11 01:46:47 +02:00
object: unsafeWindow.CanvasRenderingContext2D,
2014-10-13 09:31:04 +02:00
fake: function(sx, sy, sw, sh){
2014-10-11 01:46:47 +02:00
var l = sw * sh * 4;
var data = new Uint8ClampedArray(l);
2014-10-11 01:46:47 +02:00
for (var i = 0; i < l; i += 1){
data[i] = Math.floor(
2014-10-11 01:46:47 +02:00
Math.random() * 256
);
2014-10-11 01:17:49 +02:00
}
var imageData = new window.ImageData(sw, sh);
imageData.data.set(cloneInto(data, unsafeWindow));
2014-10-11 01:46:47 +02:00
return imageData;
}
},
readPixels: {
mode: blockMode.readAPI,
object: unsafeWindow.WebGLRenderingContext
2014-10-11 01:17:49 +02:00
}
2014-10-11 01:46:47 +02:00
};
2014-10-11 01:17:49 +02:00
2014-10-13 09:31:04 +02:00
Object.keys(changedFunctions).forEach(function(name){
var changedFunction = changedFunctions[name];
var original = changedFunction.object.prototype[name];
2014-10-11 01:46:47 +02:00
Object.defineProperty(
2014-10-13 09:31:04 +02:00
changedFunction.object.prototype,
2014-10-11 01:46:47 +02:00
name,
{
enumerable: true,
configureable: false,
get: exportFunction(function(){
2014-10-13 09:31:04 +02:00
var status = changedFunction.mode.status;
2015-04-15 12:02:21 +02:00
var callingStackMsg = errorToCallingStackMsg(new Error());
2014-10-11 01:46:47 +02:00
if (status === "ask"){
2014-10-13 09:31:04 +02:00
var askStatus = changedFunction.mode.askStatus;
var appearance = canvasAppearance(this);
if (askStatus.askOnce && askStatus.alreadyAsked[appearance.askCategory]){
2014-10-11 01:46:47 +02:00
// console.log("already asked");
status = askStatus.answer[appearance.askCategory];
2014-10-11 01:46:47 +02:00
}
else {
2014-12-10 15:58:26 +01:00
//console.log("asking");
2014-12-15 19:32:02 +01:00
var msg = _(changedFunction.mode.askText[appearance.text]);
2014-12-15 18:43:47 +01:00
if (settings.showCallingFile){
2015-04-15 12:02:21 +02:00
msg += callingStackMsg;
}
status = window.confirm(msg) ? "allow": "block";
askStatus.alreadyAsked[appearance.text] = true;
askStatus.answer[appearance.text] = status;
2014-12-10 15:58:26 +01:00
//console.log("asking (done)");
2014-12-04 23:34:41 +01:00
appearance.reset();
2014-10-11 01:46:47 +02:00
}
}
2015-04-15 12:02:21 +02:00
self.port.emit("accessed " + changedFunction.mode.name, status, callingStackMsg);
2014-10-11 01:46:47 +02:00
switch (status){
case "allow":
return original;
2014-10-13 01:37:13 +02:00
case "fake":
2014-10-13 09:31:04 +02:00
return changedFunction.fake? exportFunction(
changedFunction.fake,
2014-10-11 01:46:47 +02:00
unsafeWindow,
2014-10-13 09:31:04 +02:00
changedFunction.exportOptions
2014-10-13 01:37:13 +02:00
): undef;
case "block":
default:
return undef;
2014-10-11 01:46:47 +02:00
}
}, unsafeWindow)
}
);
});
2014-12-15 18:43:47 +01:00
// Stack parsing
function parseStackEntry(entry){
var m = /@(.*):(\d*):(\d*)$/.exec(entry) || ["", entry, "--", "--"];
return {
url: m[1],
line: m[2],
column: m[3],
raw: entry
};
}
2014-10-11 01:46:47 +02:00
// Translation
2014-12-15 18:43:47 +01:00
var _ = function(name, replace){
var str = _[name] || name;
if (replace){
Object.keys(replace).forEach(function(name){
str = str.replace(new RegExp("{" + name + "}", "g"), replace[name]);
});
}
return str;
};
self.port.on("setTranslation", function(name, translation){
_[name] = translation;
});
2014-10-11 01:46:47 +02:00
// Communication with main.js
2015-04-09 11:08:31 +02:00
function checkAbout(){
return document.location.protocol === "about:";
2015-04-09 11:08:31 +02:00
}
2014-08-20 10:21:38 +02:00
function checkPDF(blocking){
if (document.contentType.match(/\/pdf$/i)){
self.port.emit("isPDF", blocking);
return true;
}
return false;
2014-08-04 17:02:42 +02:00
}
self.port.on("block", function(force){
2015-04-09 11:08:31 +02:00
if (force || !checkAbout() || !checkPDF("block")){
blockMode.getContext.status = "block";
blockMode.readAPI.status = "allow";
2014-08-20 10:21:38 +02:00
}
});
self.port.on("ask", function(force, askOnce){
2015-04-09 11:08:31 +02:00
if (force || !checkAbout() || !checkPDF("askVisible")){
blockMode.getContext.status = "ask";
blockMode.getContext.askStatus.askOnce = askOnce;
blockMode.readAPI.status = "allow";
}
});
self.port.on("blockReadout", function(force){
2015-04-09 11:08:31 +02:00
if (force || !checkAbout() || !checkPDF("blockReadout")){
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "block";
2014-08-20 10:21:38 +02:00
}
});
2014-10-13 01:37:13 +02:00
self.port.on("fakeReadout", function(force){
2015-04-09 11:08:31 +02:00
if (force || !checkAbout() || !checkPDF("fakeReadout")){
2014-10-13 01:37:13 +02:00
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "fake";
}
});
2014-10-11 01:46:47 +02:00
self.port.on("askReadout", function(force, askOnce){
2015-04-09 11:08:31 +02:00
if (force || !checkAbout() || !checkPDF("askReadout")){
2014-10-11 01:46:47 +02:00
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "ask";
blockMode.readAPI.askStatus.askOnce = askOnce;
}
});
self.port.on("unblock", function(){
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "allow";
});
2014-10-13 09:31:04 +02:00
self.port.on("detach", function(){
blockMode.getContext.status = "allow";
blockMode.readAPI.status = "allow";
});
2014-12-15 18:43:47 +01:00
// settings passthrough
self.port.on("set", function(name, value){
settings[name] = value;
});
}());