summaryrefslogtreecommitdiff
path: root/data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js')
-rw-r--r--data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js365
1 files changed, 0 insertions, 365 deletions
diff --git a/data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js b/data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js
deleted file mode 100644
index 8bd7041..0000000
--- a/data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js
+++ /dev/null
@@ -1,365 +0,0 @@
-/** \file
- * \brief Wrappers for Web Audio API
- *
- * \see https://webaudio.github.io/web-audio-api
- *
- * \author Copyright (C) 2021 Matus Svancar
- * \author Copyright (C) 2023 Martin Zmitko
- *
- * \license SPDX-License-Identifier: GPL-3.0-or-later
- * \license SPDX-License-Identifier: MPL-2.0
- */
-//
-// 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/>.
-//
-// Alternatively, the contents of this file may be used under the terms
-// of the Mozilla Public License, v. 2.0, as described below:
-//
-// 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/.
-//
-// \copyright Copyright (c) 2020 The Brave Authors.
-
-/** \file
- * This file contains wrappers for AudioBuffer and AnalyserNode related calls
- * * https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer
- * * https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode
- * \ingroup wrappers
- *
- * The goal is to prevent fingerprinting by modifying the values from functions which are reading/copying from AudioBuffer and AnalyserNode.
- * So the audio content of wrapped objects is the same as intended.
- *
- * The modified content can be either a white noise based on domain key or a fake audio data that is modified according to
- * domain key to be different than the original albeit very similar (i.e. the approach
- * inspired by the algorithms created by Brave Software <https://brave.com>
- * available at https://github.com/brave/brave-core/blob/master/chromium_src/third_party/blink/renderer/core/execution_context/execution_context.cc.)
- *
- * \note Both approaches are detectable by a fingerprinter that checks if a predetermined audio
- * is the same as the read one. Nevertheless, the aim of the wrappers is
- * to limit the finerprintability.
- *
- * \bug Possibly inconsistant data between AudioBuffer and AnalyserNode wrappers.
- *
- * \bug Inconsistency between AudioBuffer.prototype.copyFromChannel and AudioBuffer.prototype.getChannelData.
- * AudioBuffer.prototype.copyFromChannel should call AudioBuffer.prototype.getChannelData wrapper
- * and then return result of the original call.
- */
-
-/*
- * Create private namespace
- */
-(function() {
- /**
- * \brief Modifies audio data
- *
- * \param arr typed array with data - Uint8Array or Float32Array
- *
- * Depending on level chosen this function modifies arr content:
- * * (0) - multiplies values by fudge factor based on domain key
- * * (1) - replace values by white noise based on domain key
- */
- function audioFarble(array){
- if (wasm.ready && wasm.grow(array.byteLength)) {
- try {
- farbleAudioWASM();
- } catch (e) {
- console.error("WebAssembly optimized farbling failed, falling back to JavaScript implementation", e);
- farbleAudioJS();
- }
- } else {
- farbleAudioJS();
- }
-
- function farbleAudioWASM() {
- const ARRAY_BYTE_LEN = array.byteLength;
- wasm.set(array, 0, true);
- const crc = wasm.crc16Float(ARRAY_BYTE_LEN);
- const mash = new Mash();
- mash.addData(' ');
- mash.addData(domainHash);
- mash.addData("AudioFarbling");
- mash.addData(crc);
- wasm.farbleFloats(ARRAY_BYTE_LEN, mash.n | 0);
- array.set(wasm.get(array.length, 0, true));
- }
-
- function farbleAudioJS() {
- // PRNG function needs to depend on the original audio, so that the same
- // audio is farbled the same way but different audio is farbled differently
- // See https://pagure.io/JShelter/webextension/issue/23
- const ARRAY_LEN = array.length;
- const MAXUINT32 = 4294967295;
- let crc = new CRC16();
- for (let i = 0; i < ARRAY_LEN; i++) {
- crc.single(array[i] * MAXUINT32);
- }
- var thisaudio_prng = alea(domainHash, "AudioFarbling", crc.crc);
-
- for (let i = 0; i < ARRAY_LEN; i++) {
- // Possible improvements:
- // Copy neighbor data (possibly with modifications)
- array[i] *= 0.99 + thisaudio_prng() / 100;
- }
- }
- };
-
- function audioFarbleInt(array) {
- const ARRAY_LEN = array.byteLength;
- if (wasm.ready && wasm.grow(ARRAY_LEN)) {
- try {
- farbleAudioIntWASM();
- } catch (e) {
- console.error("WebAssembly optimized farbling failed, falling back to JavaScript implementation", e);
- farbleAudioIntJS();
- }
- } else {
- farbleAudioIntJS();
- }
-
- function farbleAudioIntWASM() {
- wasm.set(array);
- const crc = wasm.crc16(ARRAY_LEN);
- const mash = new Mash();
- mash.addData(' ');
- mash.addData(domainHash);
- mash.addData("AudioFarbling");
- mash.addData(crc);
- wasm.farbleBytes(ARRAY_LEN, mash.n | 0, false);
- array.set(wasm.get(ARRAY_LEN));
- }
-
- function farbleAudioIntJS() {
- // PRNG function needs to depend on the original audio, so that the same
- // audio is farbled the same way but different audio is farbled differently
- // See https://pagure.io/JShelter/webextension/issue/23
- let crc = new CRC16();
- for (let i = 0; i < ARRAY_LEN; i++) {
- crc.single(array[i]);
- }
- var thisaudio_prng = alea(domainHash, "AudioFarbling", crc.crc);
-
- for (let i = 0; i < ARRAY_LEN; i++) {
- if (thisaudio_prng.get_bits(1)) { // Modify data with probability of 0.5
- // Possible improvements:
- // Copy neighbor data (possibly with modifications)
- // Make bigger changes than xoring with 1
- array[i] ^= 1;
- }
- }
- }
- }
- function whiteNoiseInt(array) {
- noise_prng = alea(Date.now(), prng());
- const ARRAY_LEN = array.length;
- for (let i = 0; i < ARRAY_LEN; i++) {
- array[i] = (noise_prng() * 256) | 0;
- }
- }
- function whiteNoiseFloat(array) {
- const ARRAY_LEN = array.length;
- noise_prng = alea(Date.now(), prng());
- for (let i = 0; i < ARRAY_LEN; i++) {
- array[i] = (noise_prng() * 2) -1;
- }
- }
- /** @var String audioFarbleBody.
- *
- * Contains functions for modyfing audio data according to chosen level of protection -
- * (0) - replace by white noise (range <0,0.1>) based on domain key
- * (1) - multiply array by fudge factor based on domain key
- */
- var audioFarbleBody = audioFarble;
- var wrappers = [
- {
- parent_object: "AudioBuffer.prototype",
- parent_object_property: "getChannelData",
- wrapped_objects: [
- {
- original_name: "AudioBuffer.prototype.getChannelData",
- wrapped_name: "origGetChannelData",
- }
- ],
- helping_code: "var behaviour = args[0]; WrapHelper.shared['WEBA_gcd_pool'] = new Set(); WrapHelper.shared['WEBA_origGetChannelData'] = origGetChannelData;" + audioFarbleBody + whiteNoiseFloat,
- original_function: "parent.AudioBuffer.prototype.getChannelData",
- wrapping_function_args: "channel",
- /** \fn fake AudioBuffer.prototype.getChannelData
- * \brief Returns modified channel data.
- *
- * Calls original function, which returns array with result, then calls function
- * audioFarble with returned array as argument - which changes array values according to chosen level.
- */
- wrapping_function_body: `
- var floatArr = origGetChannelData.call(this, channel);
- if (WrapHelper.shared['WEBA_gcd_pool'].has(floatArr)) {
- return floatArr;
- }
- if (behaviour == 0) {
- audioFarble(floatArr);
- }
- else if (behaviour == 1) {
- whiteNoiseFloat(floatArr);
- }
- WrapHelper.shared['WEBA_gcd_pool'].add(floatArr);
- setTimeout(function() {
- WrapHelper.shared['WEBA_gcd_pool'].delete(floatArr);
- }, 300000); // Remove the information after 5 minutes, this might need tweaking
- return floatArr;
- `,
- },
- {
- parent_object: "AudioBuffer.prototype",
- parent_object_property: "copyFromChannel",
- wrapped_objects: [
- {
- original_name: "AudioBuffer.prototype.copyFromChannel",
- wrapped_name: "origCopyFromChannel",
- }
- ],
- helping_code: "var behaviour = args[0]; WrapHelper.shared['WEBA_gcd_pool'] = new Set();" + audioFarbleBody + whiteNoiseFloat,
- original_function: "parent.AudioBuffer.prototype.copyFromChannel",
- wrapping_function_args: "destination, channel, start",
- /** \fn fake AudioBuffer.prototype.copyFromChannel
- * \brief Modifies destination array after calling original function.
- *
- * Calls original function, which writes data to destination array, then calls function
- * audioFarble with destination array as argument - which changes array values according to chosen level.
- */
- wrapping_function_body: `
- if (behaviour == 1) {
- whiteNoiseFloat(destination);
- }
- else if (behaviour == 0) {
- var floatArr = WrapHelper.shared['WEBA_origGetChannelData'].call(this, channel);
- origCopyFromChannel.call(this, destination, channel, start);
- if (WrapHelper.shared['WEBA_gcd_pool'].has(floatArr)) {
- // Already farbled, no additional farbling
- }
- else {
- audioFarble(destination);
- }
- }
- `,
- },
- {
- parent_object: "AnalyserNode.prototype",
- parent_object_property: "getByteTimeDomainData",
- wrapped_objects: [
- {
- original_name: "AnalyserNode.prototype.getByteTimeDomainData",
- wrapped_name: "origGetByteTimeDomainData",
- }
- ],
- helping_code: "var behaviour = args[0];" + audioFarbleInt + whiteNoiseInt,
- wrapping_function_args: "destination",
- /** \fn fake AnalyserNode.prototype.getByteTimeDomainData
- * \brief Modifies destination array after calling original function.
- *
- * Calls original function, which writes data to destination array, then calls function
- * audioFarble with destination array as argument - which changes array values according to chosen level.
- */
- wrapping_function_body: `
- if (behaviour == 0) {
- origGetByteTimeDomainData.call(this, destination);
- audioFarbleInt(destination);
- }
- else if (behaviour == 1) {
- whiteNoiseInt(destination);
- }
- `,
- },
- {
- parent_object: "AnalyserNode.prototype",
- parent_object_property: "getFloatTimeDomainData",
- wrapped_objects: [
- {
- original_name: "AnalyserNode.prototype.getFloatTimeDomainData",
- wrapped_name: "origGetFloatTimeDomainData",
- }
- ],
- helping_code: "var behaviour = args[0];" + audioFarbleBody + whiteNoiseFloat,
- wrapping_function_args: "destination",
- /** \fn fake AnalyserNode.prototype.getFloatTimeDomainData
- * \brief Modifies destination array after calling original function.
- *
- * Calls original function, which writes data to destination array, then calls function
- * audioFarble with destination array as argument - which changes array values according to chosen level.
- */
- wrapping_function_body: `
- if (behaviour == 0) {
- origGetFloatTimeDomainData.call(this, destination);
- audioFarble(destination);
- }
- else if (behaviour == 1) {
- whiteNoiseFloat(destination);
- }
- `,
- },
- {
- parent_object: "AnalyserNode.prototype",
- parent_object_property: "getByteFrequencyData",
- wrapped_objects: [
- {
- original_name: "AnalyserNode.prototype.getByteFrequencyData",
- wrapped_name: "origGetByteFrequencyData",
- }
- ],
- helping_code: "var behaviour = args[0];" + audioFarbleInt + whiteNoiseInt,
- wrapping_function_args: "destination",
- /** \fn fake AnalyserNode.prototype.getByteFrequencyData
- * \brief Modifies destination array after calling original function.
- *
- * Calls original function, which writes data to destination array, then calls function
- * audioFarble with destination array as argument - which changes array values according to chosen level.
- */
- wrapping_function_body: `
- if (behaviour == 0) {
- origGetByteFrequencyData.call(this, destination);
- audioFarbleInt(destination);
- }
- else if (behaviour == 1) {
- whiteNoiseInt(destination);
- }
- `,
- },
- {
- parent_object: "AnalyserNode.prototype",
- parent_object_property: "getFloatFrequencyData",
- wrapped_objects: [
- {
- original_name: "AnalyserNode.prototype.getFloatFrequencyData",
- wrapped_name: "origGetFloatFrequencyData",
- }
- ],
- helping_code: "var behaviour = args[0];" + audioFarbleBody + whiteNoiseFloat,
- wrapping_function_args: "destination",
- /** \fn fake AnalyserNode.prototype.getFloatFrequencyData
- * \brief Modifies destination array after calling original function.
- *
- * Calls original function, which writes data to destination array, then calls function
- * audioFarble with destination array as argument - which changes array values according to chosen level.
- */
- wrapping_function_body: `
- if (behaviour == 0) {
- origGetFloatFrequencyData.call(this, destination);
- audioFarble(destination);
- }
- else if (behaviour == 1) {
- whiteNoiseFloat(destination);
- }
- `,
- }
- ];
- add_wrappers(wrappers);
-})();