1
0
Fork 0
mirror of https://github.com/kkapsner/CanvasBlocker synced 2025-07-04 20:46:39 +02:00

e10s ready!

Fixes #60 and #42
This commit is contained in:
kkapsner 2016-02-13 12:28:36 +01:00
parent 35c6a82480
commit 951277e922
10 changed files with 411 additions and 178 deletions

View file

@ -4,10 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){
"use strict";
const _ = require("sdk/l10n").get;
const preferences = require("sdk/simple-prefs");
const prefs = preferences.prefs;
const {parseErrorStack} = require("./callingStack");
// Check canvas appearance
function canvasAppearance(window, context){
@ -59,7 +56,7 @@
}
var modes = new WeakMap();
function getAskMode(window, type){
function getAskMode(window, type, _){
var mode = modes.get(window);
if (mode){
return mode[type];
@ -94,12 +91,12 @@
}
}
exports.ask = function(window, type, canvas, callingStackMsg){
exports.ask = function({window, type, canvas, errorStack}, {_, prefs}){
var answer;
var askMode = getAskMode(window, type);
var askMode = getAskMode(window, type, _);
var askStatus = askMode.askStatus;
var appearance = canvasAppearance(window, canvas);
if (prefs.askOnlyOnce && askStatus.alreadyAsked[appearance.askCategory]){
if (prefs("askOnlyOnce") && askStatus.alreadyAsked[appearance.askCategory]){
// already asked
appearance.reset();
return askStatus.answer[appearance.askCategory];
@ -107,8 +104,8 @@
else {
// asking
var msg = _(askMode.askText[appearance.text]);
if (prefs.showCallingFile){
msg += callingStackMsg;
if (prefs("showCallingFile")){
msg += parseErrorStack(errorStack).toString(_);
}
answer = window.confirm(msg)? "allow": "block";
askStatus.alreadyAsked[appearance.text] = true;

View file

@ -4,16 +4,18 @@
* 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/. */
const lists = require("./lists");
const preferences = require("sdk/simple-prefs");
const prefs = preferences.prefs;
// Translation
var translate = require("sdk/l10n").get;
var _ = function(name, replace){
var _ = function(name, replace, translateAPI){
"use strict";
if (!translateAPI){
translateAPI = translate;
}
var str = translate(name) || name;
var str = translateAPI(name) || name;
if (replace){
// replace generic content in the transation by given parameter
Object.keys(replace).forEach(function(name){
@ -23,69 +25,6 @@ var _ = function(name, replace){
return str;
};
function check(stack, url, blockMode){
if (prefs.enableStackList && checkStack(stack)){
return "allow";
}
else {
return checkURL(url, blockMode);
}
}
function checkURL(url, blockMode){
"use strict";
switch (url.protocol){
case "about:":
if (url.href === "about:blank"){
break;
}
case "chrome:":
return "allow";
}
var mode = "block";
switch (blockMode){
case "blockEverything":
mode = "block";
break;
case "block":
case "blockContext":
case "blockReadout":
case "ask":
case "askContext":
case "askReadout":
case "fake":
case "fakeContext":
case "fakeReadout":
case "allow":
case "allowContext":
case "allowReadout":
if (url && lists.get("white").match(url)){
mode = "allow";
}
else if (url && lists.get("black").match(url)){
mode = "block";
}
else {
mode = blockMode;
}
break;
case "allowEverything":
mode = "allow";
break;
default:
console.log("Unknown blocking mode (" + blockMode + "). Default to block everything.");
}
return mode;
}
function checkStack(stack){
"use strict";
return lists.get("stack").match(stack);
}
// Stack parsing
function parseStackEntry(entry){
"use strict";
@ -116,10 +55,10 @@ function stackRuleMatch(stackEntry, stackRule){
}
// parse calling stack
function errorToCallingStack(error){
function parseErrorStack(errorStack){
"use strict";
var callers = error.stack.trim().split("\n");
var callers = errorStack.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
@ -131,16 +70,16 @@ function errorToCallingStack(error){
return !inDoubleStack;
}).map(parseStackEntry);
return {
toString: function(){
toString: function(translateAPI){
var msg = "";
msg += "\n\n" + _("sourceOutput") + ": ";
msg += "\n\n" + _("sourceOutput", undefined, translateAPI) + ": ";
if (prefs.showCompleteCallingStack){
msg += callers.reduce(function(stack, c){
return stack + "\n\t" + _("stackEntryOutput", c);
return stack + "\n\t" + _("stackEntryOutput", c, translateAPI);
}, "");
}
else{
msg += _("stackEntryOutput", callers[0]);
msg += _("stackEntryOutput", callers[0], translateAPI);
}
return msg;
@ -162,6 +101,4 @@ function errorToCallingStack(error){
};
}
exports.check = check;
exports.parseStackEntry = parseStackEntry;
exports.errorToCallingStack = errorToCallingStack;
exports.parseErrorStack = parseErrorStack;

95
lib/check.js Normal file
View file

@ -0,0 +1,95 @@
/* global console,exports */
/* jslint moz: true */
/* 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/. */
(function(){
"use strict";
const lists = require("./lists");
const preferences = require("sdk/simple-prefs");
const prefs = preferences.prefs;
const {parseErrorStack} = require("./callingStack");
const {URL} = require("sdk/url");
exports.check = function check({url, errorStack}){
var callingStack = parseErrorStack(errorStack);
var match = checkBoth(callingStack, url, prefs.blockMode).match(/^(block|allow|fake|ask)(|Readout|Everything|Context)$/);
if (match){
return {
type: (match[2] === "Everything" || match[2] === "")?
["context", "readout"]:
[match[2].toLowerCase()],
mode: match[1]
};
}
else {
return {
type: ["context", "readout"],
mode: "block"
};
}
};
function checkBoth(stack, url, blockMode){
if (prefs.enableStackList && checkStack(stack)){
return "allow";
}
else {
return checkURL(url, blockMode);
}
}
function checkURL(url, blockMode){
url = new URL(url);
switch (url.protocol){
case "about:":
if (url.href === "about:blank"){
break;
}
case "chrome:":
return "allow";
}
var mode = "block";
switch (blockMode){
case "blockEverything":
mode = "block";
break;
case "block":
case "blockContext":
case "blockReadout":
case "ask":
case "askContext":
case "askReadout":
case "fake":
case "fakeContext":
case "fakeReadout":
case "allow":
case "allowContext":
case "allowReadout":
if (url && lists.get("white").match(url)){
mode = "allow";
}
else if (url && lists.get("black").match(url)){
mode = "block";
}
else {
mode = blockMode;
}
break;
case "allowEverything":
mode = "allow";
break;
default:
console.log("Unknown blocking mode (" + blockMode + "). Default to block everything.");
}
return mode;
}
function checkStack(stack){
return lists.get("stack").match(stack);
}
}());

51
lib/intercept.js Normal file
View file

@ -0,0 +1,51 @@
/* 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/. */
(function(){
"use strict";
const {changedFunctions} = require("./modifiedAPI");
var apiNames = Object.keys(changedFunctions);
var undef;
exports.intercept = function intercept({subject: window}, {check, ask, notify}){
apiNames.forEach(function(name){
var changedFunction = changedFunctions[name];
var original = window.wrappedJSObject[changedFunction.object].prototype[name];
Object.defineProperty(
window.wrappedJSObject[changedFunction.object].prototype,
name,
{
enumerable: true,
configureable: false,
get: function(){
if (!window.location.href){
return undef;
}
var error = new Error();
var status = check({url: window.location.href, errorStack: error.stack});
if (status.type.indexOf(changedFunction.type) !== -1){
if (status.mode === "ask"){
status.mode = ask({window: window, type: changedFunction.type, canvas: this, errorStack: error.stack});
}
switch (status.mode){
case "allow":
return original;
case "fake":
notify({url: window.location.href, errorStack: error.stack}, window);
return changedFunction.fake || undef;
//case "block":
default:
return undef;
}
}
else {
return original;
}
}
}
);
});
}
}());

View file

@ -31,7 +31,7 @@ function getDomainRegExpList(domainList){
return {
match: function(url){
if (domain){
return url.hostname.match(regExp);
return (url.hostname || "").match(regExp);
}
else {
return url.href.match(regExp);

View file

@ -5,82 +5,107 @@
(function(){
"use strict";
require("./stylePreferencePane");
const {changedFunctions} = require("./modifiedAPI");
const {when: unload} = require("sdk/system/unload");
const {check} = require("./check.js");
const {notify} = require("./notifications");
const {ask} = require("./askForPermission");
const _ = require("sdk/l10n").get;
const lists = require("./lists");
const sharedFunctions = require("./sharedFunctions");
const observers = require("sdk/system/events");
const { when: unload } = require("sdk/system/unload");
const preferences = require("sdk/simple-prefs");
const prefService = require("sdk/preferences/service");
const prefs = preferences.prefs;
function check(callingStack, url){
var match = sharedFunctions.check(callingStack, url, prefs.blockMode).match(/^(block|allow|fake|ask)(|Readout|Everything|Context)$/);
if (match){
return {
type: (match[2] === "Everything" || match[2] === "")?
["context", "readout"]:
[match[2].toLowerCase()],
mode: match[1]
};
const notificationPref = {
doShow: function(){
return prefs.showNotifications;
},
setShow: function(value){
prefs.showNotifications = value;
prefService.set("extensions.CanvasBlocker@kkapsner.de.showNotifications", prefs.showNotifications);
}
else {
return {
type: ["context", "readout"],
mode: "block"
};
}
};
// const observers = require("sdk/system/events");
// const {intercept} = require("./intercept");
// const {errorToCallingStack} = require("./callingStack.js");
// const {ask} = require("./askForPermission");
// function interceptWrapper(ev){
// intercept(ev, {
// check,
// ask: function(data){
// return ask(
// data,
// {
// _,
// prefs: function(name){
// return prefs[ev.data];
// }
// }
// );
// },
// notify: function(data, window){
// notify(
// data,
// {
// lists, _, notificationPref, window
// }
// );
// }
// });
// }
// observers.on("content-document-global-created", interceptWrapper);
// unload(function(){
// observers.off("content-document-global-created", interceptWrapper);
// });
const {Cc, Ci} = require("chrome");
var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
var frameURL = require("sdk/self").data.url("frame.js?" + Math.random());
globalMM.loadFrameScript(frameURL, true);
var listeners = [];
function addMessageListener(name, func){
listeners.push({name, func});
globalMM.addMessageListener(name, func);
}
var apiNames = Object.keys(changedFunctions);
var undef;
function intercept({subject: window}){
apiNames.forEach(function(name){
var changedFunction = changedFunctions[name];
var original = window.wrappedJSObject[changedFunction.object].prototype[name];
Object.defineProperty(
window.wrappedJSObject[changedFunction.object].prototype,
name,
{
enumerable: true,
configureable: false,
get: function(){
var callingStack = sharedFunctions.errorToCallingStack(new Error());
var status = check(callingStack, window.location);
if (status.type.indexOf(changedFunction.type) !== -1){
if (status.mode === "ask"){
status.mode = ask(window, changedFunction.type, this, callingStack);
}
switch (status.mode){
case "allow":
return original;
case "fake":
notify(window, callingStack);
return changedFunction.fake || undef;
//case "block":
default:
return undef;
}
}
else {
return original;
}
}
}
);
});
}
observers.on("content-document-global-created", intercept);
unload(function(){
observers.off("content-document-global-created", intercept);
globalMM.removeDelayedFrameScript(frameURL);
globalMM.broadcastAsyncMessage("canvasBlocker-unload");
listeners.forEach(function(listener){
globalMM.removeMessageListener(listener.name, listener.func);
});
});
// messages from the frame.js
addMessageListener("canvasBlocker-check", function(ev){
var status = check(ev.data);
return status;
});
addMessageListener("canvasBlocker-notify", function(ev){
var browser = ev.target;
notify(ev.data, {lists, _, notificationPref, browser});
});
addMessageListener("canvasBlocker-pref-get", function(ev){
return prefs[ev.data];
});
addMessageListener("canvasBlocker-pref-set", function(ev){
prefs[ev.data.name] = ev.data.value;
prefService.set("extensions.CanvasBlocker@kkapsner.de." + ev.data.name, ev.data.value);
});
addMessageListener("canvasBlocker-list-match", function(ev){
return lists.get(ev.data.list).match(ev.data.url);
});
addMessageListener("canvasBlocker-list-appendTo", function(ev){
return lists.appendTo(ev.data.list, ev.data.entry);
});
addMessageListener("canvasBlocker-translate", function(ev){
return _(ev.data);
});
}());

View file

@ -2,26 +2,32 @@
* 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/. */
var _ = require("sdk/l10n").get;
var preferences = require("sdk/simple-prefs");
var prefService = require("sdk/preferences/service");
var prefs = preferences.prefs;
var tabUtils = require("sdk/tabs/utils");
var lists = require("./lists");
var URL = require("sdk/url").URL;
exports.notify = function(window, callingStackMsg){
var URL = require("sdk/url").URL;
const {parseErrorStack} = require("./callingStack");
var tabUtils = require("sdk/tabs/utils");
exports.notify = function({url, errorStack}, {lists, notificationPref, _, browser, window}){
"use strict";
var callingStackMsg = parseErrorStack(errorStack);
var contentURL = new URL(window.location);
if (prefs.showNotifications && !lists.get("ignore").match(contentURL)){
var contentURL = new URL(url);
if (notificationPref.doShow() && !lists.get("ignore").match(contentURL)){
var url = contentURL.href;
var domain = contentURL.hostname;
var message = _("fakedReadout").replace(/\{url\}/g, domain);
var message = _("fakedReadout").replace(/\{url\}/g, domain || url);
var tab = tabUtils.getTabForContentWindow(window);
var tabBrowser = tabUtils.getTabBrowserForTab(tab);
var browser = tabUtils.getBrowserForTab(tab);
var tab, tabBrowser;
if (browser){
window = tabUtils.getOwnerWindow(browser);
tab = tabUtils.getTabForBrowser(browser);
tabBrowser = tabUtils.getTabBrowser(window);
}
else if (window){
tab = tabUtils.getTabForContentWindow(window);
tabBrowser = tabUtils.getTabBrowserForTab(tab);
browser = tabUtils.getBrowserForTab(tab);
}
var notifyBox = tabBrowser.getNotificationBox(browser);
var notification = notifyBox.getNotificationWithValue("fake-readout");
@ -37,7 +43,7 @@ exports.notify = function(window, callingStackMsg){
label: _("displayFullURL"),
accessKey: "",
callback: function(){
browser.contentWindow.alert(notification.url);
window.alert(notification.url);
// only way to prevent closing... see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/appendNotification#Notification_box_events
throw new Error("Do not close notification.");
}
@ -46,7 +52,7 @@ exports.notify = function(window, callingStackMsg){
label: _("displayCallingStack"),
accessKey: "",
callback: function(){
browser.contentWindow.alert(notification.callingStackMsg);
window.alert(notification.callingStackMsg);
// only way to prevent closing... see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/appendNotification#Notification_box_events
throw new Error("Do not close notification.");
}
@ -55,7 +61,7 @@ exports.notify = function(window, callingStackMsg){
label: _("ignorelistDomain"),
accessKey: "",
callback: function(){
var domain = browser.contentWindow.prompt(
var domain = window.prompt(
_("inputIgnoreDomain"),
notification.domain
);
@ -68,7 +74,7 @@ exports.notify = function(window, callingStackMsg){
label: _("whitelistURL"),
accessKey: "",
callback: function(){
var url = browser.contentWindow.prompt(
var url = window.prompt(
_("inputWhitelistDomain"),
"^" + notification.url.replace(/([\\\+\*\?\[\^\]\$\(\)\{\}\=\!\|\.])/g, "\\$1") + "$"
);
@ -81,7 +87,7 @@ exports.notify = function(window, callingStackMsg){
label: _("whitelistDomain"),
accessKey: "",
callback: function(){
var domain = browser.contentWindow.prompt(
var domain = window.prompt(
_("inputWhitelistURL"),
notification.domain
);
@ -95,8 +101,7 @@ exports.notify = function(window, callingStackMsg){
label: _("disableNotifications"),
accessKey: "",
callback: function(){
prefs.showNotifications = false;
prefService.set("extensions.CanvasBlocker@kkapsner.de.showNotifications", prefs.showNotifications);
notificationPref.setShow(false);
}
}
];