1157 lines
36 KiB
JavaScript
1157 lines
36 KiB
JavaScript
/** \file
|
|
* \brief Operations and data structures connected to protection levels
|
|
*
|
|
* \author Copyright (C) 2019-2021 Libor Polcak
|
|
* \author Copyright (C) 2019 Martin Timko
|
|
* \author Copyright (C) 2021 Matus Svancar
|
|
* \author Copyright (C) 2022 Marek Salon
|
|
* \author Copyright (C) 2022 Martin Bednar
|
|
* \author Copyright (C) 2023 Martin Zmitko
|
|
*
|
|
* \license SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
/**
|
|
* Wrapping groups
|
|
*
|
|
* Used to control the built-in levels and GUI (e.g. level tweaks).
|
|
*/
|
|
var wrapping_groups = {
|
|
empty_level: { /// Automatically populated
|
|
level_text: "",
|
|
level_id: "",
|
|
level_description: "",
|
|
},
|
|
group_map: {}, ///Automatically populated
|
|
wrapper_map: {}, ///Automatically populated
|
|
group_names: [], ///Automatically populated
|
|
get_wrappers: function(level) {
|
|
wrappers = [];
|
|
for (group of wrapping_groups.groups) {
|
|
if ((level[group.id] !== undefined) && level[group.id] !== 0) {
|
|
let arg_values = group.params[level[group.id] - 1].config;
|
|
group.wrappers.forEach((w) => wrappers.push([w, ...arg_values]));
|
|
}
|
|
}
|
|
return wrappers;
|
|
},
|
|
groups: [
|
|
{
|
|
name: "time_precision",
|
|
label: browser.i18n.getMessage("jssgroupTimePrecision"),
|
|
description: browser.i18n.getMessage("jssgroupTimePrecision"),
|
|
description2: [browser.i18n.getMessage("jssgroupTimePrecisionDescription2", browser.i18n.getMessage("jssgroupPhysicalLocationGeolocation"))],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupPoor"),
|
|
description: browser.i18n.getMessage("jssgroupTimePoorDescription"),
|
|
config: [10, false],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLow"),
|
|
description: browser.i18n.getMessage("jssgroupTimeLowDescription"),
|
|
config: [100, false],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupHigh"),
|
|
description: browser.i18n.getMessage("jssgroupTimeHighDescription"),
|
|
config: [1000, true],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// HRT
|
|
"Performance.prototype.now",
|
|
// PT2
|
|
"PerformanceEntry.prototype",
|
|
// ECMA
|
|
"window.Date",
|
|
// TEMPORAL
|
|
"Temporal.Now.instant",
|
|
// DOM
|
|
"Event.prototype.timeStamp",
|
|
// GP
|
|
"Gamepad.prototype.timestamp",
|
|
// VR
|
|
"VRFrameData.prototype.timestamp",
|
|
// SENSOR
|
|
"Sensor.prototype.timestamp",
|
|
],
|
|
},
|
|
{
|
|
name: "htmlcanvaselement",
|
|
label: browser.i18n.getMessage("jssgroupLocallyRenderedImages"),
|
|
description: browser.i18n.getMessage("jssgroupLocallyRenderedImagesDescription"),
|
|
description2: [
|
|
browser.i18n.getMessage("jssgroupCanvasLocallyRenderedImagesDescription2"),
|
|
browser.i18n.getMessage("jssgroupCanvasLocallyRenderedImagesDescription3")
|
|
],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLittleLies"),
|
|
description: browser.i18n.getMessage("jssgroupLocallyRenderedImagesLittleLiesDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupLocallyRenderedImagesStrictDescription"),
|
|
config: [1],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// H-C
|
|
"CanvasRenderingContext2D.prototype.getImageData",
|
|
"HTMLCanvasElement.prototype.toBlob",
|
|
"HTMLCanvasElement.prototype.toDataURL",
|
|
"OffscreenCanvas.prototype.convertToBlob",
|
|
"CanvasRenderingContext2D.prototype.isPointInStroke",
|
|
"CanvasRenderingContext2D.prototype.isPointInPath",
|
|
"WebGLRenderingContext.prototype.readPixels",
|
|
"WebGL2RenderingContext.prototype.readPixels",
|
|
],
|
|
},
|
|
{
|
|
name: "audiobuffer",
|
|
label: browser.i18n.getMessage("jssgroupLocallyGeneratedAudio"),
|
|
description: browser.i18n.getMessage("jssgroupLocallyGeneratedAudioDescription"),
|
|
description2: [
|
|
browser.i18n.getMessage("jssgroupLocallyGeneratedAudioDescription2"),
|
|
],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLittleLies"),
|
|
description: browser.i18n.getMessage("jssgroupLocallyGeneratedAudioLittleLiesDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupLocallyGeneratedAudioStrictDescription"),
|
|
config: [1],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// AUDIO
|
|
"AudioBuffer.prototype.getChannelData",
|
|
"AudioBuffer.prototype.copyFromChannel",
|
|
"AnalyserNode.prototype.getByteTimeDomainData",
|
|
"AnalyserNode.prototype.getFloatTimeDomainData",
|
|
"AnalyserNode.prototype.getByteFrequencyData",
|
|
"AnalyserNode.prototype.getFloatFrequencyData"
|
|
],
|
|
},
|
|
{
|
|
name: "webgl",
|
|
label: browser.i18n.getMessage("jssgroupGraphicCardInformation"),
|
|
description: browser.i18n.getMessage("jssgroupGraphicCardInformationDescription"),
|
|
description2: [
|
|
browser.i18n.getMessage("jssgroupGraphicCardInformationDescription2"),
|
|
browser.i18n.getMessage("jssgroupGraphicCardInformationDescription3"),
|
|
],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLittleLies"),
|
|
description: browser.i18n.getMessage("jssgroupGraphicCardInformationLittleLiesDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupGraphicCardInformationStrictDescription"),
|
|
config: [1],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// WEBGL
|
|
"WebGLRenderingContext.prototype.getParameter",
|
|
"WebGL2RenderingContext.prototype.getParameter",
|
|
"WebGLRenderingContext.prototype.getFramebufferAttachmentParameter",
|
|
"WebGL2RenderingContext.prototype.getFramebufferAttachmentParameter",
|
|
"WebGLRenderingContext.prototype.getActiveAttrib",
|
|
"WebGL2RenderingContext.prototype.getActiveAttrib",
|
|
"WebGLRenderingContext.prototype.getActiveUniform",
|
|
"WebGL2RenderingContext.prototype.getActiveUniform",
|
|
"WebGLRenderingContext.prototype.getAttribLocation",
|
|
"WebGL2RenderingContext.prototype.getAttribLocation",
|
|
"WebGLRenderingContext.prototype.getBufferParameter",
|
|
"WebGL2RenderingContext.prototype.getBufferParameter",
|
|
"WebGLRenderingContext.prototype.getProgramParameter",
|
|
"WebGL2RenderingContext.prototype.getProgramParameter",
|
|
"WebGLRenderingContext.prototype.getRenderbufferParameter",
|
|
"WebGL2RenderingContext.prototype.getRenderbufferParameter",
|
|
"WebGLRenderingContext.prototype.getShaderParameter",
|
|
"WebGL2RenderingContext.prototype.getShaderParameter",
|
|
"WebGLRenderingContext.prototype.getShaderPrecisionFormat",
|
|
"WebGL2RenderingContext.prototype.getShaderPrecisionFormat",
|
|
"WebGLRenderingContext.prototype.getTexParameter",
|
|
"WebGL2RenderingContext.prototype.getTexParameter",
|
|
"WebGLRenderingContext.prototype.getUniformLocation",
|
|
"WebGL2RenderingContext.prototype.getUniformLocation",
|
|
"WebGLRenderingContext.prototype.getVertexAttribOffset",
|
|
"WebGL2RenderingContext.prototype.getVertexAttribOffset",
|
|
"WebGLRenderingContext.prototype.getSupportedExtensions",
|
|
"WebGL2RenderingContext.prototype.getSupportedExtensions",
|
|
"WebGLRenderingContext.prototype.getExtension",
|
|
"WebGL2RenderingContext.prototype.getExtension",
|
|
],
|
|
},
|
|
{
|
|
name: "plugins",
|
|
label: browser.i18n.getMessage("jssgroupInstalledBrowserPlugins"),
|
|
description: browser.i18n.getMessage("jssgroupInstalledBrowserPluginsDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupInstalledBrowserPluginsDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLittleLies"),
|
|
description: browser.i18n.getMessage("jssgroupInstalledBrowserPluginsLittleLiesDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupFake"),
|
|
description: browser.i18n.getMessage("jssgroupInstalledBrowserPluginsFakeDescription"),
|
|
config: [1],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupInstalledBrowserPluginsStrictDescription"),
|
|
config: [2],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// NP
|
|
"Navigator.prototype.plugins", // also modifies "Navigator.prototype.mimeTypes",
|
|
],
|
|
},
|
|
{
|
|
name: "enumerateDevices",
|
|
label: browser.i18n.getMessage("jssgroupConnectedCamerasAndMicrophones"),
|
|
description: browser.i18n.getMessage("jssgroupConnectedCamerasAndMicrophonesDescription"),
|
|
description2: [
|
|
browser.i18n.getMessage("jssgroupConnectedCamerasAndMicrophonesDescription2"),
|
|
],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLittleLies"),
|
|
description: browser.i18n.getMessage("jssgroupConnectedCamerasAndMicrophonesLittleLiesDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupAddFake"),
|
|
description: browser.i18n.getMessage("jssgroupConnectedCamerasAndMicrophonesAddFakeDescription"),
|
|
config: [1],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupConnectedCamerasAndMicrophonesStrictDescription"),
|
|
config: [2],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// MCS
|
|
"MediaDevices.prototype.enumerateDevices",
|
|
],
|
|
},
|
|
{
|
|
name: "hardware",
|
|
label: browser.i18n.getMessage("jssgroupHardware"),
|
|
description: browser.i18n.getMessage("jssgroupHardwareDescription"),
|
|
description2: [
|
|
browser.i18n.getMessage("jssgroupHardwareDescription2"),
|
|
],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLow"),
|
|
description: browser.i18n.getMessage("jssgroupHardwareLowDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupMedium"),
|
|
description: browser.i18n.getMessage("jssgroupHardwareMediumDescription"),
|
|
config: [1],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupHigh"),
|
|
description: browser.i18n.getMessage("jssgroupHardwareHighDescription"),
|
|
config: [2],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// HTML-LS
|
|
"Navigator.prototype.hardwareConcurrency",
|
|
// DM
|
|
"Navigator.prototype.deviceMemory",
|
|
],
|
|
},
|
|
{
|
|
name: "net",
|
|
label: browser.i18n.getMessage("jssgroupNetworkConditions"),
|
|
description: browser.i18n.getMessage("jssgroupNetworkConditionsDescription"),
|
|
description2: [],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupRemove"),
|
|
description: browser.i18n.getMessage("jssgroupNetworkConditionsRemoveDescription"),
|
|
config: [0],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// NET
|
|
"Navigator.prototype.connection",
|
|
"window.NetworkInformation",
|
|
],
|
|
},
|
|
{
|
|
name: "xhr",
|
|
label: browser.i18n.getMessage("jssgroupXMLHttpRequestRequests"),
|
|
description: browser.i18n.getMessage("jssgroupXMLHttpRequestRequestsDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupXMLHttpRequestRequestsDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupAsk"),
|
|
description: browser.i18n.getMessage("jssgroupXMLHttpRequestRequestsAskDescription"),
|
|
config: [false, true],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupBlock"),
|
|
description: browser.i18n.getMessage("jssgroupXMLHttpRequestRequestsBlockDescription"),
|
|
config: [true, false],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// AJAX
|
|
"XMLHttpRequest.prototype.open",
|
|
"XMLHttpRequest.prototype.send",
|
|
],
|
|
},
|
|
{
|
|
name: "arrays",
|
|
label: browser.i18n.getMessage("jssgroupArrays"),
|
|
description: browser.i18n.getMessage("jssgroupArraysDescription"),
|
|
description2: [],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupArraysShift"),
|
|
description: browser.i18n.getMessage("jssgroupArraysShiftDescription"),
|
|
config: [false],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupArraysRandomize"),
|
|
description: browser.i18n.getMessage("jssgroupArraysRandomizeDescription"),
|
|
config: [true],
|
|
},
|
|
],
|
|
wrappers: [
|
|
"window.DataView",
|
|
"window.Uint8Array",
|
|
"window.Int8Array",
|
|
"window.Uint8ClampedArray",
|
|
"window.Int16Array",
|
|
"window.Uint16Array",
|
|
"window.Int32Array",
|
|
"window.Uint32Array",
|
|
"window.Float32Array",
|
|
"window.Float64Array",
|
|
'window.BigInt64Array',
|
|
'window.BigUint64Array',
|
|
],
|
|
},
|
|
{
|
|
name: "shared_array",
|
|
label: browser.i18n.getMessage("jssgroupSharedArraysBuffer"),
|
|
description: browser.i18n.getMessage("jssgroupSharedArraysBufferDescription"),
|
|
description2: [],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupMedium"),
|
|
description: browser.i18n.getMessage("jssgroupSharedArraysBufferMediumDescription"),
|
|
config: [false],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupSharedArraysBufferStrictDescription"),
|
|
config: [true],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// SHARED
|
|
"window.SharedArrayBuffer"
|
|
],
|
|
},
|
|
{
|
|
name: "webworker",
|
|
label: browser.i18n.getMessage("jssgroupWebWorker"),
|
|
description: browser.i18n.getMessage("jssgroupWebWorkerDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupWebWorkerDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLow"),
|
|
description: browser.i18n.getMessage("jssgroupWebWorkerLowDescription"),
|
|
config: [false, false],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupWebWorkerStrictDescription"),
|
|
config: [true, false],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupRemove"),
|
|
description: browser.i18n.getMessage("jssgroupWebWorkerRemoveDescription"),
|
|
config: [false, true],
|
|
},
|
|
],
|
|
wrappers: [
|
|
"window.Worker",
|
|
],
|
|
},
|
|
{
|
|
name: "geolocation",
|
|
label: browser.i18n.getMessage("jssgroupPhysicalLocationGeolocation"),
|
|
description: browser.i18n.getMessage("jssgroupPhysicalLocationGeolocationDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupPhysicalLocationGeolocationDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupGeolocationTimestampOnly"),
|
|
description: browser.i18n.getMessage("jssgroupGeolocationTimestampOnlyDescription", browser.i18n.getMessage("jssgroupTimePrecision")),
|
|
config: [-1],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupGeolocationVillage"),
|
|
description: browser.i18n.getMessage("jssgroupGeolocationVillageDescription"),
|
|
config: [2],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupGeolocationTown"),
|
|
description: browser.i18n.getMessage("jssgroupGeolocationTownDescription"),
|
|
config: [3],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupGeolocationRegion"),
|
|
description: browser.i18n.getMessage("jssgroupGeolocationRegionDescription"),
|
|
config: [4],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupGeolocationLongDistance"),
|
|
description: browser.i18n.getMessage("jssgroupGeolocationLongDistanceDescription"),
|
|
config: [5],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupRemove"),
|
|
description: browser.i18n.getMessage("jssgroupGeolocationRemoveDescription"),
|
|
config: [0],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// GPS
|
|
"Navigator.prototype.geolocation",
|
|
"window.Geolocation",
|
|
"window.GeolocationCoordinates",
|
|
"window.GeolocationPosition",
|
|
"window.GeolocationPositionError",
|
|
"Geolocation.prototype.getCurrentPosition",
|
|
"Geolocation.prototype.watchPosition",
|
|
"Geolocation.prototype.clearWatch"
|
|
],
|
|
},
|
|
{
|
|
name: "physical_environment",
|
|
label: browser.i18n.getMessage("jssgroupPhysicalEnvironmentSensors"),
|
|
description: browser.i18n.getMessage("jssgroupPhysicalEnvironmentSensorsDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupPhysicalEnvironmentSensorsDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupHigh"),
|
|
description: browser.i18n.getMessage("jssgroupPhysicalEnvironmentSensorsHighDescription"),
|
|
config: [true],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// GENERIC SENSOR API Sensors
|
|
|
|
// Magnetometer
|
|
"Magnetometer.prototype.x",
|
|
"Magnetometer.prototype.y",
|
|
"Magnetometer.prototype.z",
|
|
|
|
// Accelerometer, LinearAccelerationSensor, and GravitySensor
|
|
"Accelerometer.prototype.x",
|
|
"Accelerometer.prototype.y",
|
|
"Accelerometer.prototype.z",
|
|
|
|
// Gyroscope
|
|
"Gyroscope.prototype.x",
|
|
"Gyroscope.prototype.y",
|
|
"Gyroscope.prototype.z",
|
|
|
|
// AbsoluteOrientationSensor and RelativeOrientationSensor
|
|
"OrientationSensor.prototype.quaternion",
|
|
|
|
// AmbientLightSensor
|
|
"AmbientLightSensor.prototype.illuminance"
|
|
],
|
|
},
|
|
{
|
|
name: "useridle",
|
|
label: browser.i18n.getMessage("jssgroupUserIdleDetection"),
|
|
description: browser.i18n.getMessage("jssgroupUserIdleDetectionDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupUserIdleDetectionDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupConfuse"),
|
|
description: browser.i18n.getMessage("jssgroupConfuseDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupBlock"),
|
|
description: browser.i18n.getMessage("jssgroupBlockDescription"),
|
|
config: [1],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupRemove"),
|
|
description: browser.i18n.getMessage("jssgroupRemoveDescription"),
|
|
config: [2],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// COOP-SCHEDULING
|
|
"window.IdleDetector",
|
|
"IdleDetector.requestPermission",
|
|
"IdleDetector.prototype.screenState",
|
|
"IdleDetector.prototype.userState",
|
|
],
|
|
},
|
|
{
|
|
name: "coopschedule",
|
|
label: browser.i18n.getMessage("jssgroupCoopschedule"),
|
|
description: browser.i18n.getMessage("jssgroupCoopscheduleDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupCoopscheduleDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupConfuse"),
|
|
description: browser.i18n.getMessage("jssgroupCoopscheduleConfuseDescription"),
|
|
config: [],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// COOP-SCHEDULING
|
|
"IdleDeadline.prototype.didTimeout",
|
|
"IdleDeadline.prototype.timeRemaining",
|
|
],
|
|
},
|
|
{
|
|
name: "gamepads",
|
|
label: browser.i18n.getMessage("jssgroupGamepads"),
|
|
description: browser.i18n.getMessage("jssgroupGamepadsDescription"),
|
|
description2: [],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupGamepadsStrictDescription"),
|
|
config: [true],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// GAMEPAD
|
|
"Navigator.prototype.getGamepads",
|
|
],
|
|
},
|
|
{
|
|
name: "vr",
|
|
label: browser.i18n.getMessage("jssgroupVirtualAndAugmentedRealityDevices"),
|
|
description: browser.i18n.getMessage("jssgroupVirtualAndAugmentedRealityDevicesDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupVirtualAndAugmentedRealityDevicesDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupVirtualAndAugmentedRealityDevicesStrictDescription"),
|
|
config: [],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// VR
|
|
"Navigator.prototype.activeVRDisplays",
|
|
// XR
|
|
"Navigator.prototype.xr",
|
|
],
|
|
},
|
|
{
|
|
name: "playback",
|
|
label: browser.i18n.getMessage("jssgroupMultimediaPlayback"),
|
|
description: browser.i18n.getMessage("jssgroupMultimediaPlaybackDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupMultimediaPlaybackDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupLittleLies"),
|
|
description: browser.i18n.getMessage("jssgroupMultimediaPlaybackLittleLiesDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupMultimediaPlaybackStrictDescription"),
|
|
config: [1],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupBlock"),
|
|
description: browser.i18n.getMessage("jssgroupMultimediaPlaybackBlockDescription"),
|
|
config: [2],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// EME
|
|
"Navigator.prototype.requestMediaKeySystemAccess",
|
|
// MEDIA-CAPABILITIES
|
|
"MediaCapabilities.prototype.encodingInfo",
|
|
"MediaCapabilities.prototype.decodingInfo",
|
|
// HTML5
|
|
"HTMLMediaElement.prototype.canPlayType",
|
|
],
|
|
},
|
|
{
|
|
name: "analytics",
|
|
label: browser.i18n.getMessage("jssgroupUnreliableTransfersToServerBeacons"),
|
|
description: browser.i18n.getMessage("jssgroupUnreliableTransfersToServerBeaconsDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupUnreliableTransfersToServerBeaconsDescription2"), browser.i18n.getMessage("jssgroupUnreliableTransfersToServerBeaconsDescription3")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupBlock"),
|
|
description: browser.i18n.getMessage("jssgroupUnreliableTransfersToServerBeaconsBlockDescription"),
|
|
config: [],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// BEACON
|
|
"Navigator.prototype.sendBeacon",
|
|
],
|
|
},
|
|
{
|
|
name: "battery",
|
|
label: browser.i18n.getMessage("jssgroupHardwareBattery"),
|
|
description: browser.i18n.getMessage("jssgroupHardwareBatteryDescription"),
|
|
description2: [],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupRemove"),
|
|
description: browser.i18n.getMessage("jssgroupHardwareBatteryRemoveDescription"),
|
|
config: [],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// BATTERY
|
|
"Navigator.prototype.getBattery",
|
|
"window.BatteryManager",
|
|
],
|
|
},
|
|
{
|
|
name: "windowname",
|
|
label: browser.i18n.getMessage("jssgroupPersistentIdentifierOfTheBrowserTab"),
|
|
description: browser.i18n.getMessage("jssgroupPersistentIdentifierOfTheBrowserTabDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupPersistentIdentifierOfTheBrowserTabDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupStrict"),
|
|
description: browser.i18n.getMessage("jssgroupPersistentIdentifierOfTheBrowserTabStrictDescription"),
|
|
config: [],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// WINDOW-NAME
|
|
"window.name",
|
|
],
|
|
},
|
|
{
|
|
name: "nfc",
|
|
label: browser.i18n.getMessage("jssgroupNFC"),
|
|
description: browser.i18n.getMessage("jssgroupNFCDescription"),
|
|
description2: [browser.i18n.getMessage("jssgroupNFCDescription2")],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupRemove"),
|
|
description: browser.i18n.getMessage("jssgroupNFCRemoveDescription"),
|
|
config: [],
|
|
},
|
|
],
|
|
wrappers: [
|
|
// BATTERY
|
|
"window.NDEFMessage",
|
|
"window.NDEFReader",
|
|
"window.NDEFRecord",
|
|
],
|
|
},
|
|
{
|
|
name: "wasm",
|
|
label: browser.i18n.getMessage("jssgroupWASM"),
|
|
description: browser.i18n.getMessage("jssgroupWASMDescription"),
|
|
description2: [
|
|
browser.i18n.getMessage("jssgroupWASMDescription2", [browser.i18n.getMessage("jssgroupLocallyRenderedImages"), browser.i18n.getMessage("jssgroupLocallyGeneratedAudio"), browser.i18n.getMessage("jssgroupLittleLies")]),
|
|
browser.i18n.getMessage("jssgroupWASMDescription3"),
|
|
],
|
|
params: [
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupWASMDisabled"),
|
|
description: browser.i18n.getMessage("jssgroupWASMDisabledDescription"),
|
|
config: [0],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupWASMPassive"),
|
|
description: browser.i18n.getMessage("jssgroupWASMPassiveDescription"),
|
|
config: [1],
|
|
},
|
|
{
|
|
short: browser.i18n.getMessage("jssgroupWASMActive"),
|
|
description: browser.i18n.getMessage("jssgroupWASMActiveDescription"),
|
|
description2: [
|
|
"jssgroupWASMActiveDescription2","jssgroupWASMActiveDescription3","jssgroupWASMActiveDescription4"
|
|
],
|
|
config: [2],
|
|
},
|
|
],
|
|
wrappers: [], // Special case with no wrappers, this group is for modifying htmlcanvaselement, webgl and audiobuffer farbling behaviour
|
|
},
|
|
],
|
|
}
|
|
var modify_wrapping_groups = modify_wrapping_groups || (() => null); // Give other scripts the possibility to modify the wrapping_groups objects
|
|
modify_wrapping_groups();
|
|
|
|
/**
|
|
* Check if the given API is supported by the browser
|
|
* @param String to the object which presence to check.
|
|
*/
|
|
function is_api_undefined(api) {
|
|
if (!self.window) return false; // mv3 service worker?
|
|
let s = api.split(".");
|
|
let last = self;
|
|
for (p of s) {
|
|
try {
|
|
if (last[p] === undefined) {
|
|
return true;
|
|
}
|
|
}
|
|
catch (e) {
|
|
// We may have encountered something like
|
|
// TypeError: 'get startTime' called on an object that does not implement interface PerformanceEntry.
|
|
break;
|
|
}
|
|
last = last[p];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true if all given API wrappers are unsuported.
|
|
*/
|
|
function are_all_api_unsupported(wrappers) {
|
|
for (wrapper of wrappers) {
|
|
if (!is_api_undefined(wrapper)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// Automatically populate infered metadata in wrapping_groups.
|
|
wrapping_groups.groups.forEach(function (group) {
|
|
group.id = group.name;
|
|
if (!are_all_api_unsupported(group.wrappers) || group.wrappers.length === 0) {
|
|
wrapping_groups.group_names.push(group.name);
|
|
wrapping_groups.empty_level[group.id] = 0;
|
|
}
|
|
wrapping_groups.group_map[group.id] = group
|
|
for (wrapper_name of group.wrappers) {
|
|
wrapping_groups.wrapper_map[wrapper_name] = group.name;
|
|
}
|
|
});
|
|
|
|
// *****************************************************************************
|
|
// levels of protection
|
|
|
|
// Level aliases
|
|
const L0 = "0";
|
|
const L1 = "1";
|
|
const L2 = "2";
|
|
const L3 = "3";
|
|
const L_EXPERIMENTAL = "Experiment"; // Use a long ID so that it is not in conflict with pre0.7 user-defined levels
|
|
|
|
/// Built-in levels
|
|
var level_0 = {
|
|
"builtin": true,
|
|
"level_id": L0,
|
|
"level_text": browser.i18n.getMessage("JSSL0Name"),
|
|
"level_description": browser.i18n.getMessage("JSSL0Description"),
|
|
};
|
|
|
|
var level_1 = {
|
|
"builtin": true,
|
|
"level_id": L1,
|
|
"level_text": browser.i18n.getMessage("JSSL1Name"),
|
|
"level_description": browser.i18n.getMessage("JSSL1Description"),
|
|
"time_precision": 3,
|
|
"net": 1,
|
|
"webworker": 3,
|
|
"geolocation": 3,
|
|
"physical_environment": 1,
|
|
"useridle": 1,
|
|
"coopschedule": 1,
|
|
"gamepads": 1,
|
|
"vr": 1,
|
|
"analytics": 1,
|
|
"battery": 1,
|
|
"nfc": 1,
|
|
};
|
|
|
|
var level_2 = {
|
|
"builtin": true,
|
|
"level_id": L2,
|
|
"level_text": browser.i18n.getMessage("JSSL2Name"),
|
|
"level_description": browser.i18n.getMessage("JSSL2Description"),
|
|
"time_precision": 3,
|
|
"htmlcanvaselement": 1,
|
|
"audiobuffer": 1,
|
|
"webgl": 1,
|
|
"plugins": 2,
|
|
"enumerateDevices": 2,
|
|
"hardware": 1,
|
|
"net": 1,
|
|
"webworker": 3,
|
|
"geolocation": 3,
|
|
"physical_environment": 1,
|
|
"useridle": 2,
|
|
"coopschedule": 1,
|
|
"gamepads": 1,
|
|
"vr": 1,
|
|
"analytics": 1,
|
|
"battery": 1,
|
|
"windowname": 1,
|
|
"nfc": 1,
|
|
"wasm": 1,
|
|
};
|
|
|
|
var level_3 = {
|
|
"builtin": true,
|
|
"level_id": L3,
|
|
"level_text": browser.i18n.getMessage("JSSL3Name"),
|
|
"level_description": browser.i18n.getMessage("JSSL3Description"),
|
|
"time_precision": 3,
|
|
"htmlcanvaselement": 2,
|
|
"audiobuffer": 2,
|
|
"webgl": 2,
|
|
"plugins": 3,
|
|
"enumerateDevices": 3,
|
|
"hardware": 3,
|
|
"net": 1,
|
|
"webworker": 3,
|
|
"geolocation": 6,
|
|
"physical_environment": 1,
|
|
"useridle": 3,
|
|
"coopschedule": 1,
|
|
"gamepads": 1,
|
|
"vr": 1,
|
|
"playback": 2,
|
|
"analytics": 1,
|
|
"battery": 1,
|
|
"windowname": 1,
|
|
"nfc": 1,
|
|
};
|
|
|
|
var level_experimental = {
|
|
"builtin": true,
|
|
"level_id": L_EXPERIMENTAL,
|
|
"level_text": browser.i18n.getMessage("JSSLexperimentalName"),
|
|
"level_description": browser.i18n.getMessage("JSSLexperimentalDescription"),
|
|
"time_precision": 3,
|
|
"htmlcanvaselement": 2,
|
|
"audiobuffer": 2,
|
|
"webgl": 2,
|
|
"plugins": 3,
|
|
"enumerateDevices": 3,
|
|
"hardware": 3,
|
|
"net": 1,
|
|
"xhr": 1,
|
|
"arrays": 2,
|
|
"shared_array": 2,
|
|
"webworker": 2,
|
|
"geolocation": 6,
|
|
"physical_environment": 1,
|
|
"useridle": 3,
|
|
"coopschedule": 1,
|
|
"gamepads": 1,
|
|
"vr": 1,
|
|
"playback": 3,
|
|
"analytics": 1,
|
|
"battery": 1,
|
|
"windowname": 1,
|
|
"nfc": 1,
|
|
};
|
|
|
|
var modify_builtin_levels = modify_builtin_levels || (() => null); // Give other scripts the possibility to modify builtin levels
|
|
modify_builtin_levels();
|
|
|
|
var levels = {};
|
|
var default_level = {};
|
|
var domains = {};
|
|
function init_levels() {
|
|
levels = {
|
|
[level_0.level_id]: level_0,
|
|
[level_1.level_id]: level_1,
|
|
[level_2.level_id]: level_2,
|
|
[level_3.level_id]: level_3,
|
|
[level_experimental.level_id]: level_experimental
|
|
};
|
|
default_level = Object.create(levels[L2]);
|
|
default_level.level_text = "Default";
|
|
domains = {};
|
|
}
|
|
init_levels();
|
|
|
|
let levels_initialised = false; // Initialized in updateLevels()
|
|
let fp_levels_initialised = false; // Initialized in fp_levels.js/loadFpdConfig()
|
|
let levels_updated_callbacks = [];
|
|
var tweak_domains = tweak_domains || {};
|
|
async function updateLevels(res) {
|
|
init_levels();
|
|
custom_levels = res["custom_levels"] || {};
|
|
for (let key in custom_levels) {
|
|
levels[key] = custom_levels[key];
|
|
}
|
|
for (let key in levels) {
|
|
levels[key].wrappers = wrapping_groups.get_wrappers(levels[key]);
|
|
}
|
|
var new_default_level = res["__default__"];
|
|
if (new_default_level === undefined || new_default_level === null || !(new_default_level in levels)) {
|
|
default_level = Object.assign({}, levels[L2]);
|
|
setDefaultLevel(L2);
|
|
}
|
|
else {
|
|
default_level = Object.assign({}, levels[new_default_level]);
|
|
}
|
|
default_level.is_default = true;
|
|
var redefined_domains = res["domains"] || {};
|
|
for (let [d, settings] of Object.entries(tweak_domains)) {
|
|
if ((default_level.level_id in settings.level_id) && !(d in redefined_domains)) {
|
|
redefined_domains[d] = {level_id: default_level.level_id, tweaks: settings.tweaks};
|
|
}
|
|
}
|
|
for (let [d, {level_id, tweaks, restore, restore_tweaks}] of Object.entries(redefined_domains)) {
|
|
let level = levels[level_id];
|
|
if (level === undefined) {
|
|
domains[d] = default_level;
|
|
}
|
|
else {
|
|
if (tweaks) {
|
|
// this domain has "tweaked" wrapper groups from other levels, let's merge them
|
|
level = Object.assign({}, level, tweaks);
|
|
level.tweaks = tweaks;
|
|
delete level.wrappers; // we will lazy instantiate them on demand in getCurrentLevelJSON()
|
|
}
|
|
if (restore) {
|
|
level.restore = restore;
|
|
if (restore_tweaks) {
|
|
level.restore_tweaks = restore_tweaks;
|
|
}
|
|
}
|
|
}
|
|
domains[d] = level;
|
|
}
|
|
|
|
levels_initialised = true;
|
|
if (fp_levels_initialised) { // Wait for both levels_initialised and fp_levels_initialised
|
|
var orig_levels_updated_callbacks = levels_updated_callbacks;
|
|
levels_updated_callbacks = [];
|
|
orig_levels_updated_callbacks.forEach((it) => it());
|
|
await updateUserScripts();
|
|
}
|
|
}
|
|
browser.storage.sync.get(null).then(updateLevels);
|
|
|
|
var wrappersPortId = null;
|
|
var cachedSiteSettings = null;
|
|
async function updateUserScripts() {
|
|
if (browser.tabs.executeScript || !("userScripts" in browser) || self.window) {
|
|
return;
|
|
}
|
|
if (!cachedSiteSettings) {
|
|
({wrappersPortId, cachedSiteSettings} = await
|
|
browser.storage.local.get(["wrappersPortId", "cachedSiteSettings"]));
|
|
}
|
|
siteSettings = JSON.stringify({domains, fpdWhitelist, fpdOn: fpDetectionOn && fpdSettings.detection});
|
|
if (siteSettings == cachedSiteSettings) {
|
|
return;
|
|
}
|
|
cachedSiteSettings = siteSettings;
|
|
const confCache = new Map();
|
|
const allGlobs = new Set();
|
|
const entries = Object.entries(domains);
|
|
entries.push(["*", default_level]);
|
|
let count = 0;
|
|
for (const [domain, l] of entries) {
|
|
if (l.tweaks && !l.wrappers) {
|
|
l.wrappers = wrapping_groups.get_wrappers(l);
|
|
}
|
|
const fpdOn = fpDetectionOn && !isFpdWhitelisted(domain);
|
|
const confKey = JSON.stringify([l.wrappers, fpdOn]);
|
|
let conf = confCache.get(confKey);
|
|
const glob = `*.${domain}`;
|
|
if (!conf) {
|
|
const fpdWrappers = fpdOn ? fp_levels.page_wrappers[fpdSettings.detection] : [];
|
|
const injection = fp_assemble_injection(l, fpdWrappers);
|
|
conf = {
|
|
id: `L:${l.level_id}-FPD:${fpdOn}-C:${count++}`,
|
|
injection,
|
|
includeGlobs: [glob],
|
|
excludeGlobs: [],
|
|
};
|
|
confCache.set(confKey, conf);
|
|
} else {
|
|
conf.includeGlobs.push(glob);
|
|
}
|
|
if (domain == '*') { // default level
|
|
conf.excludeGlobs = [... allGlobs].filter(g => !conf.includeGlobs.includes(g));
|
|
conf.includeGlobs = [];
|
|
conf.matches = ["<all_urls>"];
|
|
break;
|
|
}
|
|
allGlobs.add(glob);
|
|
const imply = `.${domain}`;
|
|
for (const otherConf of confCache.values()) {
|
|
if (otherConf === conf) continue;
|
|
const otherImplied = otherConf.includeGlobs.filter(g => g !== glob && g.endsWith(imply));
|
|
for (const impliedGlob of otherImplied) {
|
|
conf.excludeGlobs.push(impliedGlob);
|
|
}
|
|
const otherImplies = otherConf.includeGlobs.filter(g => glob.endsWith(g.replace('*', '')));
|
|
for (const implyingGlob of otherImplies) {
|
|
otherConf.excludeGlobs.push(implyingGlob);
|
|
}
|
|
}
|
|
}
|
|
|
|
const usTemplate = {
|
|
runAt: "document_start",
|
|
allFrames: true,
|
|
world: "MAIN",
|
|
};
|
|
const globs2matches = globs => [... new Set(globs)].map(g => `*://${g}/*`);
|
|
|
|
const scripts = [];
|
|
for (const conf of confCache.values()) {
|
|
const {portId, code} = patchWindow({
|
|
portId: wrappersPortId,
|
|
code: conf.injection,
|
|
});
|
|
if (wrappersPortId !== portId) {
|
|
wrappersPortId = portId;
|
|
}
|
|
browser.storage.local.set({cachedSiteSettings, wrappersPortId});
|
|
const {id, includeGlobs, excludeGlobs} = conf;
|
|
const opts = {
|
|
id,
|
|
matches: conf.matches || globs2matches(includeGlobs),
|
|
excludeMatches: globs2matches(excludeGlobs),
|
|
};
|
|
const debugCode = `console.info("Injecting wrapper for " + document.URL + ": " + JSON.stringify(${JSON.stringify(opts)}) + ", ${portId}.");`;
|
|
opts.js = [{code: debugCode}, {code}];
|
|
scripts.push(
|
|
Object.assign(opts, usTemplate)
|
|
);
|
|
}
|
|
|
|
await browser.userScripts.unregister();
|
|
if (scripts.length) {
|
|
await browser.userScripts.register(scripts);
|
|
}
|
|
}
|
|
|
|
function changedLevels(changed, area) {
|
|
if (area !== "sync") return;
|
|
browser.storage.sync.get(null).then(updateLevels);
|
|
}
|
|
browser.storage.onChanged.addListener(changedLevels);
|
|
|
|
function setDefaultLevel(level) {
|
|
browser.storage.sync.set({__default__: level});
|
|
}
|
|
|
|
function saveDomainLevels() {
|
|
tobesaved = {};
|
|
for (k in domains) {
|
|
let {level_id, tweaks, restore, restore_tweaks} = domains[k];
|
|
if (k[k.length - 1] === ".") {
|
|
k = k.substring(0, k.length-1);
|
|
}
|
|
// Tweaks not contain the new value defined by the user. However, that might
|
|
// be the value of the level. Remove such tweaks as they to not change the
|
|
// level of protection
|
|
if (tweaks) {
|
|
for (let [group, param] of Object.entries(tweaks)) {
|
|
if (param === (levels[level_id][group] || 0)) {
|
|
delete tweaks[group]; // remove redundant entries
|
|
}
|
|
}
|
|
if (Object.keys(tweaks).length === 0) {
|
|
tweaks = undefined;
|
|
}
|
|
// Do not save built-in tweaks as they are automatically added in updateLevels
|
|
if (k in tweak_domains) {
|
|
// Skip further check if the user has a different default_level
|
|
if (default_level.level_id in tweak_domains[k].level_id) {
|
|
tdb_tweaks = Object.entries(tweak_domains[k].tweaks);
|
|
current_tweaks = Object.entries(tweaks || {});
|
|
if (tdb_tweaks.length === current_tweaks.length) {
|
|
var equal = true;
|
|
for ([name, val] of tdb_tweaks) {
|
|
if (tweaks[name] !== val) {
|
|
equal = false;
|
|
break;
|
|
}
|
|
}
|
|
if (equal) {
|
|
// This entry should not be saved
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tobesaved[k] = tweaks ? {level_id, tweaks} : {level_id};
|
|
if (restore) {
|
|
tobesaved[k].restore = restore;
|
|
if (restore_tweaks) {
|
|
tobesaved[k].restore_tweaks = restore_tweaks;
|
|
}
|
|
}
|
|
}
|
|
browser.storage.sync.set({domains: tobesaved});
|
|
}
|
|
|
|
function getCurrentLevelJSON(url) {
|
|
var subDomains = extractSubDomains(getEffectiveDomain(url));
|
|
for (let domain of subDomains.reverse()) {
|
|
if (domain in domains) {
|
|
let l = domains[domain];
|
|
if (l.tweaks && !l.wrappers) {
|
|
l.wrappers = wrapping_groups.get_wrappers(l);
|
|
}
|
|
return l;
|
|
}
|
|
}
|
|
return default_level;
|
|
}
|
|
|
|
function getTweaksForLevel(level_id, tweaks_obj) {
|
|
tweaks_obj = tweaks_obj || {}; // Make sure that tweaks_obj is an object
|
|
let working = Object.assign({}, wrapping_groups.empty_level, levels[level_id], tweaks_obj);
|
|
Object.keys(working).forEach(function(key) {
|
|
if (!wrapping_groups.group_names.includes(key)) {
|
|
delete working[key];
|
|
}
|
|
});
|
|
return working;
|
|
}
|