2019-02-27 23:49:00 +01:00
|
|
|
/* 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";
|
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
let scope;
|
2019-02-27 23:49:00 +01:00
|
|
|
if ((typeof exports) !== "undefined"){
|
|
|
|
scope = exports;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
scope = require.register("./navigator", {});
|
|
|
|
}
|
|
|
|
|
|
|
|
const settings = require("./settings");
|
|
|
|
const logging = require("./logging");
|
2019-05-30 12:43:47 +02:00
|
|
|
const check = require("./check");
|
2019-02-27 23:49:00 +01:00
|
|
|
|
|
|
|
scope.allProperties = [
|
|
|
|
"appCodeName", "appName",
|
|
|
|
"appVersion", "buildID", "oscpu", "platform",
|
|
|
|
"product",
|
|
|
|
"productSub", "userAgent", "vendor", "vendorSub"];
|
|
|
|
const original = {};
|
|
|
|
scope.allProperties.forEach(function(property){
|
|
|
|
original[property] = window.navigator[property];
|
|
|
|
});
|
|
|
|
original["real Firefox version"] = window.navigator.userAgent.replace(/^.+Firefox\//, "");
|
2023-03-18 14:44:44 +01:00
|
|
|
original["real Firefox version - rv"] = window.navigator.userAgent.replace(/^.+; rv:([\d.]+).*$/, "$1");
|
2019-02-27 23:49:00 +01:00
|
|
|
|
|
|
|
let changedValues = {};
|
|
|
|
|
|
|
|
settings.onloaded(function(){
|
|
|
|
changedValues = settings.navigatorDetails;
|
|
|
|
});
|
|
|
|
settings.on("navigatorDetails", function({newValue}){
|
|
|
|
changedValues = newValue;
|
|
|
|
});
|
|
|
|
|
2020-01-25 01:03:05 +01:00
|
|
|
const getValue = function(){
|
|
|
|
function getChangedValues(getCookieStoreId){
|
|
|
|
if (changedValues.contextualIdentities){
|
|
|
|
const cookieStoreId = getCookieStoreId();
|
|
|
|
if (
|
|
|
|
cookieStoreId !== "" &&
|
|
|
|
cookieStoreId !== "firefox-default" &&
|
|
|
|
changedValues.contextualIdentities[cookieStoreId]
|
|
|
|
){
|
|
|
|
return changedValues.contextualIdentities[cookieStoreId];
|
2019-02-27 23:49:00 +01:00
|
|
|
}
|
|
|
|
else {
|
2020-01-25 01:03:05 +01:00
|
|
|
return changedValues;
|
2019-02-27 23:49:00 +01:00
|
|
|
}
|
2020-01-25 01:03:05 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return changedValues;
|
|
|
|
}
|
2019-02-27 23:49:00 +01:00
|
|
|
}
|
2020-01-25 01:03:05 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
};
|
|
|
|
}();
|
2019-02-27 23:49:00 +01:00
|
|
|
|
2020-01-25 01:03:05 +01:00
|
|
|
scope.getNavigatorValue = function getNavigatorValue(name, getCookieStoreId){
|
|
|
|
return getValue(name, getCookieStoreId);
|
2019-02-27 23:49:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
function changeHTTPHeader(details){
|
2019-05-30 12:43:47 +02:00
|
|
|
const url = new URL(details.url);
|
2019-02-27 23:49:00 +01:00
|
|
|
if (
|
2019-05-30 12:43:47 +02:00
|
|
|
settings.get("protectNavigator", url) &&
|
|
|
|
check.check({url}).mode !== "allow" &&
|
2019-02-27 23:49:00 +01:00
|
|
|
(
|
2019-11-25 22:10:31 +01:00
|
|
|
!settings.protectedAPIFeatures.hasOwnProperty("userAgent @ navigator") ||
|
|
|
|
settings.protectedAPIFeatures["userAgent @ navigator"]
|
2019-02-27 23:49:00 +01:00
|
|
|
)
|
|
|
|
){
|
2019-11-28 01:26:35 +01:00
|
|
|
for (let header of details.requestHeaders){
|
2019-02-27 23:49:00 +01:00
|
|
|
if (header.name.toLowerCase() === "user-agent"){
|
2020-01-25 01:03:05 +01:00
|
|
|
header.value = getValue("userAgent", function(){
|
|
|
|
return details.cookieStoreId;
|
|
|
|
});
|
2019-02-27 23:49:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
|
|
|
|
scope.registerHeaderChange = function(){
|
|
|
|
logging.message("Register HTTP header modification for navigator protection.");
|
|
|
|
if (!browser.webRequest.onBeforeSendHeaders.hasListener(changeHTTPHeader)){
|
|
|
|
browser.webRequest.onBeforeSendHeaders.addListener(
|
|
|
|
changeHTTPHeader,
|
|
|
|
{
|
|
|
|
urls: ["<all_urls>"],
|
|
|
|
},
|
|
|
|
["blocking", "requestHeaders"]);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
scope.unregisterHeaderChange = function(){
|
|
|
|
logging.message("Removing header modification for navigator protection.");
|
|
|
|
browser.webRequest.onBeforeSendHeaders.removeListener(changeHTTPHeader);
|
|
|
|
};
|
|
|
|
scope.init = function (){
|
|
|
|
settings.onloaded(function(){
|
|
|
|
if (!settings.protectNavigator){
|
|
|
|
scope.unregisterHeaderChange();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
settings.on("protectNavigator", function({newValue}){
|
|
|
|
if (newValue){
|
|
|
|
scope.registerHeaderChange();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
scope.unregisterHeaderChange();
|
|
|
|
}
|
|
|
|
});
|
2020-01-25 01:03:05 +01:00
|
|
|
|
|
|
|
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"
|
|
|
|
);
|
|
|
|
}
|
2019-02-27 23:49:00 +01:00
|
|
|
};
|
|
|
|
}());
|