mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2024-12-22 12:50:36 +01:00
Added container specific navigator settings
This commit is contained in:
parent
01b63b356c
commit
cc8ca147b0
@ -1192,6 +1192,10 @@
|
|||||||
"message": "CAUTION: the actual browser in use cannot be faked entirely as there is a multitude of ways to detect it. E.g. feature tests and browser specific rendering of HTML elements will always leak.",
|
"message": "CAUTION: the actual browser in use cannot be faked entirely as there is a multitude of ways to detect it. E.g. feature tests and browser specific rendering of HTML elements will always leak.",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"navigatorSettings_contextualIdentities": {
|
||||||
|
"message": "Settings for the container {select} are shown.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"navigatorSettings_presetSection.os": {
|
"navigatorSettings_presetSection.os": {
|
||||||
"message": "Operating system presets",
|
"message": "Operating system presets",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
@ -87,6 +87,8 @@
|
|||||||
logging.notice("my tab cookie store id is", data.cookieStoreId);
|
logging.notice("my tab cookie store id is", data.cookieStoreId);
|
||||||
const {persistent: persistentRnd} = require("./randomSupplies");
|
const {persistent: persistentRnd} = require("./randomSupplies");
|
||||||
persistentRnd.setCookieStoreId(data.cookieStoreId);
|
persistentRnd.setCookieStoreId(data.cookieStoreId);
|
||||||
|
const modifiedNavigatorAPI = require("./modifiedNavigatorAPI");
|
||||||
|
modifiedNavigatorAPI.setCookieStoreId(data.cookieStoreId);
|
||||||
}
|
}
|
||||||
const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd";
|
const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd";
|
||||||
if (data.hasOwnProperty(persistentRndName)){
|
if (data.hasOwnProperty(persistentRndName)){
|
||||||
|
@ -13,8 +13,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||||
|
const logging = require("./logging");
|
||||||
const navigator = require("./navigator");
|
const navigator = require("./navigator");
|
||||||
|
|
||||||
|
let cookieStoreId = false;
|
||||||
|
scope.setCookieStoreId = function(newCookieStoreId){
|
||||||
|
if (typeof newCookieStoreId === "string"){
|
||||||
|
cookieStoreId = (
|
||||||
|
newCookieStoreId !== "" &&
|
||||||
|
newCookieStoreId !== "firefox-default"
|
||||||
|
)? newCookieStoreId: "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function getCookieStoreId(){
|
||||||
|
while (cookieStoreId === false){
|
||||||
|
logging.message("Starting synchronous request to wait for cookie store id.");
|
||||||
|
try {
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", "https://[::]", false);
|
||||||
|
xhr.send();
|
||||||
|
xhr = null;
|
||||||
|
}
|
||||||
|
catch (error){
|
||||||
|
logging.verbose("Error in XHR:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieStoreId;
|
||||||
|
}
|
||||||
|
|
||||||
scope.changedGetters = navigator.allProperties.map(function(property){
|
scope.changedGetters = navigator.allProperties.map(function(property){
|
||||||
return {
|
return {
|
||||||
objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}],
|
objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}],
|
||||||
@ -25,7 +51,7 @@
|
|||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
const {notify, original} = check;
|
const {notify, original} = check;
|
||||||
const originalValue = original.call(this, ...args);
|
const originalValue = original.call(this, ...args);
|
||||||
const returnValue = navigator.getNavigatorValue(property);
|
const returnValue = navigator.getNavigatorValue(property, getCookieStoreId);
|
||||||
if (originalValue !== returnValue){
|
if (originalValue !== returnValue){
|
||||||
notify("fakedNavigatorReadout");
|
notify("fakedNavigatorReadout");
|
||||||
}
|
}
|
||||||
|
102
lib/navigator.js
102
lib/navigator.js
@ -36,38 +36,63 @@
|
|||||||
changedValues = newValue;
|
changedValues = newValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getValue = function(){
|
||||||
function getValue(name, stack = []){
|
function getChangedValues(getCookieStoreId){
|
||||||
if (stack.indexOf(name) !== -1){
|
if (changedValues.contextualIdentities){
|
||||||
return "[ERROR: loop in property definition]";
|
const cookieStoreId = getCookieStoreId();
|
||||||
}
|
if (
|
||||||
stack.push(name);
|
cookieStoreId !== "" &&
|
||||||
|
cookieStoreId !== "firefox-default" &&
|
||||||
switch (name){
|
changedValues.contextualIdentities[cookieStoreId]
|
||||||
case "original value":
|
){
|
||||||
return original[stack[stack.length - 2]];
|
return changedValues.contextualIdentities[cookieStoreId];
|
||||||
case "random":
|
|
||||||
return String.fromCharCode(Math.floor(65 + 85 * Math.random()));
|
|
||||||
default:
|
|
||||||
if (changedValues.hasOwnProperty(name)){
|
|
||||||
return parseString(changedValues[name], stack.slice());
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return original[name];
|
return changedValues;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return changedValues;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function parseString(string, stack){
|
return function getValue(name, getCookieStoreId){
|
||||||
if (string === "{undefined}"){
|
const changedValues = getChangedValues(getCookieStoreId);
|
||||||
return undefined;
|
|
||||||
}
|
function getValueInternal(name, stack = []){
|
||||||
return string.replace(/{([a-z[\]_. -]*)}/ig, function(m, name){
|
if (stack.indexOf(name) !== -1){
|
||||||
return getValue(name, stack.slice());
|
return "[ERROR: loop in property definition]";
|
||||||
});
|
}
|
||||||
}
|
stack.push(name);
|
||||||
|
|
||||||
|
switch (name){
|
||||||
|
case "original value":
|
||||||
|
return original[stack[stack.length - 2]];
|
||||||
|
case "random":
|
||||||
|
return String.fromCharCode(Math.floor(65 + 85 * Math.random()));
|
||||||
|
default:
|
||||||
|
if (changedValues.hasOwnProperty(name)){
|
||||||
|
return parseString(changedValues[name], stack.slice());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return original[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function parseString(string, stack){
|
||||||
|
if (string === "{undefined}"){
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return string.replace(/{([a-z[\]_. -]*)}/ig, function(m, name){
|
||||||
|
return getValueInternal(name, stack.slice());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return getValueInternal(name);
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
scope.getNavigatorValue = function getNavigatorValue(name){
|
scope.getNavigatorValue = function getNavigatorValue(name, getCookieStoreId){
|
||||||
return getValue(name);
|
return getValue(name, getCookieStoreId);
|
||||||
};
|
};
|
||||||
|
|
||||||
function changeHTTPHeader(details){
|
function changeHTTPHeader(details){
|
||||||
@ -82,7 +107,9 @@
|
|||||||
){
|
){
|
||||||
for (let header of details.requestHeaders){
|
for (let header of details.requestHeaders){
|
||||||
if (header.name.toLowerCase() === "user-agent"){
|
if (header.name.toLowerCase() === "user-agent"){
|
||||||
header.value = getValue("userAgent");
|
header.value = getValue("userAgent", function(){
|
||||||
|
return details.cookieStoreId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,5 +145,24 @@
|
|||||||
scope.unregisterHeaderChange();
|
scope.unregisterHeaderChange();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (browser.contextualIdentities && browser.contextualIdentities.onRemoved){
|
||||||
|
logging.message("register contextual navigator identities removal");
|
||||||
|
browser.contextualIdentities.onRemoved.addListener(function(details){
|
||||||
|
logging.message("Contextual navigator identity", details.contextualIdentity.cookieStoreId, "removed.");
|
||||||
|
if (changedValues.contextualIdentities){
|
||||||
|
delete changedValues.contextualIdentities[details.contextualIdentity.cookieStoreId];
|
||||||
|
if (Object.keys(changedValues.contextualIdentities).length === 0){
|
||||||
|
delete changedValues.contextualIdentities;
|
||||||
|
}
|
||||||
|
settings.navigatorDetails = changedValues;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logging.error(
|
||||||
|
"Old Firefox does not support browser.contextualIdentities.onRemoved"
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}());
|
}());
|
@ -1,3 +1,8 @@
|
|||||||
|
.contextualIdentities {
|
||||||
|
display: block;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.presetSection ul {
|
.presetSection ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
(function(){
|
(async function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const extension = require("../lib/extension");
|
const extension = require("../lib/extension");
|
||||||
@ -26,6 +26,144 @@
|
|||||||
disclaimer.textContent = extension.getTranslation("navigatorSettings_disclaimer");
|
disclaimer.textContent = extension.getTranslation("navigatorSettings_disclaimer");
|
||||||
document.body.appendChild(disclaimer);
|
document.body.appendChild(disclaimer);
|
||||||
|
|
||||||
|
const navigatorDetails = await async function(){
|
||||||
|
let cookieStoreId = "";
|
||||||
|
if (browser.contextualIdentities){
|
||||||
|
const contextualIdentities = await browser.contextualIdentities.query({});
|
||||||
|
if (contextualIdentities.length){
|
||||||
|
const containerLabel = document.createElement("label");
|
||||||
|
containerLabel.className = "contextualIdentities";
|
||||||
|
containerLabel.appendChild(extension.parseTranslation(
|
||||||
|
extension.getTranslation("navigatorSettings_contextualIdentities"),
|
||||||
|
{
|
||||||
|
select: function(){
|
||||||
|
const contextualIdentitiesSelect = document.createElement("select");
|
||||||
|
contextualIdentitiesSelect.appendChild(new Option("", ""));
|
||||||
|
contextualIdentities.forEach(function(contextualIdentity){
|
||||||
|
contextualIdentitiesSelect.appendChild(new Option(
|
||||||
|
contextualIdentity.name,
|
||||||
|
contextualIdentity.cookieStoreId
|
||||||
|
));
|
||||||
|
});
|
||||||
|
window.addEventListener("load", function(){
|
||||||
|
cookieStoreId = contextualIdentitiesSelect.value;
|
||||||
|
emitUpdate();
|
||||||
|
});
|
||||||
|
contextualIdentitiesSelect.addEventListener("change", function(){
|
||||||
|
cookieStoreId = this.value;
|
||||||
|
emitUpdate();
|
||||||
|
});
|
||||||
|
return contextualIdentitiesSelect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
document.body.appendChild(containerLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const callbacks = [];
|
||||||
|
let baseStorage;
|
||||||
|
let loaded = false;
|
||||||
|
|
||||||
|
function getKeys(object){
|
||||||
|
return Object.keys(object).filter(function(key){
|
||||||
|
return key !== "contextualIdentities";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function storageEqual(storage1, storage2){
|
||||||
|
const keys1 = getKeys(storage1);
|
||||||
|
const keys2 = getKeys(storage2);
|
||||||
|
return keys1.length === keys2.length && keys1.every(function(key){
|
||||||
|
return storage1[key] === storage2[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyData(from, to = {}){
|
||||||
|
getKeys(from).forEach(function(key){
|
||||||
|
to[key] = from[key];
|
||||||
|
});
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStorage(){
|
||||||
|
if (cookieStoreId === ""){
|
||||||
|
return baseStorage;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!baseStorage.contextualIdentities){
|
||||||
|
baseStorage.contextualIdentities = {};
|
||||||
|
}
|
||||||
|
if (!baseStorage.contextualIdentities[cookieStoreId]){
|
||||||
|
baseStorage.contextualIdentities[cookieStoreId] = copyData(baseStorage);
|
||||||
|
}
|
||||||
|
return baseStorage.contextualIdentities[cookieStoreId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.on("navigatorDetails", function({newValue}){
|
||||||
|
baseStorage = newValue;
|
||||||
|
emitUpdate();
|
||||||
|
});
|
||||||
|
settings.onloaded(function(){
|
||||||
|
loaded = true;
|
||||||
|
baseStorage = settings.navigatorDetails;
|
||||||
|
emitUpdate();
|
||||||
|
});
|
||||||
|
function emitUpdate(){
|
||||||
|
if (!loaded){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const storage = getStorage();
|
||||||
|
callbacks.forEach(async function(callback){
|
||||||
|
callback(storage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const api = {
|
||||||
|
get: getStorage,
|
||||||
|
getComputedValue: function getComputedValue(property){
|
||||||
|
return navigator.getNavigatorValue(property, function(){
|
||||||
|
return cookieStoreId;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onUpdate: function onUpdate(callback){
|
||||||
|
callbacks.push(callback);
|
||||||
|
if (loaded){
|
||||||
|
callback(getStorage());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
save: function save(){
|
||||||
|
if (!loaded){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (baseStorage.contextualIdentities){
|
||||||
|
if (Object.keys(baseStorage.contextualIdentities).reduce(function(lastValue, contextualIdentity){
|
||||||
|
if (storageEqual(baseStorage.contextualIdentities[contextualIdentity], baseStorage)){
|
||||||
|
delete baseStorage.contextualIdentities[contextualIdentity];
|
||||||
|
return lastValue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}, true)){
|
||||||
|
delete baseStorage.contextualIdentities;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.navigatorDetails = baseStorage;
|
||||||
|
},
|
||||||
|
reset: function reset(){
|
||||||
|
if (cookieStoreId === ""){
|
||||||
|
baseStorage = baseStorage.contextualIdentities? {
|
||||||
|
contextualIdentities: baseStorage.contextualIdentities
|
||||||
|
}: {};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
baseStorage.contextualIdentities[cookieStoreId] = {};
|
||||||
|
}
|
||||||
|
api.save();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return api;
|
||||||
|
}();
|
||||||
|
|
||||||
function presetSection(title, presets){
|
function presetSection(title, presets){
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
container.className = "presetSection";
|
container.className = "presetSection";
|
||||||
@ -64,15 +202,10 @@
|
|||||||
li.classList.remove("active");
|
li.classList.remove("active");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
settings.on("navigatorDetails", function({newValue}){
|
navigatorDetails.onUpdate(checkActive);
|
||||||
checkActive(newValue);
|
|
||||||
});
|
|
||||||
settings.onloaded(function(){
|
|
||||||
checkActive(settings.navigatorDetails);
|
|
||||||
});
|
|
||||||
|
|
||||||
button.addEventListener("click", function(){
|
button.addEventListener("click", function(){
|
||||||
const data = settings.navigatorDetails;
|
const data = navigatorDetails.get();
|
||||||
Object.keys(presetProperties).forEach(function(property){
|
Object.keys(presetProperties).forEach(function(property){
|
||||||
if (presetProperties[property] === undefined){
|
if (presetProperties[property] === undefined){
|
||||||
delete data[property];
|
delete data[property];
|
||||||
@ -85,7 +218,7 @@
|
|||||||
data[property] = value;
|
data[property] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
settings.navigatorDetails = data;
|
navigatorDetails.save();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -249,11 +382,11 @@
|
|||||||
input.value = currentProperties.hasOwnProperty(property)? currentProperties[property]: "{original value}";
|
input.value = currentProperties.hasOwnProperty(property)? currentProperties[property]: "{original value}";
|
||||||
input.addEventListener("change", function(){
|
input.addEventListener("change", function(){
|
||||||
currentProperties[property] = this.value;
|
currentProperties[property] = this.value;
|
||||||
settings.navigatorDetails = currentProperties;
|
navigatorDetails.save();
|
||||||
});
|
});
|
||||||
|
|
||||||
const computedValue = document.createElement("td");
|
const computedValue = document.createElement("td");
|
||||||
computedValue.textContent = navigator.getNavigatorValue(property);
|
computedValue.textContent = navigatorDetails.getComputedValue(property);
|
||||||
row.appendChild(computedValue);
|
row.appendChild(computedValue);
|
||||||
|
|
||||||
section.appendChild(row);
|
section.appendChild(row);
|
||||||
@ -265,7 +398,8 @@
|
|||||||
valueSection.appendChild(section);
|
valueSection.appendChild(section);
|
||||||
|
|
||||||
Object.keys(currentProperties).filter(function(property){
|
Object.keys(currentProperties).filter(function(property){
|
||||||
return navigator.allProperties.indexOf(property) === -1;
|
return property !== "contextualIdentities" &&
|
||||||
|
navigator.allProperties.indexOf(property) === -1;
|
||||||
}).sort().forEach(createPropertyRow.bind(undefined, section));
|
}).sort().forEach(createPropertyRow.bind(undefined, section));
|
||||||
|
|
||||||
section = document.createElement("tbody");
|
section = document.createElement("tbody");
|
||||||
@ -274,19 +408,11 @@
|
|||||||
|
|
||||||
navigator.allProperties.forEach(createPropertyRow.bind(undefined, section));
|
navigator.allProperties.forEach(createPropertyRow.bind(undefined, section));
|
||||||
}
|
}
|
||||||
|
navigatorDetails.onUpdate(updateValueSection);
|
||||||
settings.on("navigatorDetails", function({newValue}){
|
|
||||||
updateValueSection(newValue);
|
|
||||||
});
|
|
||||||
settings.onloaded(function(){
|
|
||||||
updateValueSection(settings.navigatorDetails);
|
|
||||||
});
|
|
||||||
|
|
||||||
const resetButton = document.createElement("button");
|
const resetButton = document.createElement("button");
|
||||||
resetButton.className = "button";
|
resetButton.className = "button";
|
||||||
resetButton.textContent = extension.getTranslation("navigatorSettings_reset");
|
resetButton.textContent = extension.getTranslation("navigatorSettings_reset");
|
||||||
resetButton.addEventListener("click", function(){
|
resetButton.addEventListener("click", navigatorDetails.reset);
|
||||||
settings.navigatorDetails = {};
|
|
||||||
});
|
|
||||||
document.body.appendChild(resetButton);
|
document.body.appendChild(resetButton);
|
||||||
}());
|
}());
|
@ -4,6 +4,7 @@ Version 1.1:
|
|||||||
|
|
||||||
new features:
|
new features:
|
||||||
- added notice for privacy.resistFingerprinting
|
- added notice for privacy.resistFingerprinting
|
||||||
|
- added container specific navigator settings
|
||||||
|
|
||||||
fixes:
|
fixes:
|
||||||
- error when exporting function with name "top"
|
- error when exporting function with name "top"
|
||||||
|
@ -113,6 +113,10 @@
|
|||||||
{
|
{
|
||||||
"version": "1.1Alpha20192301",
|
"version": "1.1Alpha20192301",
|
||||||
"update_link": "https://canvasblocker.kkapsner.de/versions/canvasblocker_beta-1.1Alpha20192301-an+fx.xpi"
|
"update_link": "https://canvasblocker.kkapsner.de/versions/canvasblocker_beta-1.1Alpha20192301-an+fx.xpi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.1Alpha20192501",
|
||||||
|
"update_link": "https://canvasblocker.kkapsner.de/versions/canvasblocker_beta-1.1Alpha20192501-an+fx.xpi"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user