diff options
Diffstat (limited to 'data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js')
-rw-r--r-- | data/extensions/jsr@javascriptrestrictor/wrappingS-WEBA.js | 365 |
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); -})(); |