mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2025-01-03 10:31:54 +01:00
First implementation of the fakeInput mode. (And other improvements.)
This commit is contained in:
parent
b6d08459a5
commit
a2fa00fb98
@ -8,7 +8,8 @@
|
|||||||
const {utils: Cu} = Components;
|
const {utils: Cu} = Components;
|
||||||
const COMMONJS_URI = "resource://gre/modules/commonjs";
|
const COMMONJS_URI = "resource://gre/modules/commonjs";
|
||||||
const {require} = Cu.import(COMMONJS_URI + "/toolkit/require.js", {});
|
const {require} = Cu.import(COMMONJS_URI + "/toolkit/require.js", {});
|
||||||
const {intercept} = require("../lib/intercept.js");
|
const {intercept, setExportFunction} = require("../lib/intercept.js");
|
||||||
|
setExportFunction(Cu.exportFunction);
|
||||||
const {ask} = require("../lib/askForPermission.js");
|
const {ask} = require("../lib/askForPermission.js");
|
||||||
|
|
||||||
// Variable to "unload" the script
|
// Variable to "unload" the script
|
||||||
|
@ -59,7 +59,6 @@ function parseErrorStack(errorStack){
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var callers = errorStack.trim().split("\n");
|
var callers = errorStack.trim().split("\n");
|
||||||
//console.log(callers);
|
|
||||||
var findme = callers.shift(); // Remove us from the stack
|
var findme = callers.shift(); // Remove us from the stack
|
||||||
findme = findme.replace(/(:[0-9]+){1,2}$/, ""); // rm line & column
|
findme = findme.replace(/(:[0-9]+){1,2}$/, ""); // rm line & column
|
||||||
// Eliminate squashed stack. stack may contain 2+ stacks, but why...
|
// Eliminate squashed stack. stack may contain 2+ stacks, but why...
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
setRandomSupply(randomSupplies.nonPersistent);
|
setRandomSupply(randomSupplies.nonPersistent);
|
||||||
var apiNames = Object.keys(changedFunctions);
|
var apiNames = Object.keys(changedFunctions);
|
||||||
var undef;
|
var undef;
|
||||||
|
var exportFunction;
|
||||||
|
|
||||||
function setRandomSupplyByType(type){
|
function setRandomSupplyByType(type){
|
||||||
switch (type){
|
switch (type){
|
||||||
@ -38,28 +39,27 @@
|
|||||||
}
|
}
|
||||||
var error = new Error();
|
var error = new Error();
|
||||||
var status = check({url: window.location.href, errorStack: error.stack});
|
var status = check({url: window.location.href, errorStack: error.stack});
|
||||||
if (status.type.indexOf(changedFunction.type) !== -1){
|
var funcStatus = changedFunction.getStatus(this, status);
|
||||||
if (status.mode === "ask"){
|
|
||||||
status.mode = ask({window: window, type: changedFunction.type, canvas: this, errorStack: error.stack});
|
if (funcStatus.active){
|
||||||
|
if (funcStatus.mode === "ask"){
|
||||||
|
funcStatus.mode = ask({window: window, type: changedFunction.type, canvas: this, errorStack: error.stack});
|
||||||
}
|
}
|
||||||
switch (status.mode){
|
switch (funcStatus.mode){
|
||||||
case "allow":
|
case "allow":
|
||||||
return original;
|
return original;
|
||||||
case "fake":
|
case "fake":
|
||||||
setRandomSupplyByType(prefs("rng"));
|
setRandomSupplyByType(prefs("rng"));
|
||||||
if (changedFunction.fake){
|
var fake = changedFunction.fakeGenerator(prefs, function(messageId){
|
||||||
notify({url: window.location.href, errorStack: error.stack}, window);
|
notify({url: window.location.href, errorStack: error.stack, messageId});
|
||||||
return changedFunction.fake;
|
});
|
||||||
}
|
switch (fake){
|
||||||
else {
|
case true:
|
||||||
if (changedFunction.fakeGenerator) {
|
return original;
|
||||||
return changedFunction.fakeGenerator(prefs, function(){
|
case false:
|
||||||
notify({url: window.location.href, errorStack: error.stack}, window);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
default:
|
||||||
|
return exportFunction(fake, window.wrappedJSObject);
|
||||||
}
|
}
|
||||||
//case "block":
|
//case "block":
|
||||||
default:
|
default:
|
||||||
@ -74,4 +74,7 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
exports.setExportFunction = function(eFunc){
|
||||||
|
exportFunction = eFunc;
|
||||||
|
};
|
||||||
}());
|
}());
|
@ -7,80 +7,165 @@
|
|||||||
|
|
||||||
var randomSupply = null;
|
var randomSupply = null;
|
||||||
|
|
||||||
function getFakeCanvas(window, original){
|
function getContext(window, canvas){
|
||||||
var context = window.HTMLCanvasElement.prototype.getContext.call(original, "2d");
|
return window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d") ||
|
||||||
var imageData, data, source;
|
window.HTMLCanvasElement.prototype.getContext.call(canvas, "webgl") ||
|
||||||
if (context){
|
window.HTMLCanvasElement.prototype.getContext.call(canvas, "experimental-webgl") ||
|
||||||
imageData = window.CanvasRenderingContext2D.prototype.getImageData.call(context, 0, 0, original.width, original.height);
|
window.HTMLCanvasElement.prototype.getContext.call(canvas, "webgl2") ||
|
||||||
source = imageData.data;
|
window.HTMLCanvasElement.prototype.getContext.call(canvas, "experimental-webgl2");
|
||||||
|
}
|
||||||
|
function getImageData(window, context){
|
||||||
|
if (context instanceof window.CanvasRenderingContext2D){
|
||||||
|
return window.CanvasRenderingContext2D.prototype.getImageData.call(context, 0, 0, context.canvas.width, context.canvas.height);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
context =
|
var imageData = new window.wrappedJSObject.ImageData(context.canvas.width, context.canvas.height);
|
||||||
window.HTMLCanvasElement.prototype.getContext.call(original, "webgl") ||
|
|
||||||
window.HTMLCanvasElement.prototype.getContext.call(original, "experimental-webgl") ||
|
|
||||||
window.HTMLCanvasElement.prototype.getContext.call(original, "webgl2") ||
|
|
||||||
window.HTMLCanvasElement.prototype.getContext.call(original, "experimental-webgl2");
|
|
||||||
imageData = new window.wrappedJSObject.ImageData(original.width, original.height);
|
|
||||||
source = new window.wrappedJSObject.Uint8Array(imageData.data.length);
|
|
||||||
window.WebGLRenderingContext.prototype.readPixels.call(
|
window.WebGLRenderingContext.prototype.readPixels.call(
|
||||||
context,
|
context,
|
||||||
0, 0, original.width, original.height,
|
0, 0, context.canvas.width, context.canvas.height,
|
||||||
context.RGBA, context.UNSIGNED_BYTE,
|
context.RGBA, context.UNSIGNED_BYTE,
|
||||||
source
|
imageData.data
|
||||||
);
|
);
|
||||||
|
return imageData;
|
||||||
}
|
}
|
||||||
data = imageData.data;
|
}
|
||||||
|
|
||||||
|
function getFakeCanvas(window, original){
|
||||||
|
var context = getContext(window, original);
|
||||||
|
var imageData = getImageData(window, context);
|
||||||
|
var data = imageData.data;
|
||||||
var l = data.length;
|
var l = data.length;
|
||||||
var rng = randomSupply.getRng(l, window);
|
var rng = randomSupply.getRng(l, window);
|
||||||
|
|
||||||
for (var i = 0; i < l; i += 1){
|
for (var i = 0; i < l; i += 1){
|
||||||
data[i] = rng(source[i], i);
|
data[i] = rng(data[i], i);
|
||||||
}
|
}
|
||||||
var canvas = original.cloneNode(true);
|
var canvas = original.cloneNode(true);
|
||||||
context = window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d");
|
context = window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d");
|
||||||
context.putImageData(imageData, 0, 0);
|
context.putImageData(imageData, 0, 0);
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
function randomMixImageData(window, imageData1, imageData2){
|
||||||
|
var data1 = imageData1.data;
|
||||||
|
var data2 = imageData2.data;
|
||||||
|
var l = data1.length;
|
||||||
|
if (l === data2.length){
|
||||||
|
var rng = randomSupply.getRng(l, window);
|
||||||
|
|
||||||
|
for (var i = 0; i < l; i += 1){
|
||||||
|
if (data1[i] > data2[i]){
|
||||||
|
data2[i] = data1[i] - rng(data1[i] - data2[i], i);
|
||||||
|
}
|
||||||
|
else if (data1[i] < data2[i]){
|
||||||
|
data2[i] = data1[i] + rng(data2[i] - data1[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imageData2;
|
||||||
|
}
|
||||||
|
|
||||||
function getWindow(canvas){
|
function getWindow(canvas){
|
||||||
return canvas.ownerDocument.defaultView;
|
return canvas.ownerDocument.defaultView;
|
||||||
}
|
}
|
||||||
|
function hasType(status, type){
|
||||||
|
return status.type.indexOf(type) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
exports.setRandomSupply = function(supply){
|
exports.setRandomSupply = function(supply){
|
||||||
randomSupply = supply;
|
randomSupply = supply;
|
||||||
};
|
};
|
||||||
|
var canvasContextType = new WeakMap();
|
||||||
// changed functions and their fakes
|
// changed functions and their fakes
|
||||||
exports.changedFunctions = {
|
exports.changedFunctions = {
|
||||||
getContext: {
|
getContext: {
|
||||||
type: "context",
|
getStatus: function(obj, status){
|
||||||
object: "HTMLCanvasElement"
|
return {
|
||||||
|
mode: hasType(status, "block")? "block": "fake",
|
||||||
|
type: status.type,
|
||||||
|
active: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
object: "HTMLCanvasElement",
|
||||||
|
fakeGenerator: function(prefs, notify){
|
||||||
|
return function(context, contextAttributes){
|
||||||
|
var window = getWindow(this);
|
||||||
|
canvasContextType.set(this, context);
|
||||||
|
return window.HTMLCanvasElement.prototype.getContext.apply(this, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
toDataURL: {
|
toDataURL: {
|
||||||
type: "readout",
|
getStatus: function(obj, status){
|
||||||
|
if (hasType(status, "input")){
|
||||||
|
var contextType = canvasContextType.get(obj);
|
||||||
|
status.active = contextType && contextType !== "2d";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status.active = hasType(status, "readout");
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
},
|
||||||
object: "HTMLCanvasElement",
|
object: "HTMLCanvasElement",
|
||||||
fake: function toDataURL(){
|
fakeGenerator: function(prefs, notify){
|
||||||
var window = getWindow(this);
|
return function toDataURL(){
|
||||||
return window.HTMLCanvasElement.prototype.toDataURL.apply(getFakeCanvas(window, this), arguments);
|
notify("fakedReadout");
|
||||||
|
var window = getWindow(this);
|
||||||
|
return window.HTMLCanvasElement.prototype.toDataURL.apply(getFakeCanvas(window, this), arguments);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toBlob: {
|
toBlob: {
|
||||||
type: "readout",
|
getStatus: function(obj, status){
|
||||||
|
if (hasType(status, "input")){
|
||||||
|
var contextType = canvasContextType.get(obj);
|
||||||
|
status.active = contextType && contextType !== "2d";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status.active = hasType(status, "readout");
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
},
|
||||||
object: "HTMLCanvasElement",
|
object: "HTMLCanvasElement",
|
||||||
fake: function toBlob(callback){
|
fakeGenerator: function(prefs, notify){
|
||||||
var window = getWindow(this);
|
return function toBlob(callback){
|
||||||
return window.HTMLCanvasElement.prototype.toBlob.apply(getFakeCanvas(window, this), arguments);
|
notify("fakedReadout");
|
||||||
|
var window = getWindow(this);
|
||||||
|
return window.HTMLCanvasElement.prototype.toBlob.apply(getFakeCanvas(window, this), arguments);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
exportOptions: {allowCallbacks: true}
|
exportOptions: {allowCallbacks: true}
|
||||||
},
|
},
|
||||||
mozGetAsFile: {
|
mozGetAsFile: {
|
||||||
type: "readout",
|
getStatus: function(obj, status){
|
||||||
|
if (hasType(status, "input")){
|
||||||
|
var contextType = canvasContextType.get(obj);
|
||||||
|
status.active = contextType && contextType !== "2d";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status.active = hasType(status, "readout");
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
},
|
||||||
object: "HTMLCanvasElement",
|
object: "HTMLCanvasElement",
|
||||||
mozGetAsFile: function mozGetAsFile(callback){
|
fakeGenerator: function(prefs, notify){
|
||||||
var window = getWindow(this);
|
return function mozGetAsFile(callback){
|
||||||
return window.HTMLCanvasElement.prototype.mozGetAsFile.apply(getFakeCanvas(window, this), arguments);
|
notify("fakedReadout");
|
||||||
|
var window = getWindow(this);
|
||||||
|
return window.HTMLCanvasElement.prototype.mozGetAsFile.apply(getFakeCanvas(window, this), arguments);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getImageData: {
|
getImageData: {
|
||||||
type: "readout",
|
getStatus: function(obj, status){
|
||||||
|
if (hasType(status, "input")){
|
||||||
|
var contextType = canvasContextType.get(obj);
|
||||||
|
status.active = contextType && contextType !== "2d";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status.active = hasType(status, "readout");
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
},
|
||||||
object: "CanvasRenderingContext2D",
|
object: "CanvasRenderingContext2D",
|
||||||
fakeGenerator: function(prefs, notify){
|
fakeGenerator: function(prefs, notify){
|
||||||
var maxSize = prefs("maxFakeSize") || Number.POSITIVE_INFINITY;
|
var maxSize = prefs("maxFakeSize") || Number.POSITIVE_INFINITY;
|
||||||
@ -91,7 +176,7 @@
|
|||||||
context = this;
|
context = this;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
notify();
|
notify("fakedReadout");
|
||||||
context = window.HTMLCanvasElement.prototype.getContext.call(
|
context = window.HTMLCanvasElement.prototype.getContext.call(
|
||||||
getFakeCanvas(window, this.canvas),
|
getFakeCanvas(window, this.canvas),
|
||||||
"2d"
|
"2d"
|
||||||
@ -107,14 +192,55 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
fillText: {
|
||||||
|
getStatus: function(obj, status){
|
||||||
|
status.active = hasType(status, "input");
|
||||||
|
return status;
|
||||||
|
},
|
||||||
|
object: "CanvasRenderingContext2D",
|
||||||
|
fakeGenerator: function(prefs, notify){
|
||||||
|
return function fillText(str, x, y){
|
||||||
|
notify("fakedInput");
|
||||||
|
var window = getWindow(this.canvas);
|
||||||
|
var oldImageData = getImageData(window, this);
|
||||||
|
var ret = window.CanvasRenderingContext2D.prototype.fillText.apply(this, arguments);
|
||||||
|
var newImageData = getImageData(window, this);
|
||||||
|
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
strokeText: {
|
||||||
|
getStatus: function(obj, status){
|
||||||
|
status.active = hasType(status, "input");
|
||||||
|
return status;
|
||||||
|
},
|
||||||
|
object: "CanvasRenderingContext2D",
|
||||||
|
fakeGenerator: function(prefs, notify){
|
||||||
|
return function strokeText(str, x, y){
|
||||||
|
notify("fakedInput");
|
||||||
|
var window = getWindow(this.canvas);
|
||||||
|
var oldImageData = getImageData(window, this);
|
||||||
|
var ret = window.CanvasRenderingContext2D.prototype.strokeText.apply(this, arguments);
|
||||||
|
var newImageData = getImageData(window, this);
|
||||||
|
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
readPixels: {
|
readPixels: {
|
||||||
type: "readout",
|
getStatus: function(obj, status){
|
||||||
|
status.active = hasType(status, "readout") || hasType(status, "input");
|
||||||
|
return status;
|
||||||
|
},
|
||||||
object: "WebGLRenderingContext",
|
object: "WebGLRenderingContext",
|
||||||
fake: function readPixels(x, y, width, height, format, type, pixels){
|
fakeGenerator: function(prefs, notify){
|
||||||
var window = getWindow(this.canvas);
|
return function readPixels(x, y, width, height, format, type, pixels){
|
||||||
var context = window.HTMLCanvasElement.prototype.getContext.call(getFakeCanvas(window, this.canvas), "webGL");
|
notify("fakedReadout");
|
||||||
return window.WebGLRenderingContext.prototype.readPixels.apply(context, arguments);
|
var window = getWindow(this.canvas);
|
||||||
|
var context = window.HTMLCanvasElement.prototype.getContext.call(getFakeCanvas(window, this.canvas), "webGL");
|
||||||
|
return window.WebGLRenderingContext.prototype.readPixels.apply(context, arguments);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ var URL = require("sdk/url").URL;
|
|||||||
const {parseErrorStack} = require("./callingStack");
|
const {parseErrorStack} = require("./callingStack");
|
||||||
|
|
||||||
var tabUtils = require("sdk/tabs/utils");
|
var tabUtils = require("sdk/tabs/utils");
|
||||||
exports.notify = function({url, errorStack}, {lists, notificationPref, _, browser, window}){
|
exports.notify = function({url, errorStack, messageId}, {lists, notificationPref, _, browser, window}){
|
||||||
"use strict";
|
"use strict";
|
||||||
var callingStackMsg = parseErrorStack(errorStack);
|
var callingStackMsg = parseErrorStack(errorStack);
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ exports.notify = function({url, errorStack}, {lists, notificationPref, _, browse
|
|||||||
if (notificationPref.doShow() && !lists.get("ignore").match(contentURL)){
|
if (notificationPref.doShow() && !lists.get("ignore").match(contentURL)){
|
||||||
url = contentURL.href;
|
url = contentURL.href;
|
||||||
var domain = contentURL.hostname;
|
var domain = contentURL.hostname;
|
||||||
var message = _("fakedReadout").replace(/\{url\}/g, domain || url);
|
var message = _(messageId).replace(/\{url\}/g, domain || url);
|
||||||
|
|
||||||
var tab, tabBrowser;
|
var tab, tabBrowser;
|
||||||
if (browser){
|
if (browser){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user