mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2024-12-22 21:00:23 +01:00
First working webExtesion.
This commit is contained in:
parent
4ea073132d
commit
cba5680406
70
lib/frame.js
70
lib/frame.js
@ -4,7 +4,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
const {process, frames} = require("sdk/remote/child");
|
||||
const {intercept} = require("./intercept.js");
|
||||
const {ask} = require("./askForPermission.js");
|
||||
const {check: originalCheck, checkStack: originalCheckStack} = require("./check.js");
|
||||
@ -38,7 +37,7 @@
|
||||
});
|
||||
}
|
||||
function notify(data){
|
||||
process.port.emit("canvasBlocker-notify", data);
|
||||
browser.runtime.sendMessage({"canvasBlocker-notify": data});
|
||||
}
|
||||
|
||||
const preferences = require("sdk/simple-prefs");
|
||||
@ -46,22 +45,59 @@
|
||||
return preferences.prefs[name];
|
||||
}
|
||||
|
||||
frames.forEvery(function(frame){
|
||||
frame.addEventListener("DOMWindowCreated", function(ev){
|
||||
function notify(data){
|
||||
frame.port.emit("canvasBlocker-notify", data);
|
||||
}
|
||||
if (enabled){
|
||||
var subject = ev.target.defaultView;
|
||||
intercept(
|
||||
{subject},
|
||||
{check, checkStack, ask: askWrapper, notify, prefs}
|
||||
);
|
||||
}
|
||||
|
||||
var interceptedWindows = new WeakMap();
|
||||
function interceptWindow(window){
|
||||
if (interceptedWindows.get(window)){
|
||||
return false;
|
||||
}
|
||||
intercept(
|
||||
{subject: window},
|
||||
{check, checkStack, ask: askWrapper, notify, prefs}
|
||||
);
|
||||
|
||||
[window.HTMLIFrameElement, window.HTMLFrameElement].forEach(function(constructor){
|
||||
var oldContentWindowGetter = constructor.prototype.__lookupGetter__("contentWindow");
|
||||
Object.defineProperty(
|
||||
constructor.prototype.wrappedJSObject,
|
||||
"contentWindow",
|
||||
{
|
||||
enumerable: true,
|
||||
configureable: true,
|
||||
get: exportFunction(function(){
|
||||
var window = oldContentWindowGetter.call(this);
|
||||
interceptWindow(window);
|
||||
return window;
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
var oldContentDocumentGetter = constructor.prototype.__lookupGetter__("contentDocument");
|
||||
Object.defineProperty(
|
||||
constructor.prototype.wrappedJSObject,
|
||||
"contentDocument",
|
||||
{
|
||||
enumerable: true,
|
||||
configureable: true,
|
||||
get: exportFunction(function(){
|
||||
var document = oldContentDocumentGetter.call(this);
|
||||
interceptWindow(document.defaultView);
|
||||
return document;
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
interceptedWindows.set(window, true);
|
||||
return true;
|
||||
};
|
||||
|
||||
if (enabled){
|
||||
interceptWindow(window);
|
||||
}
|
||||
|
||||
process.port.on("canvasBlocker-unload", function unload(){
|
||||
enabled = false;
|
||||
browser.runtime.onMessage.addListener(function(data){
|
||||
if (data["canvasBlocker-unload"]){
|
||||
enabled = false;
|
||||
}
|
||||
});
|
||||
}());
|
@ -60,7 +60,7 @@
|
||||
{
|
||||
enumerable: true,
|
||||
configureable: false,
|
||||
get: exportFunction(function()
|
||||
get: exportFunction(function(){
|
||||
var url = getURL(window);
|
||||
if (!url){
|
||||
return undef;
|
||||
|
204
lib/lists.js
204
lib/lists.js
@ -3,110 +3,124 @@
|
||||
* 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 preferences = require("sdk/simple-prefs");
|
||||
var prefService = require("sdk/preferences/service");
|
||||
var prefs = preferences.prefs;
|
||||
|
||||
|
||||
function getDomainRegExpList(domainList){
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var list = domainList
|
||||
.split(",")
|
||||
.map(function(entry){
|
||||
return entry.replace(/^\s+|\s+$/g, "");
|
||||
})
|
||||
.filter(function(entry){
|
||||
return !!entry.length;
|
||||
})
|
||||
.map(function(entry){
|
||||
var regExp;
|
||||
var domain = !!entry.match(/^[\w.]+$/);
|
||||
if (domain){
|
||||
regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\\+\*\?\[\^\]\$\(\)\{\}\=\!\|\.])/g, "\\$1") + "\\.?$", "i");
|
||||
}
|
||||
else {
|
||||
regExp = new RegExp(entry, "i");
|
||||
}
|
||||
return {
|
||||
match: function(url){
|
||||
if (domain){
|
||||
return (url.hostname || "").match(regExp);
|
||||
}
|
||||
else {
|
||||
return url.href.match(regExp);
|
||||
}
|
||||
|
||||
var scope;
|
||||
if ((typeof exports) !== "undefined"){
|
||||
scope = exports;
|
||||
}
|
||||
else {
|
||||
window.scope.lists = {};
|
||||
scope = window.scope.lists;
|
||||
}
|
||||
|
||||
var preferences = require("sdk/simple-prefs");
|
||||
var prefs = preferences.prefs;
|
||||
|
||||
|
||||
function getDomainRegExpList(domainList){
|
||||
"use strict";
|
||||
|
||||
var list = domainList
|
||||
.split(",")
|
||||
.map(function(entry){
|
||||
return entry.replace(/^\s+|\s+$/g, "");
|
||||
})
|
||||
.filter(function(entry){
|
||||
return !!entry.length;
|
||||
})
|
||||
.map(function(entry){
|
||||
var regExp;
|
||||
var domain = !!entry.match(/^[\w.]+$/);
|
||||
if (domain){
|
||||
regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\\+\*\?\[\^\]\$\(\)\{\}\=\!\|\.])/g, "\\$1") + "\\.?$", "i");
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
list.match = function(url){
|
||||
return this.some(function(entry){
|
||||
return entry.match(url);
|
||||
else {
|
||||
regExp = new RegExp(entry, "i");
|
||||
}
|
||||
return {
|
||||
match: function(url){
|
||||
if (domain){
|
||||
return (url.hostname || "").match(regExp);
|
||||
}
|
||||
else {
|
||||
return url.href.match(regExp);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
list.match = function(url){
|
||||
return this.some(function(entry){
|
||||
return entry.match(url);
|
||||
});
|
||||
};
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
var lists = {
|
||||
white: [],
|
||||
"ignore": [],
|
||||
black: []
|
||||
};
|
||||
|
||||
function updateList(type){
|
||||
"use strict";
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
var lists = {
|
||||
white: [],
|
||||
"ignore": [],
|
||||
black: []
|
||||
};
|
||||
|
||||
function updateList(type){
|
||||
"use strict";
|
||||
|
||||
lists[type] = getDomainRegExpList(prefs[type + "List"]);
|
||||
}
|
||||
Object.keys(lists).forEach(function(type){
|
||||
"use strict";
|
||||
|
||||
preferences.on(type + "List", function(){
|
||||
lists[type] = getDomainRegExpList(prefs[type + "List"]);
|
||||
}
|
||||
Object.keys(lists).forEach(function(type){
|
||||
"use strict";
|
||||
|
||||
preferences.on(type + "List", function(){
|
||||
updateList(type);
|
||||
});
|
||||
updateList(type);
|
||||
});
|
||||
updateList(type);
|
||||
});
|
||||
|
||||
function updateStackList(){
|
||||
var list;
|
||||
try {
|
||||
var data = JSON.parse(prefs.stackList);
|
||||
if (!Array.isArray(data)){
|
||||
data = [data];
|
||||
function updateStackList(){
|
||||
var list;
|
||||
try {
|
||||
var data = JSON.parse(prefs.stackList);
|
||||
if (!Array.isArray(data)){
|
||||
data = [data];
|
||||
}
|
||||
list = data.filter(function(entry){
|
||||
return typeof entry === "object" && typeof entry.url === "string";
|
||||
});
|
||||
}
|
||||
list = data.filter(function(entry){
|
||||
return typeof entry === "object" && typeof entry.url === "string";
|
||||
});
|
||||
catch(e){
|
||||
list = [];
|
||||
}
|
||||
list.match = function(stack){
|
||||
return this.some(function(stackRule){
|
||||
return stack.match(stackRule);
|
||||
});
|
||||
};
|
||||
lists.stack = list;
|
||||
}
|
||||
catch(e){
|
||||
list = [];
|
||||
}
|
||||
list.match = function(stack){
|
||||
return this.some(function(stackRule){
|
||||
return stack.match(stackRule);
|
||||
});
|
||||
};
|
||||
lists.stack = list;
|
||||
}
|
||||
lists.stack = [];
|
||||
preferences.on("stackList", function(){
|
||||
lists.stack = [];
|
||||
preferences.on("stackList", function(){
|
||||
updateStackList();
|
||||
});
|
||||
updateStackList();
|
||||
});
|
||||
updateStackList();
|
||||
|
||||
exports.get = function getList(type){
|
||||
"use strict";
|
||||
|
||||
return lists[type];
|
||||
};
|
||||
exports.appendTo = function appendToList(type, entry){
|
||||
"use strict";
|
||||
|
||||
prefs[type + "List"] += (prefs[type + "List"]? ",": "") + entry;
|
||||
prefService.set("extensions.CanvasBlocker@kkapsner.de." + type + "List", prefs[type + "List"]);
|
||||
updateList(type);
|
||||
};
|
||||
exports.update = updateList;
|
||||
scope.get = function getList(type){
|
||||
"use strict";
|
||||
|
||||
return lists[type];
|
||||
};
|
||||
scope.appendTo = function appendToList(type, entry){
|
||||
"use strict";
|
||||
|
||||
prefs[type + "List"] += (prefs[type + "List"]? ",": "") + entry;
|
||||
var obj = {};
|
||||
obj[type + "List"] = prefs[type + "List"];
|
||||
browser.storage.local.set(obj);
|
||||
updateList(type);
|
||||
};
|
||||
scope.update = updateList;
|
||||
}());
|
10
lib/main.js
10
lib/main.js
@ -4,6 +4,16 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
console.log("start main script");
|
||||
browser.runtime.onMessage.addListener(function(data){
|
||||
console.log("got data", data);
|
||||
});
|
||||
browser.runtime.onConnect.addListener(function(port){
|
||||
console.log("got port");
|
||||
});
|
||||
console.log("end main script");
|
||||
return null;
|
||||
require("./stylePreferencePane");
|
||||
|
||||
|
||||
|
@ -5,7 +5,16 @@
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
let Cu = require("chrome").Cu;
|
||||
var scope;
|
||||
if ((typeof exports) !== "undefined"){
|
||||
scope = exports;
|
||||
}
|
||||
else {
|
||||
window.scope.modifiedAPI = {};
|
||||
scope = window.scope.modifiedAPI;
|
||||
}
|
||||
|
||||
// let Cu = require("chrome").Cu;
|
||||
|
||||
var randomSupply = null;
|
||||
|
||||
@ -87,12 +96,12 @@
|
||||
return status.type.indexOf(type) !== -1;
|
||||
}
|
||||
|
||||
exports.setRandomSupply = function(supply){
|
||||
scope.setRandomSupply = function(supply){
|
||||
randomSupply = supply;
|
||||
};
|
||||
var canvasContextType = new WeakMap();
|
||||
// changed functions and their fakes
|
||||
exports.changedFunctions = {
|
||||
scope.changedFunctions = {
|
||||
getContext: {
|
||||
type: "context",
|
||||
getStatus: function(obj, status){
|
||||
@ -288,7 +297,7 @@
|
||||
return function readPixels(x, y, width, height, format, type, pixels){
|
||||
// not able to use the getFakeCanvas function because the context type is wrong...
|
||||
notify("fakedReadout");
|
||||
var xPixels = Cu.waiveXrays(pixels);
|
||||
var xPixels = pixels//Cu.waiveXrays(pixels);
|
||||
var ret = original.apply(this, window.Array.from(arguments));
|
||||
var l = xPixels.length;
|
||||
var rng = randomSupply.getRng(l, window);
|
||||
|
@ -5,6 +5,15 @@
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var scope;
|
||||
if ((typeof exports) !== "undefined"){
|
||||
scope = exports;
|
||||
}
|
||||
else {
|
||||
window.scope.randomSupplies = {};
|
||||
scope = window.scope.randomSupplies;
|
||||
}
|
||||
|
||||
function getDomain(window){
|
||||
if (!window.location.href || window.location.href === "about:blank"){
|
||||
if (window !== window.parent){
|
||||
@ -19,12 +28,14 @@
|
||||
const getPersistentRnd = (function(){
|
||||
var persistentRnd = Object.create(null);
|
||||
|
||||
const {process} = require("sdk/remote/child");
|
||||
process.port.on("canvasBlocker-set-domain-rnd", function(process, {domain, rnd}){
|
||||
persistentRnd[domain] = new Uint8Array(rnd);
|
||||
});
|
||||
process.port.on("canvasBlocker-clear-domain-rnd", function(){
|
||||
persistentRnd = Object.create(null);
|
||||
browser.runtime.onMessage.addListener(function(data){
|
||||
if (data["canvasBlocker-set-domain-rnd"]){
|
||||
var {domain, rnd} = data["canvasBlocker-set-domain-rnd"];
|
||||
persistentRnd[domain] = new Uint8Array(rnd);
|
||||
}
|
||||
if (data["canvasBlocker-clear-domain-rnd"]){
|
||||
persistentRnd = Object.create(null);
|
||||
}
|
||||
});
|
||||
|
||||
return function getPersistentRnd(window){
|
||||
@ -33,12 +44,12 @@
|
||||
// create the (sub-)domains random numbers if not existing
|
||||
persistentRnd[domain] = new Uint8Array(128);
|
||||
window.crypto.getRandomValues(persistentRnd[domain]);
|
||||
process.port.emit("canvasBlocker-new-domain-rnd", {domain, rnd: Array.from(persistentRnd[domain])});
|
||||
browser.runtime.sendMessage({"canvasBlocker-new-domain-rnd": {domain, rnd: Array.from(persistentRnd[domain])}});
|
||||
}
|
||||
return persistentRnd[domain];
|
||||
}
|
||||
}());
|
||||
exports.persistent = {
|
||||
scope.persistent = {
|
||||
getRng: function(length, window){
|
||||
var bitSet = getPersistentRnd(window);
|
||||
|
||||
@ -60,7 +71,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
exports.nonPersistent = {
|
||||
scope.nonPersistent = {
|
||||
getRng: function(length, window){
|
||||
// Initialize the random number batch creation
|
||||
var randomI = 65536;
|
||||
|
56
manifest.json
Normal file
56
manifest.json
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "CanvasBlocker",
|
||||
"title": "__MSG_addon_title__",
|
||||
"id": "CanvasBlocker@kkapsner.de",
|
||||
"keywords": "privacy, canvas, fingerprinting",
|
||||
"description": "__MSG_addon_description__",
|
||||
"homepage": "https://github.com/kkapsner/CanvasBlocker/",
|
||||
"version": "0.4.0-Development",
|
||||
"background": {
|
||||
"scripts": ["lib/main.js"]
|
||||
},
|
||||
"content_scripts": [{
|
||||
"matches": ["<all_urls>"],
|
||||
"all_frames": true,
|
||||
"run_at": "document_start",
|
||||
"js": [
|
||||
"lib/defaultSettings.js",
|
||||
"lib/require.js",
|
||||
|
||||
"lib/modifiedAPI.js",
|
||||
"lib/randomSupplies.js",
|
||||
"lib/intercept.js",
|
||||
|
||||
"lib/callingStack.js",
|
||||
"lib/askForPermission.js",
|
||||
|
||||
"lib/lists.js",
|
||||
"lib/check.js",
|
||||
|
||||
"lib/frame.js"
|
||||
]
|
||||
}],
|
||||
"options_ui": {
|
||||
"browser_style": true,
|
||||
"page": "options/options.html"
|
||||
},
|
||||
"author": "Korbinian Kapsner",
|
||||
"license": "MPL 2.0",
|
||||
"permissions": [
|
||||
"<all_urls>",
|
||||
"storage",
|
||||
"tabs",
|
||||
"activeTab",
|
||||
"declarativeContentScript",
|
||||
"events"
|
||||
],
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "CanvasBlocker@kkapsner.de",
|
||||
"strict_min_version": "50.0"
|
||||
}
|
||||
},
|
||||
"default_locale": "en",
|
||||
"manifest_version": 2
|
||||
}
|
183
package.json
183
package.json
@ -1,183 +0,0 @@
|
||||
{
|
||||
"locales": {
|
||||
"de": {
|
||||
"title": "CanvasBlocker",
|
||||
"description": "Ändert die JS-API zum Ändern von <canvas> um Canvas-Fingerprinting zu verhindern."
|
||||
}
|
||||
},
|
||||
"name": "canvasblocker",
|
||||
"title": "CanvasBlocker",
|
||||
"id": "CanvasBlocker@kkapsner.de",
|
||||
"keywords": "privacy, canvas, fingerprinting",
|
||||
"description": "Changes the JS-API for modifying <canvas> to prevent Canvas-Fingerprinting.",
|
||||
"homepage": "https://github.com/kkapsner/CanvasBlocker/",
|
||||
"preferences": [
|
||||
{
|
||||
"name": "whiteList",
|
||||
"title": "White list",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "blackList",
|
||||
"title": "Black list",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "blockMode",
|
||||
"title": "block mode",
|
||||
"type": "menulist",
|
||||
"value": "fakeReadout",
|
||||
"options": [
|
||||
{
|
||||
"value": "blockReadout",
|
||||
"label": "block readout API"
|
||||
},
|
||||
{
|
||||
"value": "fakeReadout",
|
||||
"label": "fake readout API"
|
||||
},
|
||||
{
|
||||
"value": "fakeInput",
|
||||
"label": "fake input API"
|
||||
},
|
||||
{
|
||||
"value": "askReadout",
|
||||
"label": "ask for readout API permission"
|
||||
},
|
||||
{
|
||||
"value": "",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"value": "blockEverything",
|
||||
"label": "block everything"
|
||||
},
|
||||
{
|
||||
"value": "block",
|
||||
"label": "allow only white list"
|
||||
},
|
||||
{
|
||||
"value": "ask",
|
||||
"label": "ask for permission"
|
||||
},
|
||||
{
|
||||
"value": "allow",
|
||||
"label": "block only black list"
|
||||
},
|
||||
{
|
||||
"value": "allowEverything",
|
||||
"label": "allow everything"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "maxFakeSize",
|
||||
"title": "Maximal fake size",
|
||||
"type": "integer",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "rng",
|
||||
"title": "Random number generator",
|
||||
"type": "menulist",
|
||||
"value": "nonPersistent",
|
||||
"options": [
|
||||
{
|
||||
"value": "nonPersistent",
|
||||
"label": "non persistent"
|
||||
},
|
||||
{
|
||||
"value": "persistent",
|
||||
"label": "persistent"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "persistentRndStorage",
|
||||
"title": "Persistent storage",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "storePersistentRnd",
|
||||
"title": "Store persistent data",
|
||||
"type": "bool",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "clearPersistentRnd",
|
||||
"title": "Clear persistent random storage",
|
||||
"type": "control",
|
||||
"label": "Clear"
|
||||
},
|
||||
{
|
||||
"name": "askOnlyOnce",
|
||||
"title": "Ask only once",
|
||||
"type": "bool",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "showNotifications",
|
||||
"title": "Show notifications",
|
||||
"type": "bool",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "notificationDisplayTime",
|
||||
"title": "notification display time",
|
||||
"type": "integer",
|
||||
"value": 30
|
||||
},
|
||||
{
|
||||
"name": "ignoreList",
|
||||
"title": "Ignore list",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "showCallingFile",
|
||||
"title": "Display calling file",
|
||||
"type": "bool",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "showCompleteCallingStack",
|
||||
"title": "Display complete calling stack",
|
||||
"type": "bool",
|
||||
"value": false
|
||||
},{
|
||||
"name": "enableStackList",
|
||||
"title": "Use file specific scoped white list",
|
||||
"type": "bool",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "stackList",
|
||||
"title": "File specific white list",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "showReleaseNotes",
|
||||
"title": "Release notes",
|
||||
"type": "control",
|
||||
"label": "Show"
|
||||
}
|
||||
],
|
||||
"main": "lib/main.js",
|
||||
"author": "Korbinian Kapsner",
|
||||
"license": "MPL 2.0",
|
||||
"version": "0.4.0-Development",
|
||||
|
||||
"engines": {
|
||||
"firefox": ">=50.0",
|
||||
"fennec": ">=50.0"
|
||||
},
|
||||
"permissions": {
|
||||
"private-browsing": true,
|
||||
"multiprocess": true
|
||||
},
|
||||
"hasEmbeddedWebExtension": true
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
Version 0.4.0:
|
||||
todos:
|
||||
- import settings in content script (have to wait for the new API to register content scripts)
|
||||
- check if webGL is still working
|
||||
changes:
|
||||
-
|
||||
- switched to webExtension
|
||||
|
||||
new features:
|
||||
-
|
||||
|
Loading…
x
Reference in New Issue
Block a user