Added container specific navigator settings

This commit is contained in:
kkapsner 2020-01-25 01:03:05 +01:00
parent 01b63b356c
commit cc8ca147b0
8 changed files with 265 additions and 51 deletions

View File

@ -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.",
"description": ""
},
"navigatorSettings_contextualIdentities": {
"message": "Settings for the container {select} are shown.",
"description": ""
},
"navigatorSettings_presetSection.os": {
"message": "Operating system presets",
"description": ""

View File

@ -87,6 +87,8 @@
logging.notice("my tab cookie store id is", data.cookieStoreId);
const {persistent: persistentRnd} = require("./randomSupplies");
persistentRnd.setCookieStoreId(data.cookieStoreId);
const modifiedNavigatorAPI = require("./modifiedNavigatorAPI");
modifiedNavigatorAPI.setCookieStoreId(data.cookieStoreId);
}
const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd";
if (data.hasOwnProperty(persistentRndName)){

View File

@ -13,8 +13,34 @@
}
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
const logging = require("./logging");
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){
return {
objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}],
@ -25,7 +51,7 @@
return checkerWrapper(checker, this, arguments, function(args, check){
const {notify, original} = check;
const originalValue = original.call(this, ...args);
const returnValue = navigator.getNavigatorValue(property);
const returnValue = navigator.getNavigatorValue(property, getCookieStoreId);
if (originalValue !== returnValue){
notify("fakedNavigatorReadout");
}

View File

@ -36,38 +36,63 @@
changedValues = newValue;
});
function getValue(name, stack = []){
if (stack.indexOf(name) !== -1){
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());
const getValue = function(){
function getChangedValues(getCookieStoreId){
if (changedValues.contextualIdentities){
const cookieStoreId = getCookieStoreId();
if (
cookieStoreId !== "" &&
cookieStoreId !== "firefox-default" &&
changedValues.contextualIdentities[cookieStoreId]
){
return changedValues.contextualIdentities[cookieStoreId];
}
else {
return original[name];
return changedValues;
}
}
else {
return changedValues;
}
}
}
function parseString(string, stack){
if (string === "{undefined}"){
return undefined;
}
return string.replace(/{([a-z[\]_. -]*)}/ig, function(m, name){
return getValue(name, stack.slice());
});
}
return function getValue(name, getCookieStoreId){
const changedValues = getChangedValues(getCookieStoreId);
function getValueInternal(name, stack = []){
if (stack.indexOf(name) !== -1){
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){
return getValue(name);
scope.getNavigatorValue = function getNavigatorValue(name, getCookieStoreId){
return getValue(name, getCookieStoreId);
};
function changeHTTPHeader(details){
@ -82,7 +107,9 @@
){
for (let header of details.requestHeaders){
if (header.name.toLowerCase() === "user-agent"){
header.value = getValue("userAgent");
header.value = getValue("userAgent", function(){
return details.cookieStoreId;
});
}
}
}
@ -118,5 +145,24 @@
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"
);
}
};
}());

View File

@ -1,3 +1,8 @@
.contextualIdentities {
display: block;
margin: 0.5em 0;
}
.presetSection ul {
list-style-type: none;
padding: 0;

View File

@ -1,7 +1,7 @@
/* 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(){
(async function(){
"use strict";
const extension = require("../lib/extension");
@ -26,6 +26,144 @@
disclaimer.textContent = extension.getTranslation("navigatorSettings_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){
const container = document.createElement("div");
container.className = "presetSection";
@ -64,15 +202,10 @@
li.classList.remove("active");
}
}
settings.on("navigatorDetails", function({newValue}){
checkActive(newValue);
});
settings.onloaded(function(){
checkActive(settings.navigatorDetails);
});
navigatorDetails.onUpdate(checkActive);
button.addEventListener("click", function(){
const data = settings.navigatorDetails;
const data = navigatorDetails.get();
Object.keys(presetProperties).forEach(function(property){
if (presetProperties[property] === undefined){
delete data[property];
@ -85,7 +218,7 @@
data[property] = value;
}
});
settings.navigatorDetails = data;
navigatorDetails.save();
});
});
@ -249,11 +382,11 @@
input.value = currentProperties.hasOwnProperty(property)? currentProperties[property]: "{original value}";
input.addEventListener("change", function(){
currentProperties[property] = this.value;
settings.navigatorDetails = currentProperties;
navigatorDetails.save();
});
const computedValue = document.createElement("td");
computedValue.textContent = navigator.getNavigatorValue(property);
computedValue.textContent = navigatorDetails.getComputedValue(property);
row.appendChild(computedValue);
section.appendChild(row);
@ -265,7 +398,8 @@
valueSection.appendChild(section);
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));
section = document.createElement("tbody");
@ -274,19 +408,11 @@
navigator.allProperties.forEach(createPropertyRow.bind(undefined, section));
}
settings.on("navigatorDetails", function({newValue}){
updateValueSection(newValue);
});
settings.onloaded(function(){
updateValueSection(settings.navigatorDetails);
});
navigatorDetails.onUpdate(updateValueSection);
const resetButton = document.createElement("button");
resetButton.className = "button";
resetButton.textContent = extension.getTranslation("navigatorSettings_reset");
resetButton.addEventListener("click", function(){
settings.navigatorDetails = {};
});
resetButton.addEventListener("click", navigatorDetails.reset);
document.body.appendChild(resetButton);
}());

View File

@ -4,6 +4,7 @@ Version 1.1:
new features:
- added notice for privacy.resistFingerprinting
- added container specific navigator settings
fixes:
- error when exporting function with name "top"

View File

@ -113,6 +113,10 @@
{
"version": "1.1Alpha20192301",
"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"
}
]
}