From cd8d0e48117abbb6809b97dd1a8ae72b0d19b2f1 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:31:23 +0000 Subject: [PATCH 1/38] Integration tests: Correct NBS GUI test. The slider for turning NBS on/off was changes. This test is updated in this commit according to changes. --- diff --git a/tests/integration_tests/testing/tests_definition/test_NBS_setting.py b/tests/integration_tests/testing/tests_definition/test_NBS_setting.py index 18da0e6..c30e704 100644 --- a/tests/integration_tests/testing/tests_definition/test_NBS_setting.py +++ b/tests/integration_tests/testing/tests_definition/test_NBS_setting.py @@ -28,14 +28,15 @@ from time import sleep def switch_NBS_setting(browser): browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) - browser.driver.find_elements(By.CLASS_NAME, 'switch')[0].click() + sleep(1) + browser.driver.find_elements(By.CLASS_NAME, 'slider')[0].click() sleep(1) def get_NBS_setting(browser): browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) - sleep(1) - return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('#shield-switch + .slider'),':before').getPropertyValue('content')")) + sleep(2) + return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('.switch .slider'),':before').getPropertyValue('content')")) ## Test turnning NBS off in popup. From d787692b87b2b7a9d7d770572811b85e3e9f632b Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:32:40 +0000 Subject: [PATCH 2/38] Integration tests: Correct Plugins test. The apparent modification (on level 0) of the plugins is caused by the Selenium environment in which the testing takes place. --- diff --git a/tests/integration_tests/testing/tests_definition/test_navigator.py b/tests/integration_tests/testing/tests_definition/test_navigator.py index 9baf4ce..9df6f4e 100644 --- a/tests/integration_tests/testing/tests_definition/test_navigator.py +++ b/tests/integration_tests/testing/tests_definition/test_navigator.py @@ -109,7 +109,9 @@ def test_oscpu(browser, navigator, expected): ## Test plugins count def test_plugins_count(browser, navigator, expected): - if expected.navigator.plugins['count'][browser.type] == 'REAL VALUE': + if expected.navigator.mimeTypes == 'IGNORE': + return + elif expected.navigator.plugins['count'][browser.type] == 'REAL VALUE': assert len(navigator['plugins']) == len(browser.real.navigator.plugins) elif expected.navigator.plugins['count'][browser.type] == 'PLUS_2': assert len(navigator['plugins']) == len(browser.real.navigator.plugins) + 2 @@ -118,7 +120,9 @@ def test_plugins_count(browser, navigator, expected): ## Test plugins array value def test_plugins(browser, navigator, expected): - if expected.navigator.plugins['value'][browser.type] == 'REAL VALUE': + if expected.navigator.mimeTypes == 'IGNORE': + return + elif expected.navigator.plugins['value'][browser.type] == 'REAL VALUE': assert navigator['plugins'] == browser.real.navigator.plugins elif expected.navigator.plugins['value'][browser.type] == 'EMPTY': assert not navigator['plugins'] @@ -127,7 +131,9 @@ def test_plugins(browser, navigator, expected): ## Test mimeTypes def test_mime_types(browser, navigator, expected): - if expected.navigator.mimeTypes == 'EMPTY': + if expected.navigator.mimeTypes == 'IGNORE': + return + elif expected.navigator.mimeTypes == 'EMPTY': assert navigator['mimeTypes'] == [] elif expected.navigator.mimeTypes == 'SPOOF VALUE': if browser.real.navigator.mimeTypes == []: diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index 6dd3de9..9ba2c81 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -1,5 +1,5 @@ # -# JShelter is a browser extension which increases level +# JavaScript Restrictor is a browser extension which increases level # of security, anonymity and privacy of the user while browsing the # internet. # @@ -26,7 +26,7 @@ from values_tested import TestedValues from web_browser_type import BrowserType -## Module contains definitions for expected values of default levels od JShelter. +## Module contains definitions for expected values of default levels od JSR. # # Expected values are comparing during testing with current values of variables. # 'REAL VALUE' means that current value should not be spoofed. @@ -35,13 +35,11 @@ from web_browser_type import BrowserType # This module can be edited when definition of default levels will be changed. -# Ignore Plugins and mimeTypes tests - explanation: +## Expected values for default level 0 of JSR. +# Ignore Plugins and mimeTypes test - explanation: # The apparent modification of the plugins is caused by the Selenium environment in which the testing takes place. # This difference only appears in a browser controlled by Selenium. # This issue is not caused by JShield, but by Selenium. - - -## Expected values for default level 0 of JShelter. level0 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -77,11 +75,11 @@ level0 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 'EXACTLY'}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 'IGNORE', BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'REAL VALUE', + 'value': {BrowserType.FIREFOX: 'IGNORE', BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='REAL VALUE', + mimeTypes='IGNORE', get_channel= 'REAL VALUE', copy_channel= 'REAL VALUE', byte_time_domain= 'REAL VALUE', @@ -103,7 +101,7 @@ level0 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 1 of JShelter. +## Expected values for default level 1 of JSR. level1 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -143,11 +141,11 @@ level1 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.01}, - plugins={'count': {BrowserType.FIREFOX: 0, - BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'EMPTY', - BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='SPOOF VALUE', + plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + BrowserType.CHROME: 'REAL VALUE'}, + 'value': {BrowserType.FIREFOX: 'REAL VALUE', + BrowserType.CHROME: 'REAL VALUE'}}, + mimeTypes='REAL VALUE', get_channel= 'REAL VALUE', copy_channel= 'REAL VALUE', byte_time_domain= 'REAL VALUE', @@ -169,7 +167,7 @@ level1 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 2 of JShelter. +## Expected values for default level 2 of JSR. level2 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -209,11 +207,11 @@ level2 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.1}, - plugins={'count': {BrowserType.FIREFOX: 0, - BrowserType.CHROME: 'IGNORE'}, + plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + BrowserType.CHROME: 'PLUS_2'}, 'value': {BrowserType.FIREFOX: 'EMPTY', - BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='EMPTY', + BrowserType.CHROME: 'SPOOF VALUE'}}, + mimeTypes='SPOOF VALUE', get_channel= 'SPOOF VALUE', copy_channel= 'SPOOF VALUE', byte_time_domain= 'SPOOF VALUE', @@ -235,7 +233,7 @@ level2 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 3 of JShelter. +## Expected values for default level 3 of JSR. level3 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -291,7 +289,7 @@ level3 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for custom level 4 of JShelter. +## Expected values for custom level 4 of JSR. ## The hard-coded configuration of the level 4 is defined in the file web_browser.py in function define_test_level. level4 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', From bb978d93f6471a3136e9ae32be2e356af1b9a2bd Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:32:54 +0000 Subject: [PATCH 3/38] Unit tests: Init for ECMA-SHARED tests. --- diff --git a/tests/unit_tests/config/global.json b/tests/unit_tests/config/global.json index acf670f..7ce40ba 100644 --- a/tests/unit_tests/config/global.json +++ b/tests/unit_tests/config/global.json @@ -310,6 +310,44 @@ { "begin": "var browser = JSON.parse(JSON.stringify(sinon_browser)); browser.storage.sync.get = function(param) { return Promise.resolve(param); }; browser.runtime.onMessage.addListener = function(){return;}; browser.runtime.getURL = function(){return;};" } + }, + { + "name": "wrappingS-ECMA-SHARED", + "remove_custom_namespace": true, + "let_to_var": false, + "src_script_requirements": [ + { + "type": "const", + "requirements": [ + { + "from": "./wrapping.js", + "objects": [ + "add_wrappers" + ] + } + ] + } + ], + "extra_exports": [ + "proxyHandler", + "wrappingFunctionBody", + "wrappers" + ], + "test_script_requirements": [ + { + "type": "const", + "requirements": [ + { + "from": "./wrappingS-ECMA-SHARED.js", + "objects": [ + "proxyHandler", + "wrappingFunctionBody", + "wrappers" + ] + } + ] + } + ] } ] } diff --git a/tests/unit_tests/start_unit_tests.sh b/tests/unit_tests/start_unit_tests.sh index d1892ef..f90e131 100755 --- a/tests/unit_tests/start_unit_tests.sh +++ b/tests/unit_tests/start_unit_tests.sh @@ -122,7 +122,7 @@ for k in $(jq '.scripts | keys | .[]' ./config/global.json); do remove_custom_namespace=$(jq -r '.remove_custom_namespace' <<< "$script") if [ $remove_custom_namespace == "true" ] then - sed -i -e "s/(function() {//" -e "s/})();//" -e "s/successCallback(/return(/" ./tmp/$source_script_name + sed -i -e "s/(function() {//" -e "s/(function () {//" -e "s/})();//" -e "s/successCallback(/return(/" ./tmp/$source_script_name fi # Modify source script - convert "let" variables to "var" variables if necessary. @@ -244,6 +244,6 @@ echo Testing FINISHED. echo Cleanup STARTED. # Remove ./tmp directory (temporary working directory) after tests finished. -rm -rf ./tmp +# rm -rf ./tmp echo Cleanup FINISHED. diff --git a/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js new file mode 100644 index 0000000..a5ddfdb --- /dev/null +++ b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js @@ -0,0 +1,42 @@ +// +// JavaScript Restrictor is a browser extension which increases level +// of security, anonymity and privacy of the user while browsing the +// internet. +// +// Copyright (C) 2022 Martin Bednar +// +// 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 ev1267027en 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 . +// + +/// + +describe("ECMA-SHARED", function() { + describe("proxyHandler", function() { + it("should be defined.",function() { + expect(proxyHandler).toBeDefined(); + }); + }); + describe("wrappingFunctionBody", function() { + it("should be defined.",function() { + expect(wrappingFunctionBody).toBeDefined(); + }); + }); + describe("wrappers", function() { + it("should be defined.",function() { + expect(wrappers).toBeDefined(); + }); + }); +}); \ No newline at end of file From fa0b9c21f22c09709bddda4add5fae101bc4a35a Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:33:12 +0000 Subject: [PATCH 4/38] Unit tests: Init for ECMA-ARRAY tests. --- diff --git a/tests/unit_tests/config/global.json b/tests/unit_tests/config/global.json index 7ce40ba..947108c 100644 --- a/tests/unit_tests/config/global.json +++ b/tests/unit_tests/config/global.json @@ -348,6 +348,74 @@ ] } ] + }, + { + "name": "wrappingS-ECMA-ARRAY", + "remove_custom_namespace": true, + "let_to_var": false, + "src_script_requirements": [ + { + "type": "const", + "requirements": [ + { + "from": "./wrapping.js", + "objects": [ + "add_wrappers" + ] + } + ] + } + ], + "extra_exports": [ + "packIEEE754", + "unpackIEEE754", + "unpackF64", + "packF64", + "unpackF32", + "packF32", + "constructDecorator", + "offsetDecorator", + "redefineNewArrayFunctions", + "redefineNewArrayConstructors", + "proxyHandler", + "getByteDecorator", + "setByteDecorator", + "getFloatDecorator", + "setFloatDecorator", + "getBigIntDecorator", + "setBigIntDecorator", + "redefineDataViewFunctions" + ], + "test_script_requirements": [ + { + "type": "const", + "requirements": [ + { + "from": "./wrappingS-ECMA-ARRAY.js", + "objects": [ + "packIEEE754", + "unpackIEEE754", + "unpackF64", + "packF64", + "unpackF32", + "packF32", + "constructDecorator", + "offsetDecorator", + "redefineNewArrayFunctions", + "redefineNewArrayConstructors", + "proxyHandler", + "getByteDecorator", + "setByteDecorator", + "getFloatDecorator", + "setFloatDecorator", + "getBigIntDecorator", + "setBigIntDecorator", + "redefineDataViewFunctions" + ] + } + ] + } + ] } ] } diff --git a/tests/unit_tests/tests/wrappingS-ECMA-ARRAY_tests.js b/tests/unit_tests/tests/wrappingS-ECMA-ARRAY_tests.js new file mode 100644 index 0000000..6632b09 --- /dev/null +++ b/tests/unit_tests/tests/wrappingS-ECMA-ARRAY_tests.js @@ -0,0 +1,120 @@ +// +// JavaScript Restrictor is a browser extension which increases level +// of security, anonymity and privacy of the user while browsing the +// internet. +// +// Copyright (C) 2022 Martin Bednar +// +// 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 ev1267027en 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 . +// + +/// + +describe("ECMA-ARRAY", function() { + describe("packIEEE754", function() { + it("should be defined.",function() { + expect(packIEEE754).toBeDefined(); + }); + it("should return array.",function() { + expect(packIEEE754(14156,2,5)).toEqual(jasmine.any(Array)); + }); + }); + describe("unpackIEEE754", function() { + it("should be defined.",function() { + expect(unpackIEEE754).toBeDefined(); + }); + }); + describe("unpackF64", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("packF64", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("unpackF32", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("packF32", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("constructDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("offsetDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("redefineNewArrayFunctions", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("redefineNewArrayConstructors", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("proxyHandler", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("getByteDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("setByteDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("getFloatDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("setFloatDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("getBigIntDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("setBigIntDecorator", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); + describe("redefineDataViewFunctions", function() { + it("should be defined.",function() { + expect(unpackF64).toBeDefined(); + }); + }); +}); diff --git a/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js index a5ddfdb..85bde3c 100644 --- a/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js +++ b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js @@ -39,4 +39,4 @@ describe("ECMA-SHARED", function() { expect(wrappers).toBeDefined(); }); }); -}); \ No newline at end of file +}); From 42812b7abb774c68c8e6ee8b7540a54b2f71d571 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:33:30 +0000 Subject: [PATCH 5/38] Integration tests: Set a lower deviation between the browser and the system time. --- diff --git a/tests/integration_tests/testing/tests_definition/test_time.py b/tests/integration_tests/testing/tests_definition/test_time.py index 6ff333a..bebc996 100644 --- a/tests/integration_tests/testing/tests_definition/test_time.py +++ b/tests/integration_tests/testing/tests_definition/test_time.py @@ -48,4 +48,4 @@ def test_hours_minutes_seconds(browser): p_time = p_now.hour * 60 * 60 + p_now.minute * 60 + p_now.second # Values do not have to be strictly equal. # A deviation of less than 4 is tolerated. - assert abs(js_time - p_time) < 4 + assert abs(js_time - p_time) < 2 From c7419e7478d5c2e2e53508cb73e3a549f9b9f788 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:33:43 +0000 Subject: [PATCH 6/38] Update Selenium deprecated methods for getting elements. --- diff --git a/tests/integration_tests/testing/values_getters.py b/tests/integration_tests/testing/values_getters.py index 38844f2..8548108 100644 --- a/tests/integration_tests/testing/values_getters.py +++ b/tests/integration_tests/testing/values_getters.py @@ -3,8 +3,8 @@ # of security, anonymity and privacy of the user while browsing the # internet. # -# Copyright (C) 2020 Martin Bednar # Copyright (C) 2021 Matus Svancar +# Copyright (C) 2022 Martin Bednar # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -44,11 +44,11 @@ from configuration import get_config # Function waits maximally 10 seconds for loading geolocation data. def get_position(driver): driver.get(get_config("testing_page")) - driver.find_element_by_xpath("//button[text()='Show GPS data']").click() + driver.find_element(By.XPATH, "//button[text()='Show GPS data']").click() WebDriverWait(driver, 10).until( ec.presence_of_element_located((By.ID, 'mapnavi')) ) - location = driver.find_element_by_id('placeToWriteGPSDetails').text + location = driver.find_element(By.ID, 'placeToWriteGPSDetails').text location = location.replace(" ", "").split() position = {} for property in location: @@ -130,10 +130,10 @@ def get_referrer(driver): def is_canvas_spoofed(driver): try: driver.get(get_config("testing_page")) - driver.find_element_by_xpath("//button[text()='Add line to canvas']").click() - driver.find_element_by_xpath("//button[text()='Add circle to canvas']").click() - driver.find_element_by_xpath("//button[text()='Add text to canvas']").click() - driver.find_element_by_xpath("//button[text()='Get data and show image in canvas frame']").click() + driver.find_element(By.XPATH, "//button[text()='Add line to canvas']").click() + driver.find_element(By.XPATH, "//button[text()='Add circle to canvas']").click() + driver.find_element(By.XPATH, "//button[text()='Add text to canvas']").click() + driver.find_element(By.XPATH, "//button[text()='Get data and show image in canvas frame']").click() is_spoofed = driver.execute_script("var canvas = document.getElementById('canvas1'); return !canvas.getContext('2d')" ".getImageData(0, 0, canvas.width, canvas.height).data.some(channel => channel !== 255)") except: @@ -269,7 +269,7 @@ def get_webgl_precisions(driver, name): ## returns object with attributes output by AudioContext.getChannelData, AudioContext.copyFromChannel, AnalyserNode.getFloatFrequencyData, AnalyserNode.getByteFrequencyData, AnalyserNode.getFloatTimeDomainData, AnalyserNode.getByteTimeDomainData which are saved in testing page def get_audio(driver): driver.get(get_config("testing_page")) - driver.find_element_by_xpath("//button[text()='Test audio']").click() + driver.find_element(By.XPATH, "//button[text()='Test audio']").click() sleep(3) audio = {'get_channel': driver.execute_script("return document.getElementById('channel_data_result').innerHTML;"), 'copy_channel': driver.execute_script("return document.getElementById('copy_result').innerHTML;"), From 40f16579b756339aa037eb4f9943fae2d6090718 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:35:11 +0000 Subject: [PATCH 7/38] Integration tests: PluginArray - level 0 in Firefox - set to REAL VALUE (empty array). --- diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index 9ba2c81..c8dc35c 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -75,9 +75,9 @@ level0 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 'EXACTLY'}, - plugins={'count': {BrowserType.FIREFOX: 'IGNORE', + plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'IGNORE', + 'value': {BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'IGNORE'}}, mimeTypes='IGNORE', get_channel= 'REAL VALUE', From 5d78f9715af5c9437018ef0f8794076cb1ba9c91 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:35:23 +0000 Subject: [PATCH 8/38] Integration tests: PluginArray - level 0 in Firefox - update expected values. --- diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index c8dc35c..f871fb4 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -75,9 +75,9 @@ level0 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 'EXACTLY'}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 0, BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'REAL VALUE', + 'value': {BrowserType.FIREFOX: 'EMPTY', BrowserType.CHROME: 'IGNORE'}}, mimeTypes='IGNORE', get_channel= 'REAL VALUE', @@ -141,9 +141,9 @@ level1 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.01}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 0, BrowserType.CHROME: 'REAL VALUE'}, - 'value': {BrowserType.FIREFOX: 'REAL VALUE', + 'value': {BrowserType.FIREFOX: 'EMPTY', BrowserType.CHROME: 'REAL VALUE'}}, mimeTypes='REAL VALUE', get_channel= 'REAL VALUE', @@ -207,9 +207,9 @@ level2 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.1}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 'PLUS_2', BrowserType.CHROME: 'PLUS_2'}, - 'value': {BrowserType.FIREFOX: 'EMPTY', + 'value': {BrowserType.FIREFOX: 'SPOOF VALUE', BrowserType.CHROME: 'SPOOF VALUE'}}, mimeTypes='SPOOF VALUE', get_channel= 'SPOOF VALUE', From c8a1b6205ecc2ca79289050423ac1e490113af31 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:35:36 +0000 Subject: [PATCH 9/38] Integration tests: Ignore PluginArray modified by Selenium. --- diff --git a/tests/integration_tests/testing/tests_definition/test_navigator.py b/tests/integration_tests/testing/tests_definition/test_navigator.py index 9df6f4e..4917be1 100644 --- a/tests/integration_tests/testing/tests_definition/test_navigator.py +++ b/tests/integration_tests/testing/tests_definition/test_navigator.py @@ -3,8 +3,8 @@ # of security, anonymity and privacy of the user while browsing the # internet. # -# Copyright (C) 2020 Martin Bednar # Copyright (C) 2021 Matus Svancar +# Copyright (C) 2022 Martin Bednar # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -109,7 +109,7 @@ def test_oscpu(browser, navigator, expected): ## Test plugins count def test_plugins_count(browser, navigator, expected): - if expected.navigator.mimeTypes == 'IGNORE': + if expected.navigator.plugins['count'][browser.type] == 'IGNORE': return elif expected.navigator.plugins['count'][browser.type] == 'REAL VALUE': assert len(navigator['plugins']) == len(browser.real.navigator.plugins) @@ -120,7 +120,7 @@ def test_plugins_count(browser, navigator, expected): ## Test plugins array value def test_plugins(browser, navigator, expected): - if expected.navigator.mimeTypes == 'IGNORE': + if expected.navigator.plugins['count'][browser.type] == 'IGNORE': return elif expected.navigator.plugins['value'][browser.type] == 'REAL VALUE': assert navigator['plugins'] == browser.real.navigator.plugins diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index f871fb4..b58d353 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -208,9 +208,9 @@ level2 = TestedValues( time={'value': 'REAL VALUE', 'accuracy': 0.1}, plugins={'count': {BrowserType.FIREFOX: 'PLUS_2', - BrowserType.CHROME: 'PLUS_2'}, + BrowserType.CHROME: 'IGNORE'}, 'value': {BrowserType.FIREFOX: 'SPOOF VALUE', - BrowserType.CHROME: 'SPOOF VALUE'}}, + BrowserType.CHROME: 'IGNORE'}}, mimeTypes='SPOOF VALUE', get_channel= 'SPOOF VALUE', copy_channel= 'SPOOF VALUE', From 9a2942646aa3c2cc0293bf3cf871f881c58c953f Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:36:08 +0000 Subject: [PATCH 10/38] Integration tests: Add the time accuracy test. --- diff --git a/tests/integration_tests/testing/tests_definition/test_time.py b/tests/integration_tests/testing/tests_definition/test_time.py index bebc996..dfc8444 100644 --- a/tests/integration_tests/testing/tests_definition/test_time.py +++ b/tests/integration_tests/testing/tests_definition/test_time.py @@ -3,7 +3,7 @@ # of security, anonymity and privacy of the user while browsing the # internet. # -# Copyright (C) 2020 Martin Bednar +# Copyright (C) 2022 Martin Bednar # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -47,5 +47,28 @@ def test_hours_minutes_seconds(browser): p_now = datetime.now() p_time = p_now.hour * 60 * 60 + p_now.minute * 60 + p_now.second # Values do not have to be strictly equal. - # A deviation of less than 4 is tolerated. - assert abs(js_time - p_time) < 2 + # A deviation of less than 1 is tolerated. + assert abs(js_time - p_time) <= 1 + + +## Test time accuracy. +def test_accuracy(browser, expected): + #Suppose time is rounded. + is_time_rounded = True + # Make 3 measurement. + for _ in range(3): + # Wait a while to value of time will be changed. + time.sleep(random.randint(1, 3)) + miliseconds = browser.driver.execute_script("let d = new Date();" + "return d.getMilliseconds()") + if expected.time['accuracy'] == 'EXACTLY': + if int(miliseconds / 10) * 10 != miliseconds: + # miliseconds was not rounded. At least one of three measurement has to say value was not rounded. + is_time_rounded = False + else: + assert is_in_accuracy(miliseconds, expected.time['accuracy']) + + if expected.time['accuracy'] == 'EXACTLY': + # At least one of three measurement has to say value was not rounded. + # is_time_rounded should be false if EXACTLY value is required. + assert not is_time_rounded From b4ef71dca8a90a88527cbafb7ae64c882adb6815 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:41:39 +0000 Subject: [PATCH 11/38] Rename the fakePluginArray function. This function has a same name as a variable. It did not cause conflicts, but for code purity the function was renamed. --- diff --git a/common/wrappingS-NP.js b/common/wrappingS-NP.js index c84794a..c0547a6 100644 --- a/common/wrappingS-NP.js +++ b/common/wrappingS-NP.js @@ -31,9 +31,10 @@ // \copyright Copyright (c) 2020 The Brave Authors. /** \file - * This file contains wrappers for NavigatorPlugins. See the MDN docs on the [plugins](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/plugins) - * and [MIME types](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/mimeTypes). + * This file contains wrappers for NavigatorPlugins * + * * https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/plugins + * * https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/mimeTypes * \ingroup wrappers * * The goal is to prevent fingerprinting by modifying value returned by getters navigator.plugins and navigator.mimeTypes @@ -44,8 +45,8 @@ * * (1) - replace by shuffled PluginArray with two fake plugins, empty MimeTypeArray * * (2) - replace by empty PluginArray and MimeTypeArray * - * These approaches are inspired by the algorithms created by [Brave Software](https://brave.com) - * available [here](https://github.com/brave/brave-core/blob/master/chromium_src/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc). + * These approaches are inspired by the algorithms created by Brave Software + * available at https://github.com/brave/brave-core/blob/master/chromium_src/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc * */ @@ -174,9 +175,8 @@ var counter = 0; for(var i = 0;i=0;j++){ - // (plugins[i][j].type != "") <- Exclude fake plugins. Fake plugin has type == "". if((typeof plugins[i][j] != 'undefined') && (ret.namedItem(plugins[i][j].name)==null) && (plugins[i][j].type != "")){ - ret[counter] = farbleMime(plugins[i][j], plugins[i]); + ret[counter] = plugins[i][j]; ret[plugins[i][j].type] = plugins[i][j]; counter++; } @@ -280,12 +280,6 @@ buffer.push(farblePlugin(plugins[i])); } } - if(args[0]==1){ - for(var i = 0;i Date: Mar 07 2022 12:41:58 +0000 Subject: [PATCH 12/38] Farble MimeType while creating fake MimeTypeArray. Farbling Mime is mentioned in comments (line 324), but the farbling didn't really happen. This commit fix it. Plugin is farbled before adding to fake MimeTypeArray. --- diff --git a/common/wrappingS-NP.js b/common/wrappingS-NP.js index c0547a6..adb6a3f 100644 --- a/common/wrappingS-NP.js +++ b/common/wrappingS-NP.js @@ -175,8 +175,9 @@ var counter = 0; for(var i = 0;i=0;j++){ + // (plugins[i][j].type != "") <- Exclude fake plugins. Fake plugin has type == "". if((typeof plugins[i][j] != 'undefined') && (ret.namedItem(plugins[i][j].name)==null) && (plugins[i][j].type != "")){ - ret[counter] = plugins[i][j]; + ret[counter] = farbleMime(plugins[i][j], plugins[i]); ret[plugins[i][j].type] = plugins[i][j]; counter++; } From 49549cd8bd40ff762e1e86a5061cc579e0051704 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:42:10 +0000 Subject: [PATCH 13/38] Fix> Add missing real Plugins to fake PluginsArray. Documentation says: "level1: replace by shuffled PluginArray with two fake plugins". But only 2 fake plugins were returned. Fix it. Before adding 2 fake plugins, add all real plugins and shuffle them. --- diff --git a/common/wrappingS-NP.js b/common/wrappingS-NP.js index adb6a3f..33b0c24 100644 --- a/common/wrappingS-NP.js +++ b/common/wrappingS-NP.js @@ -281,6 +281,12 @@ buffer.push(farblePlugin(plugins[i])); } } + if(args[0]==1){ + for(var i = 0;i Date: Mar 07 2022 12:42:19 +0000 Subject: [PATCH 14/38] Return empty MimeTypesArray on levels 2 and 3. Documentation says: "(1,2) - empty MimeTypeArray object". But non-empty array was always returned. Fix it. Add condition to return empty MimeType array on levels 1 and 2. --- diff --git a/common/wrappingS-NP.js b/common/wrappingS-NP.js index 33b0c24..a8b77a3 100644 --- a/common/wrappingS-NP.js +++ b/common/wrappingS-NP.js @@ -294,7 +294,12 @@ shuffleArray(buffer); } var fakePluginArray = fakePluginArrayF(buffer); - var fakeMimeTypeArray = fakeMimeTypeArrayF(fakePluginArray); + if(args[0]==1 || args[0]==2){ + var fakeMimeTypeArray = fakeMimeTypeArrayF([]); + } + else { + var fakeMimeTypeArray = fakeMimeTypeArrayF(fakePluginArray); + } `, post_wrapping_code: [ { From 5ba375f3fc97917e7b51d202b956ed3878ed8c55 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:42:41 +0000 Subject: [PATCH 15/38] Fix: Update NP levels setting according to documentation. NP - documentation: PluginsArray: (0) - shuffled PluginArray object with modified original plugins and two fake plugins (1) - shuffled PluginArray object with two fake Plugins (2) - empty PluginArray object MimeTypesArray: (0) - modified MimeTypeArray with links to updated Plugins (1,2) - empty MimeTypeArray object --- diff --git a/common/levels.js b/common/levels.js index 461508f..3d9c315 100644 --- a/common/levels.js +++ b/common/levels.js @@ -26,7 +26,7 @@ /** * Wrapping groups * - * Used to control the built-in levels and GUI (e.g. level tweaks). + * Used to control the built-in levels and options GUI. */ var wrapping_groups = { empty_level: { /// Automatically populated @@ -34,14 +34,17 @@ var wrapping_groups = { level_id: "", level_description: "", }, - group_map: {}, ///Automatically populated - wrapper_map: {}, ///Automatically populated - group_names: [], ///Automatically populated + option_map: {}, ///Automatically populated + associated_params: {}, ///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; + if (level[group.id] === true) { + let arg_names = wrapping_groups.associated_params[group.id]; + let arg_values = arg_names.reduce(function(prev, name) { + prev.push(level[name]); + return prev; + }, []); group.wrappers.forEach((w) => wrappers.push([w, ...arg_values])); } } @@ -51,23 +54,36 @@ var wrapping_groups = { { name: "time_precision", label: "Time precision", - description: "Prevent attacks and fingerprinting techniques relying on precise time measurement (or make them harder).", - description2: ["Limit the precision of high resolution time stamps (Date, Performance, events, Gamepad API, Web VR API). Timestamps provided by the Geolocation API are wrapped as well if you enable Geolocation API wrapping"], - params: [ - { - short: "Poor", - description: "Round time to hundredths of a second (1.230)", - config: [2, false], - }, - { - short: "Low", - description: "Round time to tenths of a second (1.200)", - config: [1, false], - }, - { - short: "High", - description: "Randomize decimal digits with noise (1.451)", - config: [0, true], + description: "Limit the precision of high resolution time stamps (Date, Performance, events, Gamepad API, Web VR API)", + description2: ["Timestamps provided by the Geolocation API are wrapped as well if you enable Geolocation API wrapping"], + options: [ + { + description: "Manipulate time to", + ui_elem: "select", + name: "precision", + default: 1, + data_type: "Number", + options: [ + { + value: 2, + description: "Hundredths of a second (1.230)", + }, + { + value: 1, + description: "Tenths of a second (1.200)", + }, + { + value: 0, + description: "Full seconds (1.000)", + }, + ], + }, + { + ui_elem: "input-checkbox", + name: "randomize", + description: "Apply additional randomization after rounding (note that the random noise is influenced by the selected precision and consequently is more effective with lower time precision)", + data_type: "Boolean", + default: false, }, ], wrappers: [ @@ -89,24 +105,30 @@ var wrapping_groups = { }, { name: "htmlcanvaselement", - label: "Localy rendered images", - description: "Protect against canvas fingerprinting.", + description: "Protect against canvas fingerprinting", description2: [ "Functions canvas.toDataURL(), canvas.toBlob(), CanvasRenderingContext2D.getImageData(), OffscreenCanvas.convertToBlob() return modified image data to prevent fingerprinting", "CanvasRenderingContext2D.isPointInStroke() and CanvasRenderingContext2D.isPointInPath() are modified to lie with probability" ], - params: [ - { - short: "Little lies", - description: "Alter image data based on domain hash", - config: [0], - }, - { - short: "Strict", - description: "Replace by white image", - config: [1], - }, - ], + options: [ + { + description: "farbling type", + ui_elem: "select", + name: "method", + default: 0, + data_type: "Number", + options: [ + { + value: 0, + description: "Alter image data based on domain and session hashes", + }, + { + value: 1, + description: "Replace by white image", + } + ], + } + ], wrappers: [ // H-C "CanvasRenderingContext2D.prototype.getImageData", @@ -119,22 +141,28 @@ var wrapping_groups = { }, { name: "audiobuffer", - label: "Locally generated audio and audio card information", - description: "Protect against audio fingerprinting, spoof details of your audio card.", + description: "Protect against audio fingerprinting", description2: [ "Functions AudioBuffer.getChannelData(), AudioBuffer.copyFromChannel(), AnalyserNode.getByteTimeDomainData(), AnalyserNode.getFloatTimeDomainData(), AnalyserNode.getByteFrequencyData() and AnalyserNode.getFloatFrequencyData() are modified to alter audio data based on domain key" ], - params: [ - { - short: "Little lies", - description: "Add amplitude noise based on domain hash", - config: [0], - }, - { - short: "Strict", - description: "Replace by white noise based on domain hash", - config: [1], - }, + options: [ + { + description: "farbling type", + ui_elem: "select", + name: "method", + default: 0, + data_type: "Number", + options: [ + { + value: 0, + description: "Add amplitude noise based on domain hash", + }, + { + value: 1, + description: "Replace by white noise based on domain hash", + } + ], + } ], wrappers: [ // AUDIO @@ -148,25 +176,29 @@ var wrapping_groups = { }, { name: "webgl", - label: "Localy rendered images and graphic card information", - description: "Protect against WEBGL fingerprinting, spoof details of your graphic card.", + description: "Protect against WEBGL fingerprinting", description2: [ "Function WebGLRenderingContext.getParameter() returns modified/bottom values for certain parameters", "WebGLRenderingContext functions .getFramebufferAttachmentParameter(), .getActiveAttrib(), .getActiveUniform(), .getAttribLocation(), .getBufferParameter(), .getProgramParameter(), .getRenderbufferParameter(), .getShaderParameter(), .getShaderPrecisionFormat(), .getTexParameter(), .getUniformLocation(), .getVertexAttribOffset(), .getSupportedExtensions() and .getExtension() return modified values", "Function WebGLRenderingContext.readPixels() returns modified image data to prevent fingerprinting" ], - params: [ - { - short: "Little lies", - description: "Generate random numbers/strings and modify canvas using domain hash", - config: [0], - }, - { - short: "Strict", - description: "Return bottom values (null, empty string), empty canvas", - config: [1], - }, - ], + options: [{ + description: "farbling type", + ui_elem: "select", + name: "method", + default: 0, + data_type: "Number", + options: [ + { + value: 0, + description: "Generate random numbers/strings based on domain hash, modified canvas", + }, + { + value: 1, + description: "Return bottom values (null, empty string), empty canvas", + } + ], + }], wrappers: [ // WEBGL "WebGLRenderingContext.prototype.getParameter", @@ -205,26 +237,29 @@ var wrapping_groups = { }, { name: "plugins", - label: "Installed browser plugins", description: "Protect against plugin fingerprinting", description2: [], - params: [ - { - short: "Little lies", - description: "Edit current and add two fake plugins", - config: [0], - }, - { - short: "Fake", - description: "Return two fake plugins", - config: [1], - }, - { - short: "Empty", - description: "Return empty", - config: [2], - }, - ], + options: [{ + description: "farbling type", + ui_elem: "select", + name: "method", + default: 0, + data_type: "Number", + options: [ + { + value: 0, + description: "Edit current and add two fake plugins", + }, + { + value: 1, + description: "Return two fake plugins", + }, + { + value: 2, + description: "Return empty" + } + ], + }], wrappers: [ // NP "Navigator.prototype.plugins", // also modifies "Navigator.prototype.mimeTypes", @@ -232,28 +267,31 @@ var wrapping_groups = { }, { name: "enumerateDevices", - label: "Connected cameras and microphones", description: "Prevent fingerprinting based on the multimedia devices connected to the computer", description2: [ "Function MediaDevices.enumerateDevices() is modified to return empty or modified result" ], - params: [ - { - short: "Little lies", - description: "Randomize order", - config: [0], - }, - { - short: "Add fake", - description: "Add 0-4 fake devices and randomize order", - config: [1], - }, - { - short: "Empty", - description: "Return empty", - config: [2], - }, - ], + options: [{ + description: "farbling type", + ui_elem: "select", + name: "method", + default: 0, + data_type: "Number", + options: [ + { + value: 0, + description: "Randomize order", + }, + { + value: 1, + description: "Add 0-4 fake devices and randomize order", + }, + { + value: 2, + description: "Return empty promise" + } + ], + }], wrappers: [ // MCS "MediaDevices.prototype.enumerateDevices", @@ -261,28 +299,31 @@ var wrapping_groups = { }, { name: "hardware", - label: "Device memory and CPU", - description: "Spoof hardware information on the amount of RAM and CPU count.", + description: "Spoof hardware information to the most popular HW", description2: [ "Getters navigator.deviceMemory and navigator.hardwareConcurrency return modified values", ], - params: [ - { - short: "Low", - description: "Return random valid value between minimum and real value", - config: [0], - }, - { - short: "Medium", - description: "Return random valid value between minimum and 8", - config: [1], - }, - { - short: "High", - description: "Return 4 for navigator.deviceMemory and 2 for navigator.hardwareConcurrency", - config: [2], - }, - ], + options: [{ + description: "farbling type", + ui_elem: "select", + name: "method", + default: 0, + data_type: "Number", + options: [ + { + value: 0, + description: "Return random valid value between minimum and real value", + }, + { + value: 1, + description: "Return random valid value between minimum and 8.0", + }, + { + value: 2, + description: "Return 4 for navigator.deviceMemory and 2 for navigator.hardwareConcurrency" + } + ], + }], wrappers: [ // HTML-LS "Navigator.prototype.hardwareConcurrency", @@ -292,19 +333,25 @@ var wrapping_groups = { }, { name: "xhr", - label: "XMLHttpRequest requests (XHR)", - description: "Filter reliable XHR requests to server.", - description2: ["Note that these requests are broadly employed for benign purposes and also note that Fetch, SSE, WebRTC, and WebSockets APIs are not blocked. All provide similar and some even better means of communication with server. For practical usage, we recommend activating Fingerprint Detector instead of XHR wrappers. JShelter keeps the wrapper as it is useful for some users mainly for experimental reasons."], - params: [ - { - short: "Ask", - description: "Ask before executing an XHR request", - config: [false, true], - }, - { - short: "Block", - description: "Block all XMLHttpRequests", - config: [true, false], + description: "Filter XMLHttpRequest requests", + description2: [], + options: [ + { + ui_elem: "input-radio", + name: "behaviour", + data_type: "Boolean", + options: [ + { + value: "block", + description: "Block all XMLHttpRequest.", + default: false, + }, + { + value: "ask", + description: "Ask before executing an XHR request.", + default: true, + }, + ], }, ], wrappers: [ @@ -315,19 +362,15 @@ var wrapping_groups = { }, { name: "arrays", - label: "ArrayBuffer", - description: "Protect against ArrayBuffer exploitation, for example, to prevent side channel attacks on memory layout (or make them harder).", + description: "Protect against ArrayBuffer exploitation", description2: [], - params: [ + options: [ { - short: "Shift", - description: "Shift indexes to make memory page boundaries detection harder", - config: [false], - }, - { - short: "Randomize", - description: "Use random mapping of array indexing to memory", - config: [true], + ui_elem: "input-checkbox", + name: "mapping", + description: "Use random mapping of array indexing to memory.", + data_type: "Boolean", + default: false, }, ], wrappers: [ @@ -345,19 +388,25 @@ var wrapping_groups = { }, { name: "shared_array", - label: "SharedArrayBuffer", - description: "Protect against SharedArrayBuffer exploitation, for example, to prevent side channel attacks on memory layout (or make them harder).", + description: "Protect against SharedArrayBuffer exploitation:", description2: [], - params: [ - { - short: "Medium", - description: "Randomly slow messages to prevent high resolution timers", - config: [false], - }, - { - short: "Strict", - description: "Block SharedArrayBuffer", - config: [true], + options: [ + { + ui_elem: "input-radio", + name: "approach", + data_type: "Boolean", + options: [ + { + value: "block", + description: "Block SharedArrayBuffer.", + default: true, + }, + { + value: "polyfill", + description: "Randomly slow messages to prevent high resolution timers.", + default: false, + }, + ], }, ], wrappers: [ @@ -367,19 +416,25 @@ var wrapping_groups = { }, { name: "webworker", - label: "WebWorker", - description: "Protect against WebWorker exploitation, for example, to provide high resolution timers", + description: "Protect against WebWorker exploitation", description2: [], - params: [ - { - short: "Medium", - description: "Randomly slow messages to prevent high resolution timers", - config: [false], - }, - { - short: "Strict", - description: "Remove real parallelism, use WebWorker polyfill", - config: [true], + options: [ + { + ui_elem: "input-radio", + name: "approach", + data_type: "Boolean", + options: [ + { + value: "polyfill", + description: "Remove real parallelism, use WebWorker polyfill.", + default: true, + }, + { + value: "slow", + description: "Randomly slow messages to prevent high resolution timers.", + default: false, + }, + ], }, ], wrappers: [ @@ -388,39 +443,45 @@ var wrapping_groups = { }, { name: "geolocation", - label: "Physical location (geolocation)", - description: "Limit the information on real-world position provided by Geolocation API.", + description: "Geolocation API wrapping", description2: [], - params: [ - { - short: "Timestamp-only", - description: "Provide accurate data (use when you really need to provide exact location and you want to protect geolocation timestamps)", - config: [-1], - }, - { - short: "Village", - description: "Use accuracy of hundreds of meters", - config: [2], - }, - { - short: "Town", - description: "Use accuracy of kilometers", - config: [3], - }, - { - short: "Region", - description: "Use accuracy of tens of kilometers", - config: [4], - }, - { - short: "Long distance", - description: "Use accuracy of hundreds of kilometers", - config: [5], - }, - { - short: "Strict", - description: "Turn location services off", - config: [0], + options: [ + { + description: "Location obfuscation", + ui_elem: "select", + name: "locationObfuscationType", + default: 0, + data_type: "Number", + options: [ + { + value: 0, + description: "Turn location services off", + }, + //{ + // value: 1, + // description: "Use the position below", + //}, + { + value: 2, + description: "Use accuracy of hundreds of meters", + }, + { + value: 3, + description: "Use accuracy of kilometers", + }, + { + value: 4, + description: "Use accuracy of tens of kilometers", + }, + { + value: 5, + description: "Use accuracy of hundreds of kilometers", + }, + { + value: -1, + description: "Provide accurate data (use when you really need to provide exact location)", + }, + ], }, ], wrappers: [ @@ -437,14 +498,15 @@ var wrapping_groups = { }, { name: "physical_environment", - label: "Physical environement sensors", - description: "Limit the information provided by physical environment sensors like Magnetometer or Accelerometer.", + description: "Wrapping APIs for scanning properties of the physical environment", description2: [], - params: [ + options: [ { - short: "High", - description: "Emulate stationary device based on domain hash", - config: [true], + name: "emulateStationaryDevice", + description: "Emulate stationary device", + data_type: "Boolean", + ui_elem: "input-checkbox", + default: true, }, ], wrappers: [ @@ -460,30 +522,18 @@ var wrapping_groups = { "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" + // Here, we will add references to other GenericSensorAPI + // sensor wrappers (DeviceOrientationSensor, AmbientLightSensor, + // ProximitySensor, ...) + // We should also decide whether Bluetooth / NFC belongs here ], }, { name: "gamepads", - label: "Gamepads", - description: "Prevent websites from accessing and learning information on local gamepads.", + description: "Prevent websites from learning information on local gamepads", description2: [], - params: [ - { - short: "Strict", - description: "Hide all gamepads", - config: [true], - }, - ], + default: true, + options: [], wrappers: [ // GAMEPAD "Navigator.prototype.getGamepads", @@ -491,16 +541,10 @@ var wrapping_groups = { }, { name: "vr", - label: "Virtual and augmented reality devices", - description: "Prevent websites from accessing and learning information on local virtual and augmented reality displays.", + description: "Prevent websites from learning information on local Virtual Reality displays", description2: [], - params: [ - { - short: "Strict", - description: "Hide all devices", - config: [], - }, - ], + default: true, + options: [], wrappers: [ // VR "Navigator.prototype.activeVRDisplays", @@ -510,16 +554,10 @@ var wrapping_groups = { }, { name: "analytics", - label: "Unreliable transfers to server (beacons)", - description: "Prevent unreliable transfers to server (beacons).", - description2: ["Such transfers are typically misused for analytics but occassionally may be used by e-shops or other pages.", "Prevent sending information through Beacon API."], - params: [ - { - short: "Disabled", - description: "The wrapper performs no action", - config: [], - }, - ], + description: "Prevent sending analytics through Beacon API", + description2: [], + default: true, + options: [], wrappers: [ // BEACON "Navigator.prototype.sendBeacon", @@ -527,16 +565,10 @@ var wrapping_groups = { }, { name: "battery", - label: "Hardware battery", description: "Disable Battery status API", description2: [], - params: [ - { - short: "Disabled", - description: "Disable the API", - config: [], - }, - ], + default: true, + options: [], wrappers: [ // BATTERY "Navigator.prototype.getBattery", @@ -545,16 +577,10 @@ var wrapping_groups = { }, { name: "windowname", - label: "Persistent identifier of the browser tab", - description: "Clear window.name value on the webpage loading.", - description2: ["This API might be occasionally used for benign purposes.", "This API provides a possibility to detect cross-site browsing in one tab and broser session."], - params: [ - { - short: "Strict", - description: "Clear during page reload", - config: [], - }, - ], + description: "Clear window.name value on the webpage loading", + description2: [], + default: true, + options: [], wrappers: [ // WINDOW-NAME "window.name", @@ -601,14 +627,32 @@ function are_all_api_unsupported(wrappers) { /// Automatically populate infered metadata in wrapping_groups. wrapping_groups.groups.forEach(function (group) { group.id = group.name; - if (!are_all_api_unsupported(group.wrappers)) { - 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; - } + group.data_type = "Boolean"; + group.ui_elem = "input-checkbox"; + wrapping_groups.empty_level[group.id] = are_all_api_unsupported(group.wrappers) ? true : Boolean(group.default); + wrapping_groups.option_map[group.id] = group + wrapping_groups.associated_params[group.id] = []; + group.options.forEach((function (gid, option) { + option.id = `${gid}_${option.name}`; + if (option.default !== undefined) { + wrapping_groups.empty_level[option.id] = option.default; + wrapping_groups.associated_params[group.id].push(option.id); + } + wrapping_groups.option_map[option.id] = option; + if (option.options !== undefined) { + option.options.forEach((function (oid, choice) { + choice.id = `${oid}_${choice.value}`; + if (choice.default !== undefined) { + wrapping_groups.empty_level[choice.id] = choice.default; + wrapping_groups.associated_params[group.id].push(choice.id); + } + if (choice.ui_elem === undefined && option.ui_elem !== undefined) { + choice.ui_elem = option.ui_elem; + } + wrapping_groups.option_map[choice.id] = choice; + }).bind(null, option.id)); + } + }).bind(null, group.id)); }); // ***************************************************************************** @@ -619,83 +663,110 @@ 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": "Turn JavaScript Shield off", - "level_description": "JavaScript APIs are not wrapped. Use this level if you trust the oprator of the visited page(s) or if you do not like JavaScript Shield but apply other protection mechanisms.", + "level_text": "Turn wrappers off", + "level_description": "No protection at all", +}; + +var level_1 = { + "builtin": true, + "level_id": L1, + "level_text": "Minimal", + "level_description": "Minimal level of protection", + "time_precision": true, + "time_precision_precision": 2, + "time_precision_randomize": false, + "hardware": true, + "hardware_method": 0, + "battery": true, + "plugins": true, + "plugins_method": 0, + "geolocation": true, + "geolocation_locationObfuscationType": 2, + "analytics": true, + "windowname": true, + "physical_environment": true, + "physical_environment_emulateStationaryDevice": true, }; var level_2 = { "builtin": true, "level_id": L2, "level_text": "Recommended", - "level_description": "Make the browser appear differently to distinct fingerprinters. Apply security counter-measures that are likely not to break web pages. Slightly modify the results of API calls in different way on different domains so that the cross-site fingerprint is not stable. The generated fingerprint values also differ with each browser restart. If you need a different fingerprint for the same website without restart, use incognito mode. Keep in mind that even if you log out from a site, clear your cookies, change your IP address, the modified APIs will provide a way to compute the same fingerprint. Restart your browser if you want to change your fingerprint. If in doubt, use this level.", - "time_precision": 3, - "htmlcanvaselement": 1, - "audiobuffer": 1, - "webgl": 1, - "plugins": 2, - "enumerateDevices": 2, - "hardware": 1, - "geolocation": 3, - "physical_environment": 1, - "gamepads": 1, - "vr": 1, - "analytics": 1, - "battery": 1, - "windowname": 1, + "level_description": "Recommended level of protection for most sites", + "time_precision": true, + "time_precision_precision": 1, + "time_precision_randomize": false, + "hardware": true, + "hardware_method": 0, + "battery": true, + "htmlcanvaselement": true, + "htmlcanvaselement_method": 0, + "audiobuffer": true, + "audiobuffer_method": 0, + "webgl": true, + "webgl_method": 0, + "plugins": true, + "plugins_method": 1, + "enumerateDevices": true, + "enumerateDevices_method": 1, + "geolocation": true, + "geolocation_locationObfuscationType": 3, + "gamepads": true, + "vr": true, + "analytics": true, + "windowname": true, + "physical_environment": true, + "physical_environment_emulateStationaryDevice": true, }; var level_3 = { "builtin": true, "level_id": L3, - "level_text": "Strict", - "level_description": "Enable all non-experimental protection. The wrapped APIs return fake values. Some APIs are blocked completely, others provide meaningful but rare values. Some return values are meaningless. This level will make you fingerprintable because the results of API calls are generally modified in the same way on all webistes and in each session. Use this level if you want to limit the information provided by your browser. If you are worried about fingerprinters, make sure the Fingerprint Detector is activated.", - "time_precision": 3, - "htmlcanvaselement": 2, - "audiobuffer": 2, - "webgl": 2, - "plugins": 3, - "enumerateDevices": 3, - "hardware": 3, - "webworker": 2, - "geolocation": 6, - "physical_environment": 1, - "gamepads": 1, - "vr": 1, - "analytics": 1, - "battery": 1, - "windowname": 1, + "level_text": "High", + "level_description": "High level of protection", + "time_precision": true, + "time_precision_precision": 0, + "time_precision_randomize": true, + "hardware": true, + "hardware_method": 2, + "battery": true, + "htmlcanvaselement": true, + "htmlcanvaselement_method": 1, + "audiobuffer": true, + "audiobuffer_method": 1, + "webgl": true, + "webgl_method": 1, + "plugins": true, + "plugins_method": 2, + "enumerateDevices": true, + "enumerateDevices_method": 2, + "xhr": true, + "xhr_behaviour_block": false, + "xhr_behaviour_ask": true, + "arrays": true, + "arrays_mapping": true, + "shared_array": true, + "shared_array_approach_block": true, + "shared_array_approach_polyfill": false, + "webworker": true, + "webworker_approach_polyfill": true, + "webworker_approach_slow": false, + "geolocation": true, + "geolocation_locationObfuscationType": 0, + "gamepads": true, + "vr": true, + "analytics": true, + "windowname": true, + "physical_environment": true, + "physical_environment_emulateStationaryDevice": true, }; -var level_experimental = { - "builtin": true, - "level_id": L_EXPERIMENTAL, - "level_text": "Experimental", - "level_description": "Strict level protections with additional wrappers enabled (including APIs known to regularly break webpages and APIs that do not work perfectly). Use this level if you want to experiment with JShelter. Use Recommended or Strict level with active Fingerprint Detector for your regular activities.", - "time_precision": 3, - "htmlcanvaselement": 2, - "audiobuffer": 2, - "webgl": 2, - "plugins": 3, - "enumerateDevices": 3, - "hardware": 3, - "xhr": 1, - "arrays": 2, - "shared_array": 2, - "webworker": 2, - "geolocation": 6, - "physical_environment": 1, - "gamepads": 1, - "vr": 1, - "analytics": 1, - "battery": 1, - "windowname": 1, -}; +const BUILTIN_LEVEL_NAMES = [L0, L1, L2, L3]; var levels = {}; var default_level = {}; @@ -704,9 +775,9 @@ var wrapped_codes = {}; 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 + [level_3.level_id]: level_3 }; default_level = Object.create(levels[L2]); default_level.level_text = "Default"; @@ -741,24 +812,31 @@ function updateLevels(res) { } default_level.is_default = true; var new_domains = res["domains"] || {}; - for (let [d, {level_id, tweaks, restore, restore_tweaks}] of Object.entries(new_domains)) { + for (let [d, {level_id, tweaks}] of Object.entries(new_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; + } else if (tweaks) { + // this domain has "tweaked" wrapper groups from other levels, let's merge them + level = Object.assign({tweaks}, level); + for ([group, tlev_id] of Object.entries(tweaks)) { + if (tlev_id === level_id) { + // redundant tweak: same level + delete tweaks[group]; + continue; + } + // cleanup original group settings for this level + delete level[group]; + let prefix = `${group}_`; + for (let key of Object.keys(level).filter(k => k.startsWith(prefix))) delete[key]; + // now copy the group settings from the tweak level + let tweakLevel = levels[tlev_id]; + if (tweakLevel[group]) { + level[group] = tweakLevel[group]; + for (let key of Object.keys(tweakLevel).filter(k => k.startsWith(prefix))) level[key] = tweakLevel[key]; } } + delete level.wrappers; // we will lazy instantiate them on demand in getCurrentLevelJSON() } domains[d] = level; } @@ -781,27 +859,17 @@ function setDefaultLevel(level) { function saveDomainLevels() { tobesaved = {}; for (k in domains) { - let {level_id, tweaks, restore, restore_tweaks} = domains[k]; + let {level_id, tweaks} = domains[k]; if (k[k.length - 1] === ".") { k = k.substring(0, k.length-1); } 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; + for (let [group, tlev_id] of Object.entries(tweaks)) { + if (tlev_id === level_id) delete tweaks[group]; // remove redundant entries } + if (Object.keys(tweaks).length === 0) delete tweaks; } 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}); } @@ -820,14 +888,3 @@ function getCurrentLevelJSON(url) { } return [default_level, wrapped_codes[default_level.level_id]]; } - -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; -} From 0ec554f0c5951e3055a317ebf024f1ea960956dd Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:43:12 +0000 Subject: [PATCH 16/38] Integration tests: Update Plugins and MimeTypes expected values. Update expected values according to documentation and source code changes. Previous configuration was wrong according to documentation. Fix it. Ignore non-empty values in Google Chrome - not able to perform tests, because Selenium modifies Plugins and MimeTypes arrays. --- diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index b58d353..6dd3de9 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -1,5 +1,5 @@ # -# JavaScript Restrictor is a browser extension which increases level +# JShelter is a browser extension which increases level # of security, anonymity and privacy of the user while browsing the # internet. # @@ -26,7 +26,7 @@ from values_tested import TestedValues from web_browser_type import BrowserType -## Module contains definitions for expected values of default levels od JSR. +## Module contains definitions for expected values of default levels od JShelter. # # Expected values are comparing during testing with current values of variables. # 'REAL VALUE' means that current value should not be spoofed. @@ -35,11 +35,13 @@ from web_browser_type import BrowserType # This module can be edited when definition of default levels will be changed. -## Expected values for default level 0 of JSR. -# Ignore Plugins and mimeTypes test - explanation: +# Ignore Plugins and mimeTypes tests - explanation: # The apparent modification of the plugins is caused by the Selenium environment in which the testing takes place. # This difference only appears in a browser controlled by Selenium. # This issue is not caused by JShield, but by Selenium. + + +## Expected values for default level 0 of JShelter. level0 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -75,11 +77,11 @@ level0 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 'EXACTLY'}, - plugins={'count': {BrowserType.FIREFOX: 0, + plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'EMPTY', + 'value': {BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='IGNORE', + mimeTypes='REAL VALUE', get_channel= 'REAL VALUE', copy_channel= 'REAL VALUE', byte_time_domain= 'REAL VALUE', @@ -101,7 +103,7 @@ level0 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 1 of JSR. +## Expected values for default level 1 of JShelter. level1 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -142,10 +144,10 @@ level1 = TestedValues( time={'value': 'REAL VALUE', 'accuracy': 0.01}, plugins={'count': {BrowserType.FIREFOX: 0, - BrowserType.CHROME: 'REAL VALUE'}, + BrowserType.CHROME: 'IGNORE'}, 'value': {BrowserType.FIREFOX: 'EMPTY', - BrowserType.CHROME: 'REAL VALUE'}}, - mimeTypes='REAL VALUE', + BrowserType.CHROME: 'IGNORE'}}, + mimeTypes='SPOOF VALUE', get_channel= 'REAL VALUE', copy_channel= 'REAL VALUE', byte_time_domain= 'REAL VALUE', @@ -167,7 +169,7 @@ level1 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 2 of JSR. +## Expected values for default level 2 of JShelter. level2 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -207,11 +209,11 @@ level2 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.1}, - plugins={'count': {BrowserType.FIREFOX: 'PLUS_2', + plugins={'count': {BrowserType.FIREFOX: 0, BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'SPOOF VALUE', + 'value': {BrowserType.FIREFOX: 'EMPTY', BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='SPOOF VALUE', + mimeTypes='EMPTY', get_channel= 'SPOOF VALUE', copy_channel= 'SPOOF VALUE', byte_time_domain= 'SPOOF VALUE', @@ -233,7 +235,7 @@ level2 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 3 of JSR. +## Expected values for default level 3 of JShelter. level3 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -289,7 +291,7 @@ level3 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for custom level 4 of JSR. +## Expected values for custom level 4 of JShelter. ## The hard-coded configuration of the level 4 is defined in the file web_browser.py in function define_test_level. level4 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', From 37d0ab3f16971d0bab0b104fb56c3b71bf75d04f Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:51:45 +0000 Subject: [PATCH 17/38] Integration tests: Correct Plugins test. The apparent modification (on level 0) of the plugins is caused by the Selenium environment in which the testing takes place. --- diff --git a/tests/integration_tests/testing/tests_definition/test_navigator.py b/tests/integration_tests/testing/tests_definition/test_navigator.py index 4917be1..187e590 100644 --- a/tests/integration_tests/testing/tests_definition/test_navigator.py +++ b/tests/integration_tests/testing/tests_definition/test_navigator.py @@ -1,10 +1,10 @@ # -# JShelter is a browser extension which increases level +# JavaScript Restrictor is a browser extension which increases level # of security, anonymity and privacy of the user while browsing the # internet. # +# Copyright (C) 2020 Martin Bednar # Copyright (C) 2021 Matus Svancar -# Copyright (C) 2022 Martin Bednar # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -109,7 +109,7 @@ def test_oscpu(browser, navigator, expected): ## Test plugins count def test_plugins_count(browser, navigator, expected): - if expected.navigator.plugins['count'][browser.type] == 'IGNORE': + if expected.navigator.mimeTypes == 'IGNORE': return elif expected.navigator.plugins['count'][browser.type] == 'REAL VALUE': assert len(navigator['plugins']) == len(browser.real.navigator.plugins) @@ -120,7 +120,7 @@ def test_plugins_count(browser, navigator, expected): ## Test plugins array value def test_plugins(browser, navigator, expected): - if expected.navigator.plugins['count'][browser.type] == 'IGNORE': + if expected.navigator.mimeTypes == 'IGNORE': return elif expected.navigator.plugins['value'][browser.type] == 'REAL VALUE': assert navigator['plugins'] == browser.real.navigator.plugins diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index 6dd3de9..9ba2c81 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -1,5 +1,5 @@ # -# JShelter is a browser extension which increases level +# JavaScript Restrictor is a browser extension which increases level # of security, anonymity and privacy of the user while browsing the # internet. # @@ -26,7 +26,7 @@ from values_tested import TestedValues from web_browser_type import BrowserType -## Module contains definitions for expected values of default levels od JShelter. +## Module contains definitions for expected values of default levels od JSR. # # Expected values are comparing during testing with current values of variables. # 'REAL VALUE' means that current value should not be spoofed. @@ -35,13 +35,11 @@ from web_browser_type import BrowserType # This module can be edited when definition of default levels will be changed. -# Ignore Plugins and mimeTypes tests - explanation: +## Expected values for default level 0 of JSR. +# Ignore Plugins and mimeTypes test - explanation: # The apparent modification of the plugins is caused by the Selenium environment in which the testing takes place. # This difference only appears in a browser controlled by Selenium. # This issue is not caused by JShield, but by Selenium. - - -## Expected values for default level 0 of JShelter. level0 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -77,11 +75,11 @@ level0 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 'EXACTLY'}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 'IGNORE', BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'REAL VALUE', + 'value': {BrowserType.FIREFOX: 'IGNORE', BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='REAL VALUE', + mimeTypes='IGNORE', get_channel= 'REAL VALUE', copy_channel= 'REAL VALUE', byte_time_domain= 'REAL VALUE', @@ -103,7 +101,7 @@ level0 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 1 of JShelter. +## Expected values for default level 1 of JSR. level1 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -143,11 +141,11 @@ level1 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.01}, - plugins={'count': {BrowserType.FIREFOX: 0, - BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'EMPTY', - BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='SPOOF VALUE', + plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + BrowserType.CHROME: 'REAL VALUE'}, + 'value': {BrowserType.FIREFOX: 'REAL VALUE', + BrowserType.CHROME: 'REAL VALUE'}}, + mimeTypes='REAL VALUE', get_channel= 'REAL VALUE', copy_channel= 'REAL VALUE', byte_time_domain= 'REAL VALUE', @@ -169,7 +167,7 @@ level1 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 2 of JShelter. +## Expected values for default level 2 of JSR. level2 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -209,11 +207,11 @@ level2 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.1}, - plugins={'count': {BrowserType.FIREFOX: 0, - BrowserType.CHROME: 'IGNORE'}, + plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + BrowserType.CHROME: 'PLUS_2'}, 'value': {BrowserType.FIREFOX: 'EMPTY', - BrowserType.CHROME: 'IGNORE'}}, - mimeTypes='EMPTY', + BrowserType.CHROME: 'SPOOF VALUE'}}, + mimeTypes='SPOOF VALUE', get_channel= 'SPOOF VALUE', copy_channel= 'SPOOF VALUE', byte_time_domain= 'SPOOF VALUE', @@ -235,7 +233,7 @@ level2 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for default level 3 of JShelter. +## Expected values for default level 3 of JSR. level3 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'REAL VALUE'}, @@ -291,7 +289,7 @@ level3 = TestedValues( methods_toString='REAL VALUE' ) -## Expected values for custom level 4 of JShelter. +## Expected values for custom level 4 of JSR. ## The hard-coded configuration of the level 4 is defined in the file web_browser.py in function define_test_level. level4 = TestedValues( user_agent={BrowserType.FIREFOX: 'REAL VALUE', From ee714efe72937928d06b2340ebeb6aa78afdac55 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:53:34 +0000 Subject: [PATCH 18/38] Unit tests: Init for ECMA-SHARED tests. --- diff --git a/tests/unit_tests/config/global.json b/tests/unit_tests/config/global.json index 947108c..7ce40ba 100644 --- a/tests/unit_tests/config/global.json +++ b/tests/unit_tests/config/global.json @@ -348,74 +348,6 @@ ] } ] - }, - { - "name": "wrappingS-ECMA-ARRAY", - "remove_custom_namespace": true, - "let_to_var": false, - "src_script_requirements": [ - { - "type": "const", - "requirements": [ - { - "from": "./wrapping.js", - "objects": [ - "add_wrappers" - ] - } - ] - } - ], - "extra_exports": [ - "packIEEE754", - "unpackIEEE754", - "unpackF64", - "packF64", - "unpackF32", - "packF32", - "constructDecorator", - "offsetDecorator", - "redefineNewArrayFunctions", - "redefineNewArrayConstructors", - "proxyHandler", - "getByteDecorator", - "setByteDecorator", - "getFloatDecorator", - "setFloatDecorator", - "getBigIntDecorator", - "setBigIntDecorator", - "redefineDataViewFunctions" - ], - "test_script_requirements": [ - { - "type": "const", - "requirements": [ - { - "from": "./wrappingS-ECMA-ARRAY.js", - "objects": [ - "packIEEE754", - "unpackIEEE754", - "unpackF64", - "packF64", - "unpackF32", - "packF32", - "constructDecorator", - "offsetDecorator", - "redefineNewArrayFunctions", - "redefineNewArrayConstructors", - "proxyHandler", - "getByteDecorator", - "setByteDecorator", - "getFloatDecorator", - "setFloatDecorator", - "getBigIntDecorator", - "setBigIntDecorator", - "redefineDataViewFunctions" - ] - } - ] - } - ] } ] } diff --git a/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js index 85bde3c..a5ddfdb 100644 --- a/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js +++ b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js @@ -39,4 +39,4 @@ describe("ECMA-SHARED", function() { expect(wrappers).toBeDefined(); }); }); -}); +}); \ No newline at end of file From 098acae8535cf97975f3ba9717df3e66047a112c Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:54:40 +0000 Subject: [PATCH 19/38] Unit tests: Init for ECMA-ARRAY tests. --- diff --git a/tests/unit_tests/config/global.json b/tests/unit_tests/config/global.json index 7ce40ba..947108c 100644 --- a/tests/unit_tests/config/global.json +++ b/tests/unit_tests/config/global.json @@ -348,6 +348,74 @@ ] } ] + }, + { + "name": "wrappingS-ECMA-ARRAY", + "remove_custom_namespace": true, + "let_to_var": false, + "src_script_requirements": [ + { + "type": "const", + "requirements": [ + { + "from": "./wrapping.js", + "objects": [ + "add_wrappers" + ] + } + ] + } + ], + "extra_exports": [ + "packIEEE754", + "unpackIEEE754", + "unpackF64", + "packF64", + "unpackF32", + "packF32", + "constructDecorator", + "offsetDecorator", + "redefineNewArrayFunctions", + "redefineNewArrayConstructors", + "proxyHandler", + "getByteDecorator", + "setByteDecorator", + "getFloatDecorator", + "setFloatDecorator", + "getBigIntDecorator", + "setBigIntDecorator", + "redefineDataViewFunctions" + ], + "test_script_requirements": [ + { + "type": "const", + "requirements": [ + { + "from": "./wrappingS-ECMA-ARRAY.js", + "objects": [ + "packIEEE754", + "unpackIEEE754", + "unpackF64", + "packF64", + "unpackF32", + "packF32", + "constructDecorator", + "offsetDecorator", + "redefineNewArrayFunctions", + "redefineNewArrayConstructors", + "proxyHandler", + "getByteDecorator", + "setByteDecorator", + "getFloatDecorator", + "setFloatDecorator", + "getBigIntDecorator", + "setBigIntDecorator", + "redefineDataViewFunctions" + ] + } + ] + } + ] } ] } diff --git a/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js index a5ddfdb..85bde3c 100644 --- a/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js +++ b/tests/unit_tests/tests/wrappingS-ECMA-SHARED_tests.js @@ -39,4 +39,4 @@ describe("ECMA-SHARED", function() { expect(wrappers).toBeDefined(); }); }); -}); \ No newline at end of file +}); From 96ccd6ebd307ac0faa5341fc66eec0d221ca4d7b Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:55:07 +0000 Subject: [PATCH 20/38] Integration tests: Set a lower deviation between the browser and the system time. --- diff --git a/tests/integration_tests/testing/tests_definition/test_time.py b/tests/integration_tests/testing/tests_definition/test_time.py index dfc8444..4675e8c 100644 --- a/tests/integration_tests/testing/tests_definition/test_time.py +++ b/tests/integration_tests/testing/tests_definition/test_time.py @@ -1,9 +1,9 @@ # -# JShelter is a browser extension which increases level +# JavaScript Restrictor is a browser extension which increases level # of security, anonymity and privacy of the user while browsing the # internet. # -# Copyright (C) 2022 Martin Bednar +# Copyright (C) 2020 Martin Bednar # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -47,28 +47,5 @@ def test_hours_minutes_seconds(browser): p_now = datetime.now() p_time = p_now.hour * 60 * 60 + p_now.minute * 60 + p_now.second # Values do not have to be strictly equal. - # A deviation of less than 1 is tolerated. - assert abs(js_time - p_time) <= 1 - - -## Test time accuracy. -def test_accuracy(browser, expected): - #Suppose time is rounded. - is_time_rounded = True - # Make 3 measurement. - for _ in range(3): - # Wait a while to value of time will be changed. - time.sleep(random.randint(1, 3)) - miliseconds = browser.driver.execute_script("let d = new Date();" - "return d.getMilliseconds()") - if expected.time['accuracy'] == 'EXACTLY': - if int(miliseconds / 10) * 10 != miliseconds: - # miliseconds was not rounded. At least one of three measurement has to say value was not rounded. - is_time_rounded = False - else: - assert is_in_accuracy(miliseconds, expected.time['accuracy']) - - if expected.time['accuracy'] == 'EXACTLY': - # At least one of three measurement has to say value was not rounded. - # is_time_rounded should be false if EXACTLY value is required. - assert not is_time_rounded + # A deviation of less than 4 is tolerated. + assert abs(js_time - p_time) < 2 From 91bf548a6edf7d8145fda241ca19887b24a261cb Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:56:12 +0000 Subject: [PATCH 21/38] Integration tests: PluginArray - level 0 in Firefox - set to REAL VALUE (empty array). --- diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index 9ba2c81..c8dc35c 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -75,9 +75,9 @@ level0 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 'EXACTLY'}, - plugins={'count': {BrowserType.FIREFOX: 'IGNORE', + plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'IGNORE', + 'value': {BrowserType.FIREFOX: 'REAL VALUE', BrowserType.CHROME: 'IGNORE'}}, mimeTypes='IGNORE', get_channel= 'REAL VALUE', From 3a4bc11a939575da14cbd83cc8cde525b87162a0 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:56:24 +0000 Subject: [PATCH 22/38] Integration tests: PluginArray - level 0 in Firefox - update expected values. --- diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index c8dc35c..f871fb4 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -75,9 +75,9 @@ level0 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 'EXACTLY'}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 0, BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'REAL VALUE', + 'value': {BrowserType.FIREFOX: 'EMPTY', BrowserType.CHROME: 'IGNORE'}}, mimeTypes='IGNORE', get_channel= 'REAL VALUE', @@ -141,9 +141,9 @@ level1 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.01}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 0, BrowserType.CHROME: 'REAL VALUE'}, - 'value': {BrowserType.FIREFOX: 'REAL VALUE', + 'value': {BrowserType.FIREFOX: 'EMPTY', BrowserType.CHROME: 'REAL VALUE'}}, mimeTypes='REAL VALUE', get_channel= 'REAL VALUE', @@ -207,9 +207,9 @@ level2 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.1}, - plugins={'count': {BrowserType.FIREFOX: 'REAL VALUE', + plugins={'count': {BrowserType.FIREFOX: 'PLUS_2', BrowserType.CHROME: 'PLUS_2'}, - 'value': {BrowserType.FIREFOX: 'EMPTY', + 'value': {BrowserType.FIREFOX: 'SPOOF VALUE', BrowserType.CHROME: 'SPOOF VALUE'}}, mimeTypes='SPOOF VALUE', get_channel= 'SPOOF VALUE', From 6a7e0cc3571f96ae8d3882a04923a0acd7eb588d Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:56:35 +0000 Subject: [PATCH 23/38] Integration tests: Ignore PluginArray modified by Selenium. --- diff --git a/tests/integration_tests/testing/tests_definition/test_navigator.py b/tests/integration_tests/testing/tests_definition/test_navigator.py index 187e590..ad15c3b 100644 --- a/tests/integration_tests/testing/tests_definition/test_navigator.py +++ b/tests/integration_tests/testing/tests_definition/test_navigator.py @@ -3,8 +3,8 @@ # of security, anonymity and privacy of the user while browsing the # internet. # -# Copyright (C) 2020 Martin Bednar # Copyright (C) 2021 Matus Svancar +# Copyright (C) 2022 Martin Bednar # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -109,7 +109,7 @@ def test_oscpu(browser, navigator, expected): ## Test plugins count def test_plugins_count(browser, navigator, expected): - if expected.navigator.mimeTypes == 'IGNORE': + if expected.navigator.plugins['count'][browser.type] == 'IGNORE': return elif expected.navigator.plugins['count'][browser.type] == 'REAL VALUE': assert len(navigator['plugins']) == len(browser.real.navigator.plugins) @@ -120,7 +120,7 @@ def test_plugins_count(browser, navigator, expected): ## Test plugins array value def test_plugins(browser, navigator, expected): - if expected.navigator.mimeTypes == 'IGNORE': + if expected.navigator.plugins['count'][browser.type] == 'IGNORE': return elif expected.navigator.plugins['value'][browser.type] == 'REAL VALUE': assert navigator['plugins'] == browser.real.navigator.plugins diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index f871fb4..b58d353 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -208,9 +208,9 @@ level2 = TestedValues( time={'value': 'REAL VALUE', 'accuracy': 0.1}, plugins={'count': {BrowserType.FIREFOX: 'PLUS_2', - BrowserType.CHROME: 'PLUS_2'}, + BrowserType.CHROME: 'IGNORE'}, 'value': {BrowserType.FIREFOX: 'SPOOF VALUE', - BrowserType.CHROME: 'SPOOF VALUE'}}, + BrowserType.CHROME: 'IGNORE'}}, mimeTypes='SPOOF VALUE', get_channel= 'SPOOF VALUE', copy_channel= 'SPOOF VALUE', From 6e72316e6f03d011659e8cd0d055108d148b891c Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:58:33 +0000 Subject: [PATCH 24/38] Integration tests: Add the time accuracy test. --- diff --git a/tests/integration_tests/testing/tests_definition/test_time.py b/tests/integration_tests/testing/tests_definition/test_time.py index 4675e8c..364bc1c 100644 --- a/tests/integration_tests/testing/tests_definition/test_time.py +++ b/tests/integration_tests/testing/tests_definition/test_time.py @@ -3,7 +3,7 @@ # of security, anonymity and privacy of the user while browsing the # internet. # -# Copyright (C) 2020 Martin Bednar +# Copyright (C) 2022 Martin Bednar # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -47,5 +47,28 @@ def test_hours_minutes_seconds(browser): p_now = datetime.now() p_time = p_now.hour * 60 * 60 + p_now.minute * 60 + p_now.second # Values do not have to be strictly equal. - # A deviation of less than 4 is tolerated. - assert abs(js_time - p_time) < 2 + # A deviation of less than 1 is tolerated. + assert abs(js_time - p_time) <= 1 + + +## Test time accuracy. +def test_accuracy(browser, expected): + #Suppose time is rounded. + is_time_rounded = True + # Make 3 measurement. + for _ in range(3): + # Wait a while to value of time will be changed. + time.sleep(random.randint(1, 3)) + miliseconds = browser.driver.execute_script("let d = new Date();" + "return d.getMilliseconds()") + if expected.time['accuracy'] == 'EXACTLY': + if int(miliseconds / 10) * 10 != miliseconds: + # miliseconds was not rounded. At least one of three measurement has to say value was not rounded. + is_time_rounded = False + else: + assert is_in_accuracy(miliseconds, expected.time['accuracy']) + + if expected.time['accuracy'] == 'EXACTLY': + # At least one of three measurement has to say value was not rounded. + # is_time_rounded should be false if EXACTLY value is required. + assert not is_time_rounded From 26356cadc3cb3e04bed9aaa599cac2a86d2c83af Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:58:41 +0000 Subject: [PATCH 25/38] Integration tests: Add ARRAYS test: crypto.getRandomValues. Known bug in the production - function window.crypto.getRandomValues(array) fails when called. The bug is caused by passing a proxy array to the function, but the actual array is expected (not the proxy). --- diff --git a/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py new file mode 100644 index 0000000..13d21a5 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py @@ -0,0 +1,47 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2022 Martin Bednar +# +# 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 . +# + +import pytest +from selenium.webdriver.common.by import By + +from configuration import get_config + +## Setup method - it is run before time tests execution starts. +# +# This setup method open testing page. +@pytest.fixture(scope='module', autouse=True) +def load_test_page(browser): + browser.driver.get(get_config("testing_page")) + + +## Test crypto.getRandomValues. +# Random values should be generated. No error in Javascript runtime should appear. +# \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. +# Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). +def test_crypto_getRandomValues(browser): + ul = browser.driver.find_element(By.ID,"getRandomValues") + if len(ul.text) > 0: + items = ul.find_elements(By.TAG_NAME,"li") + assert len(items) > 0 + else: + pytest.fail("No random value generated. Probable JavaScript error: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView.") From eb2d66f516049bd8d4362e9bd79aca3ab0ed365e Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:58:52 +0000 Subject: [PATCH 26/38] Integration tests: Update tested levels. Levels has been changed in JShelter. Level 1 was removed and level "Experiment" was added. Adapt the tested levels to the new settings. --- diff --git a/tests/integration_tests/testing/configuration.py b/tests/integration_tests/testing/configuration.py index bea2af6..b9a535f 100644 --- a/tests/integration_tests/testing/configuration.py +++ b/tests/integration_tests/testing/configuration.py @@ -35,7 +35,7 @@ class __Config: # Browsers in which tests will be run. tested_browsers = [BrowserType.CHROME, BrowserType.FIREFOX] # Default levels of JShelter which will be tested. - tested_jsr_levels = [0, 1, 2, 3] + tested_jsr_levels = [0, 2, 3, "Experiment"] diff --git a/tests/integration_tests/testing/conftest.py b/tests/integration_tests/testing/conftest.py index 82b7a84..e689467 100644 --- a/tests/integration_tests/testing/conftest.py +++ b/tests/integration_tests/testing/conftest.py @@ -54,3 +54,7 @@ def expected(): return values_expected.level3 elif get_shared_browser().jsr_level == 4: return values_expected.level4 + elif get_shared_browser().jsr_level == "Experiment": + return values_expected.level3 + else: + return values_expected.level3 From f9a037adfc6c8030b92a65db43d6efeca4f2d199 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:59:16 +0000 Subject: [PATCH 27/38] Integration tests: Update available levels in JShelter setting. Levels has been changed in JShelter. The level 1 was removed and the level "Experiment" was added. --- diff --git a/tests/integration_tests/testing/tests_definition/test_domain_level_setting.py b/tests/integration_tests/testing/tests_definition/test_domain_level_setting.py index 33e6a98..091cc57 100644 --- a/tests/integration_tests/testing/tests_definition/test_domain_level_setting.py +++ b/tests/integration_tests/testing/tests_definition/test_domain_level_setting.py @@ -28,7 +28,7 @@ import random domains = ["messenger.com", "email.seznam.cz", "facebook.com", "www.fit.vutbr.cz"] -levels = ['0', '1', '2', '3'] +levels = ['0', '2', '3', 'Experiment'] def set_domain_level(browser, domain, level): From 3457eb0421ffa866de0a5b7dd961d23fa0889676 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:59:43 +0000 Subject: [PATCH 28/38] Integration tests: NBS switch - select second (not first) switch. In the previous version, NBS switch was the first one, but in this version, it is the second one, because JS wrapping switch is before it. In the test, select the second (not the first) switch, which is now NBS switch. --- diff --git a/tests/integration_tests/testing/tests_definition/test_NBS_setting.py b/tests/integration_tests/testing/tests_definition/test_NBS_setting.py index c30e704..e26368b 100644 --- a/tests/integration_tests/testing/tests_definition/test_NBS_setting.py +++ b/tests/integration_tests/testing/tests_definition/test_NBS_setting.py @@ -29,14 +29,14 @@ from time import sleep def switch_NBS_setting(browser): browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) sleep(1) - browser.driver.find_elements(By.CLASS_NAME, 'slider')[0].click() + browser.driver.find_elements(By.CLASS_NAME, 'slider')[1].click() sleep(1) def get_NBS_setting(browser): browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) sleep(2) - return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('.switch .slider'),':before').getPropertyValue('content')")) + return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('#nbs_whitelist .switch_wrapper .switch .slider'),':before').getPropertyValue('content')")) ## Test turnning NBS off in popup. From f9d20fe0568c87c2d759e8e20b112340b4850be3 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 12:59:54 +0000 Subject: [PATCH 29/38] Integration tests: Expect failure of the ECMA_ARRAY test - the known bug. --- diff --git a/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py index 13d21a5..72502fd 100644 --- a/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py +++ b/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py @@ -38,6 +38,7 @@ def load_test_page(browser): # Random values should be generated. No error in Javascript runtime should appear. # \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. # Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). +@pytest.mark.xfail def test_crypto_getRandomValues(browser): ul = browser.driver.find_element(By.ID,"getRandomValues") if len(ul.text) > 0: From 8123a0da151b121002b8fa42885700d6fa8346d4 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:00:14 +0000 Subject: [PATCH 30/38] Integration tests: Fix expected values for Plugins Array in Firefox according to doc. --- diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index b58d353..799ade3 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -207,9 +207,9 @@ level2 = TestedValues( referrer='REAL VALUE', time={'value': 'REAL VALUE', 'accuracy': 0.1}, - plugins={'count': {BrowserType.FIREFOX: 'PLUS_2', + plugins={'count': {BrowserType.FIREFOX: 0, BrowserType.CHROME: 'IGNORE'}, - 'value': {BrowserType.FIREFOX: 'SPOOF VALUE', + 'value': {BrowserType.FIREFOX: 'EMPTY', BrowserType.CHROME: 'IGNORE'}}, mimeTypes='SPOOF VALUE', get_channel= 'SPOOF VALUE', From 2b985df6fc8f90ccca2971c829547c23db65cd8f Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:00:26 +0000 Subject: [PATCH 31/38] Integration tests: Define exact order of running the tests. HW tests has to be run in the beginning otherwise they crash (unknown reason). Define exact order of test to prevent crashes of HW tests. --- diff --git a/tests/integration_tests/testing/tests_definition/test_01_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_01_ECMA_arrays.py new file mode 100644 index 0000000..72502fd --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_01_ECMA_arrays.py @@ -0,0 +1,48 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2022 Martin Bednar +# +# 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 . +# + +import pytest +from selenium.webdriver.common.by import By + +from configuration import get_config + +## Setup method - it is run before time tests execution starts. +# +# This setup method open testing page. +@pytest.fixture(scope='module', autouse=True) +def load_test_page(browser): + browser.driver.get(get_config("testing_page")) + + +## Test crypto.getRandomValues. +# Random values should be generated. No error in Javascript runtime should appear. +# \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. +# Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). +@pytest.mark.xfail +def test_crypto_getRandomValues(browser): + ul = browser.driver.find_element(By.ID,"getRandomValues") + if len(ul.text) > 0: + items = ul.find_elements(By.TAG_NAME,"li") + assert len(items) > 0 + else: + pytest.fail("No random value generated. Probable JavaScript error: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView.") diff --git a/tests/integration_tests/testing/tests_definition/test_02_NBS_setting.py b/tests/integration_tests/testing/tests_definition/test_02_NBS_setting.py new file mode 100644 index 0000000..691e7c5 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_02_NBS_setting.py @@ -0,0 +1,57 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest +from selenium.webdriver.common.by import By +from time import sleep + + +def switch_NBS_setting(browser): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) + sleep(1) + browser.driver.find_elements(By.CLASS_NAME, 'slider')[1].click() + sleep(1) + + +def get_NBS_setting(browser): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) + sleep(2) + return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('#nbs_whitelist .switch_wrapper .switch .slider'),':before').getPropertyValue('content')")) + + +## Test turnning NBS off in popup. +## Sleep 0.5 second to changes take effect. +def test_switching_NBS(browser): + NBS_setting_values = ['"ON"', '"OFF"'] + + original_setting = get_NBS_setting(browser) + original_setting_index = NBS_setting_values.index(original_setting) + + # Range is saing how many times should NBS be switched. + for i in range(4): + switch_NBS_setting(browser) + assert get_NBS_setting(browser) == NBS_setting_values[(i + 1 + original_setting_index) % 2] + + # Return original value + if get_NBS_setting(browser) != original_setting: + switch_NBS_setting(browser) diff --git a/tests/integration_tests/testing/tests_definition/test_03_hw.py b/tests/integration_tests/testing/tests_definition/test_03_hw.py new file mode 100644 index 0000000..a7bfb54 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_03_hw.py @@ -0,0 +1,82 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest + +from values_getters import get_device, get_IOdevices + + +## Setup method - it is run before hw tests execution starts. +# +# This setup method initialize variable device that contains current data about device and +# this variable is provided to device tests and values in device variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def device(browser): + return get_device(browser.driver) + + +## Setup method - it is run before hw tests execution starts. +# +# This setup method initialize variable IOdevices that contains current data about IO devices and +# this variable is provided to device tests and values in IOdevices variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def IOdevices(browser): + return get_IOdevices(browser.driver) + + +## Test device memory. +def test_device_memory(browser, device, expected): + if expected.device.deviceMemory[browser.type] == 'SPOOF VALUE': + assert device['deviceMemory'] in expected.device.deviceMemory['valid_values'] + assert device['deviceMemory'] <= browser.real.device.deviceMemory + else: + assert device['deviceMemory'] == browser.real.device.deviceMemory + + +## Test hardware concurrency. +def test_hardware_concurrency(browser, device, expected): + if expected.device.hardwareConcurrency['value'] == 'REAL VALUE': + assert device['hardwareConcurrency'] == browser.real.device.hardwareConcurrency + elif expected.device.hardwareConcurrency['value'] == 'SPOOF VALUE': + expectedval = expected.device.hardwareConcurrency['valid_values'] + if expectedval == "UP TO REAL VALUE": + expectedval = range(browser.real.device.hardwareConcurrency + 1) + assert device['hardwareConcurrency'] in expectedval + else: + assert False # We should not get here + + +## Test IOdevices. +def test_IOdevices(browser, IOdevices, expected): + if expected.device.IOdevices == 'REAL VALUE': + assert len(IOdevices) == len(browser.real.device.IOdevices) + for i in range(len(IOdevices)): + assert IOdevices[i]['kind'] == browser.real.device.IOdevices[i]['kind'] + elif expected.device.IOdevices == 'EMPTY': + if IOdevices == 'ERROR': + assert IOdevices == 'ERROR' + else: + assert IOdevices == [] + assert len(IOdevices) == 0 + else: + assert len(IOdevices) in expected.device.IOdevices diff --git a/tests/integration_tests/testing/tests_definition/test_04_canvas.py b/tests/integration_tests/testing/tests_definition/test_04_canvas.py new file mode 100644 index 0000000..e671c65 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_04_canvas.py @@ -0,0 +1,104 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2020 Martin Bednar +# Copyright (C) 2021 Matus Svancar +# +# 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 . +# + +from values_getters import is_canvas_spoofed +from values_getters import get_dataURL_canvas +from values_getters import get_imageData_canvas +from values_getters import get_blob_canvas +from values_getters import get_point_in_path +from values_getters import get_point_in_stroke + + +## Test canvas - if canvas is spoofed: Reading from canvas returns white image. +## +## This test fails in Google Chrome on JShelter level 3 - expected failure because of known bug: +## selenium.common.exceptions.JavascriptException: Message: javascript error: +## Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'. +def test_canvas(browser, expected): + is_spoofed = is_canvas_spoofed(browser.driver) + if is_spoofed == "ERROR": + print("\nCan not read Canvas data.") + assert False + else: + if expected.protect_canvas: + assert is_spoofed + else: + assert not is_spoofed + +def test_getImageData(browser, expected): + image = get_imageData_canvas(browser.driver,"canvasx") + if image == "ERROR": + print("\n getImageData error.") + assert False + else: + if expected.canvas_imageData == 'SPOOF VALUE': + assert image != browser.real.canvas_imageData + else: + assert image == browser.real.canvas_imageData + + +def test_to_data_URL(browser, expected): + image = get_dataURL_canvas(browser.driver,"canvasx") + if image == "ERROR": + print("\n toDataURL error.") + assert False + else: + if expected.canvas_dataURL == 'SPOOF VALUE': + assert image != browser.real.canvas_dataURL + else: + assert image == browser.real.canvas_dataURL + + +def test_to_blob(browser, expected): + image = get_blob_canvas(browser.driver,"canvasx") + if image == "ERROR": + print("\n toBlob error.") + assert False + else: + if expected.canvas_blob == 'SPOOF VALUE': + assert image != browser.real.canvas_blob + else: + assert image == browser.real.canvas_blob + +def test_is_point_in_path(browser, expected): + point = get_point_in_path(browser.driver,"canvas4", (expected.canvas_point_path == 'FALSE VALUE')) + if point == "ERROR": + print("\n isPointInPath error.") + assert False + else: + if expected.canvas_point_path in {'SPOOF VALUE','FALSE VALUE'}: + assert point == False + else: + assert point == True + +def test_is_point_in_stroke(browser, expected): + point = get_point_in_stroke(browser.driver,"canvas5", (expected.canvas_point_stroke == 'FALSE VALUE')) + if point == "ERROR": + print("\n isPointInStroke error.") + assert False + else: + if expected.canvas_point_stroke in {'SPOOF VALUE','FALSE VALUE'} : + assert point == False + else: + assert point == True diff --git a/tests/integration_tests/testing/tests_definition/test_05_domain_level_setting.py b/tests/integration_tests/testing/tests_definition/test_05_domain_level_setting.py new file mode 100644 index 0000000..074ca57 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_05_domain_level_setting.py @@ -0,0 +1,79 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest +from selenium.webdriver.common.by import By +from selenium.webdriver.support.select import Select +import random + + +domains = ["messenger.com", "email.seznam.cz", "facebook.com", "www.fit.vutbr.cz"] +levels = ['0', '2', '3', 'Experiment'] + + +def set_domain_level(browser, domain, level): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) + browser.driver.find_elements(By.ID, 'domain-text')[0].send_keys(domain) + select = Select(browser.driver.find_elements(By.ID, 'domain-level')[0]) + select.select_by_value(level) + browser.driver.find_elements(By.ID, 'add_domain')[0].click() + + +def unset_domain_level(browser, domain): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) + browser.driver.find_elements(By.ID, 'delete-dl-' + domain)[0].click() + +def change_domain_level(browser, domain, level): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) + select = Select(browser.driver.find_elements(By.ID, 'dl-change-' + domain)[0]) + select.select_by_value(level) + browser.driver.find_elements(By.ID, 'overwrite-dl-' + domain)[0].click() + + +def get_domain_level(browser, domain): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) + select = Select(browser.driver.find_elements(By.ID, 'dl-change-' + domain)[0]) + selected_option = select.first_selected_option + return selected_option.get_attribute("value") + + + +## Test setting a level for the selected domains. +def test_setting_domain_level(browser): + for i in range(len(domains)): + domain = domains[i] + level = random.choice(levels) + set_domain_level(browser, domain, level) + assert get_domain_level(browser, domain) == level + + +## Test changing a level for the selected domains. +def test_change_domain_level(browser): + for i in range(len(domains)): + domain = domains[i] + level = random.choice(levels) + change_domain_level(browser, domain, level) + assert get_domain_level(browser, domain) == level + + # Tear down. + unset_domain_level(browser, domain) diff --git a/tests/integration_tests/testing/tests_definition/test_06_gps.py b/tests/integration_tests/testing/tests_definition/test_06_gps.py new file mode 100644 index 0000000..91243fb --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_06_gps.py @@ -0,0 +1,217 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest +from time import time + +from values_getters import get_position +from math_operations import is_in_accuracy, calc_distance + +## Setup method - it is run before gps tests execution starts. +# +# This setup method initialize variable position that contains current data about position and +# this variable is provided to gps tests and values in position variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def position(browser): + position = { + 'accuracy' : "null", + 'altitude' : "null", + 'altitudeaccurac' : "null", + 'heading' : "null", + 'latitude' : "null", + 'longitude' : "null", + 'speed' : "null", + 'timestamp' : "null" + } + try: + position = get_position(browser.driver) + except: + print("\nCan not read GPS data.") + return position + + +## Test accuracy of the latitude and longitude properties in meters. +def test_accuracy(browser, position, expected): + if expected.geolocation.accuracy['value'] == 'REAL VALUE': + if position['accuracy'] == "null": + # If current value is null, real value has to be null too. + assert position['accuracy'] == browser.real.geolocation.accuracy + else: + if expected.geolocation.accuracy['accuracy'] == 'EXACTLY': + # x is real position (position returned without JShelter) + # y should be real position too (position returned with JShelter level 0) + # + # It is clear that x and y will not be exact same values. This is due to the netural GPS inaccuracy. + # A small difference is tolerated. + # x.accuracy and y.accuracy will be probably different. + # But distance between x and y should be less than (x.accuracy + y.accuracy). + assert calc_distance(float(browser.real.geolocation.latitude), + float(browser.real.geolocation.longitude), + float(position['latitude']), + float(position['longitude'])) < (float(browser.real.geolocation.accuracy) + float(position['accuracy'])) + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['accuracy'], expected.geolocation.accuracy['accuracy']) + else: + # Should be spoofed value. + assert position['accuracy'] == expected.geolocation.accuracy['value'] + + +## Test position's altitude in meters, relative to sea level. +def test_altitude(browser, position, expected): + if expected.geolocation.altitude['value'] == 'REAL VALUE': + if position['altitude'] == "null": + # If current value is null, real value has to be null too. + assert position['altitude'] == browser.real.geolocation.altitude + else: + if expected.geolocation.altitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 10 meters is tolerated. + assert abs(float(position['altitude']) - float(browser.real.geolocation.altitude)) < 10 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['altitude'], expected.geolocation.altitude['accuracy']) + else: + # Should be spoofed value. + assert position['altitude'] == expected.geolocation.altitude['value'] + + +## Test accuracy of the altitude property in meters. +def test_altitudeaccurac(browser, position, expected): + if expected.geolocation.altitudeAccurac['value'] == 'REAL VALUE': + if position['altitudeaccurac'] == "null": + # If current value is null, real value has to be null too. + assert position['altitudeaccurac'] == browser.real.geolocation.altitudeAccurac + else: + if expected.geolocation.altitudeAccurac['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 10 meters is tolerated. + assert abs(float(position['altitudeaccurac']) - float(browser.real.geolocation.altitudeAccurac)) < 10 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['altitudeaccurac'], + expected.geolocation.altitudeAccurac['accuracy']) + else: + # Should be spoofed value. + assert position['altitudeaccurac'] == expected.geolocation.altitudeAccurac['value'] + + +## Test heading. +# +# Heading is the direction in which the device is traveling. This value, specified in degrees, +# indicates how far off from heading true north the device is. 0 degrees represents true north, +# and the direction is determined clockwise (east is 90 degrees and west is 270 degrees). +# If speed is 0, heading is NaN. If the device is unable to provide heading information, this value is null +def test_heading(browser, position, expected): + if expected.geolocation.heading['value'] == 'REAL VALUE': + if position['heading'] == "null": + # If current value is null, real value has to be null too. + assert position['heading'] == browser.real.geolocation.heading + else: + if expected.geolocation.heading['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 30 degrees is tolerated. + assert abs(float(position['heading']) - float(browser.real.geolocation.heading)) < 30 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['heading'], expected.geolocation.heading['accuracy']) + else: + # Should be spoofed value. + assert position['heading'] == expected.geolocation.heading['value'] + + +## Test position's latitude in decimal degrees. +def test_latitude(browser, position, expected): + if expected.geolocation.latitude['value'] == 'REAL VALUE': + if position['latitude'] == "null": + # If current value is null, real value has to be null too. + assert position['latitude'] == browser.real.geolocation.latitude + else: + if expected.geolocation.latitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 1 degrees is tolerated. + assert abs(float(position['latitude']) - float(browser.real.geolocation.latitude)) < 1 + else: + real_latitude = float(browser.real.geolocation.latitude) + spoofed_latitude = float(position['latitude']) + max_allowed_deviation = expected.geolocation.latitude['accuracy'] + assert abs(real_latitude - spoofed_latitude) < max_allowed_deviation + else: + # Should be spoofed value. + assert position['latitude'] == expected.geolocation.latitude['value'] + + +## Test position's longitude in decimal degrees. +def test_longitude(browser, position, expected): + if expected.geolocation.longitude['value'] == 'REAL VALUE': + if position['longitude'] == "null": + # If current value is null, real value has to be null too. + assert position['longitude'] == browser.real.geolocation.longitude + else: + if expected.geolocation.longitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 1 degrees is tolerated. + assert abs(float(position['longitude']) - float(browser.real.geolocation.longitude)) < 1 + else: + real_longitude = float(browser.real.geolocation.longitude) + spoofed_longitude = float(position['longitude']) + max_allowed_deviation = expected.geolocation.longitude['accuracy'] + assert abs(real_longitude - spoofed_longitude) < max_allowed_deviation + else: + # Should be spoofed value. + assert position['longitude'] == expected.geolocation.longitude['value'] + + +## Test speed (velocity) of the device in meters per second. This value can be null. +def test_speed(browser, position, expected): + if expected.geolocation.speed['value'] == 'REAL VALUE': + if position['speed'] == "null": + # If current value is null, real value has to be null too. + assert position['speed'] == browser.real.geolocation.speed + else: + if expected.geolocation.speed['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 5 meters per second is tolerated. + assert abs(float(position['speed']) - float(browser.real.geolocation.speed)) < 5 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['speed'], expected.geolocation.speed['accuracy']) + else: + # Should be spoofed value. + assert position['speed'] == expected.geolocation.speed['value'] + + +## Test timestamp. +def test_timestamp(position, expected): + if expected.geolocation.timestamp['value'] == 'REAL VALUE': + if expected.geolocation.timestamp['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal because executing command takes some time. + # A deviation of less than 2 seconds is tolerated. + assert abs(time() - int(position['timestamp'])/1000) < 2 + else: + timestamp_accuracy = expected.geolocation.timestamp['accuracy']*1000 + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['timestamp'], timestamp_accuracy) + else: + # Should be spoofed value. + assert position['timestamp'] == expected.geolocation.timestamp['value'] diff --git a/tests/integration_tests/testing/tests_definition/test_07_navigator.py b/tests/integration_tests/testing/tests_definition/test_07_navigator.py new file mode 100644 index 0000000..ad15c3b --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_07_navigator.py @@ -0,0 +1,144 @@ +# +# JavaScript Restrictor is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Matus Svancar +# Copyright (C) 2022 Martin Bednar +# +# 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 . +# + +import pytest + +from values_getters import get_navigator + + +## Setup method - it is run before navigator tests execution starts. +# +# This setup method initialize variable navigator that contains current data about navigator and +# this variable is provided to navigator tests and values in device variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def navigator(browser): + return get_navigator(browser.driver) + + +## Test user agent. +def test_user_agent(browser, navigator, expected): + if expected.navigator.userAgent[browser.type] == 'REAL VALUE': + assert navigator['userAgent'] == browser.real.navigator.userAgent + else: + assert navigator['userAgent'] == expected.navigator.userAgent[browser.type] + + +## Test app version. +def test_app_version(browser, navigator, expected): + if expected.navigator.appVersion == 'REAL VALUE': + assert navigator['appVersion'] == browser.real.navigator.appVersion + else: + assert navigator['appVersion'] == expected.navigator.appVersion + + +## Test platform. +def test_platform(browser, navigator, expected): + if expected.navigator.platform == 'REAL VALUE': + assert navigator['platform'] == browser.real.navigator.platform + else: + assert navigator['platform'] == expected.navigator.platform + + +## Test vendor. +def test_vendor(browser, navigator, expected): + if expected.navigator.vendor[browser.type] == 'REAL VALUE': + assert navigator['vendor'] == browser.real.navigator.vendor + else: + assert navigator['vendor'] == expected.navigator.vendor[browser.type] + + +## Test language. +def test_language(browser, navigator, expected): + if expected.navigator.language == 'REAL VALUE': + assert navigator['language'] == browser.real.navigator.language + else: + assert navigator['language'] == expected.navigator.language + + +## Test languages. +def test_languages(browser, navigator, expected): + if expected.navigator.languages == 'REAL VALUE': + assert navigator['languages'] == browser.real.navigator.languages + else: + assert navigator['languages'] == expected.navigator.languages + + +## Test cookie enabled. +def test_cookie_enabled(browser, navigator, expected): + if expected.navigator.cookieEnabled == 'REAL VALUE': + assert navigator['cookieEnabled'] == browser.real.navigator.cookieEnabled + else: + assert navigator['cookieEnabled'] == expected.navigator.cookieEnabled + + +## Test doNotTrack flag. +def test_do_not_track(browser, navigator, expected): + if expected.navigator.doNotTrack == 'REAL VALUE': + assert navigator['doNotTrack'] == browser.real.navigator.doNotTrack + else: + assert navigator['doNotTrack'] == expected.navigator.doNotTrack + + +## Test oscpu +def test_oscpu(browser, navigator, expected): + if expected.navigator.oscpu == 'REAL VALUE': + assert navigator['oscpu'] == browser.real.navigator.oscpu + else: + assert navigator['oscpu'] == expected.navigator.oscpu + +## Test plugins count +def test_plugins_count(browser, navigator, expected): + if expected.navigator.plugins['count'][browser.type] == 'IGNORE': + return + elif expected.navigator.plugins['count'][browser.type] == 'REAL VALUE': + assert len(navigator['plugins']) == len(browser.real.navigator.plugins) + elif expected.navigator.plugins['count'][browser.type] == 'PLUS_2': + assert len(navigator['plugins']) == len(browser.real.navigator.plugins) + 2 + else: + assert len(navigator['plugins']) == expected.navigator.plugins['count'][browser.type] + +## Test plugins array value +def test_plugins(browser, navigator, expected): + if expected.navigator.plugins['count'][browser.type] == 'IGNORE': + return + elif expected.navigator.plugins['value'][browser.type] == 'REAL VALUE': + assert navigator['plugins'] == browser.real.navigator.plugins + elif expected.navigator.plugins['value'][browser.type] == 'EMPTY': + assert not navigator['plugins'] + else: + assert navigator['plugins'] != browser.real.navigator.plugins + +## Test mimeTypes +def test_mime_types(browser, navigator, expected): + if expected.navigator.mimeTypes == 'IGNORE': + return + elif expected.navigator.mimeTypes == 'EMPTY': + assert navigator['mimeTypes'] == [] + elif expected.navigator.mimeTypes == 'SPOOF VALUE': + if browser.real.navigator.mimeTypes == []: + assert navigator['mimeTypes'] == [] + else: + assert navigator['mimeTypes'] != browser.real.navigator.mimeTypes + else: + assert navigator['mimeTypes'] == browser.real.navigator.mimeTypes diff --git a/tests/integration_tests/testing/tests_definition/test_08_performance.py b/tests/integration_tests/testing/tests_definition/test_08_performance.py new file mode 100644 index 0000000..1020264 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_08_performance.py @@ -0,0 +1,48 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2020 Martin Bednar +# +# 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 . +# + +import time +import random + +from math_operations import is_in_accuracy + + +## Test performance. +def test_performance(browser, expected): + is_performance_rounded = True + # Make 3 measurement. + for _ in range(3): + # Wait a while to value of performance will be changed. + time.sleep(random.randint(1, 3)) + performance = browser.driver.execute_script("return window.performance.now()") + if expected.performance['accuracy'] == 'EXACTLY': + if int(performance / 10) * 10 != performance: + # Performance was not rounded. At least one of three measurement has to say value was not rounded. + is_performance_rounded = False + else: + assert is_in_accuracy(performance, expected.performance['accuracy']) + + if expected.performance['accuracy'] == 'EXACTLY': + # At least one of three measurement has to say value was not rounded. + # is_performance_rounded should be false if EXACTLY value is required. + assert not is_performance_rounded diff --git a/tests/integration_tests/testing/tests_definition/test_09_referrer.py b/tests/integration_tests/testing/tests_definition/test_09_referrer.py new file mode 100644 index 0000000..1eb98b7 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_09_referrer.py @@ -0,0 +1,43 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2020 Martin Bednar +# +# 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 . +# + +import pytest + +from values_getters import get_referrer + + +## Setup method - it is run before referrer test execution starts. +# +# This setup method initialize variable referrer that contains current data about referrer and +# this variable is provided to referrer test and value in referrer variable is compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def referrer(browser): + return get_referrer(browser.driver) + + +## Test referrer - where the page was navigated from. +def test_referrer(browser, referrer, expected): + if expected.referrer == 'REAL VALUE': + assert referrer == browser.real.referrer + else: + assert referrer == expected.referrer diff --git a/tests/integration_tests/testing/tests_definition/test_10_time.py b/tests/integration_tests/testing/tests_definition/test_10_time.py new file mode 100644 index 0000000..364bc1c --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_10_time.py @@ -0,0 +1,74 @@ +# +# JavaScript Restrictor is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2022 Martin Bednar +# +# 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 . +# + +import pytest +from datetime import datetime +import time +import random + +from math_operations import is_in_accuracy +from configuration import get_config + + +## Setup method - it is run before time tests execution starts. +# +# This setup method open testing page - it is necessary in Mozilla Firefox. +# In Mozilla Firefox: Time is spoofed only when page is opened. +@pytest.fixture(scope='module', autouse=True) +def load_test_page(browser): + browser.driver.get(get_config("testing_page")) + + +## Test hours. +# Hours should be real value. Maximal deviation should be 1 (change hour during command execution or another timezone). +def test_hours_minutes_seconds(browser): + js_time = browser.driver.execute_script("let d = new Date();" + "return d.getHours()*60*60 + d.getMinutes()*60 + d.getSeconds()") + p_now = datetime.now() + p_time = p_now.hour * 60 * 60 + p_now.minute * 60 + p_now.second + # Values do not have to be strictly equal. + # A deviation of less than 1 is tolerated. + assert abs(js_time - p_time) <= 1 + + +## Test time accuracy. +def test_accuracy(browser, expected): + #Suppose time is rounded. + is_time_rounded = True + # Make 3 measurement. + for _ in range(3): + # Wait a while to value of time will be changed. + time.sleep(random.randint(1, 3)) + miliseconds = browser.driver.execute_script("let d = new Date();" + "return d.getMilliseconds()") + if expected.time['accuracy'] == 'EXACTLY': + if int(miliseconds / 10) * 10 != miliseconds: + # miliseconds was not rounded. At least one of three measurement has to say value was not rounded. + is_time_rounded = False + else: + assert is_in_accuracy(miliseconds, expected.time['accuracy']) + + if expected.time['accuracy'] == 'EXACTLY': + # At least one of three measurement has to say value was not rounded. + # is_time_rounded should be false if EXACTLY value is required. + assert not is_time_rounded diff --git a/tests/integration_tests/testing/tests_definition/test_11_toString.py b/tests/integration_tests/testing/tests_definition/test_11_toString.py new file mode 100644 index 0000000..f75535c --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_11_toString.py @@ -0,0 +1,41 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest + +from values_getters import get_methods_toString + + +## Setup method - it is run before toString tests execution starts. +# +# This setup method initialize variable methods_toString that contains methods.toString() and +# this variable is provided to methods_toString test and the methods.toString() in the variable are compared with real values. +@pytest.fixture(scope='module', autouse=True) +def methods_toString(browser): + return get_methods_toString(browser.driver) + + +## Test methods.toString(). They should be always unchanged by JShelter. +def test_methods_toString(browser, methods_toString): + for method in methods_toString: + assert methods_toString[method] == browser.real.methods_toString[method] diff --git a/tests/integration_tests/testing/tests_definition/test_12_webaudio.py b/tests/integration_tests/testing/tests_definition/test_12_webaudio.py new file mode 100644 index 0000000..5d322ef --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_12_webaudio.py @@ -0,0 +1,99 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Matus Svancar +# +# 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 . +# +import pytest +from values_getters import get_audio + +## AudioContext and AnalyserNode tests +## +## All of these tests fail in Google Chrome on JShelter level 3 - expected failure because of known bug: +## selenium.common.exceptions.JavascriptException: Message: javascript error: +## Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'. + +@pytest.fixture(scope='module', autouse=True) +def audio_data(browser): + audio = None + try: + audio = get_audio(browser.driver) + except: + print("\nCan not read audio data.") + return audio + +## Test AudioContext.getChannelData +def test_channel_data(browser, audio_data, expected): + if audio_data: + if expected.audio.get_channel == 'SPOOF VALUE': + assert audio_data['get_channel'] != browser.real.audio.get_channel + else: + assert audio_data['get_channel'] == browser.real.audio.get_channel + else: + assert False + +## Test AudioContext.copyFromChannel +def test_copy_channel(browser, audio_data, expected): + if audio_data: + if expected.audio.copy_channel == 'SPOOF VALUE': + assert audio_data['copy_channel'] != browser.real.audio.copy_channel + else: + assert audio_data['copy_channel'] == browser.real.audio.copy_channel + else: + assert False + +## Test AnalyserNode.getByteTimeDomainData +def test_byte_time_domain(browser, audio_data, expected): + if audio_data: + if expected.audio.byte_time_domain == 'SPOOF VALUE': + assert audio_data['byte_time_domain'] != browser.real.audio.byte_time_domain + else: + assert audio_data['byte_time_domain'] == browser.real.audio.byte_time_domain + else: + assert False + +## Test AnalyserNode.getFloatTimeDomainData +def test_float_time_domain(browser, audio_data, expected): + if audio_data: + if expected.audio.float_time_domain == 'SPOOF VALUE': + assert audio_data['float_time_domain'] != browser.real.audio.float_time_domain + else: + assert audio_data['float_time_domain'] == browser.real.audio.float_time_domain + else: + assert False + +## Test AnalyserNode.getByteFrequencyData +def test_byte_frequency(browser, audio_data, expected): + if audio_data: + if expected.audio.byte_frequency == 'SPOOF VALUE': + assert audio_data['byte_frequency'] != browser.real.audio.byte_frequency + else: + assert audio_data['byte_frequency'] == browser.real.audio.byte_frequency + else: + assert False + +## Test AnalyserNode.getFloatFrequencyData +def test_float_frequency(browser, audio_data, expected): + if audio_data: + if expected.audio.float_frequency == 'SPOOF VALUE': + assert audio_data['float_frequency'] != browser.real.audio.float_frequency + else: + assert audio_data['float_frequency'] == browser.real.audio.float_frequency + else: + assert False diff --git a/tests/integration_tests/testing/tests_definition/test_13_webgl.py b/tests/integration_tests/testing/tests_definition/test_13_webgl.py new file mode 100644 index 0000000..74d5c7a --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_13_webgl.py @@ -0,0 +1,157 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Matus Svancar +# +# 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 . +# +import pytest +from values_getters import get_webgl_params +from values_getters import get_webgl_pixels +from values_getters import get_dataURL_canvas +from values_getters import get_webgl_precisions + +@pytest.fixture(scope='module', autouse=True) +def webgl_params(browser): + return get_webgl_params(browser.driver, "webglCanvas") + +# Test WebGLRenderingContext.getParameter for unmaskedVendor +def test_unmasked_vendor(browser, webgl_params, expected): + if expected.webgl_parameters == 'REAL VALUE': + assert webgl_params['unmaskedVendor'] == browser.real.webgl_parameters['unmaskedVendor'] + else: + if webgl_params['unmaskedVendor'] == browser.real.webgl_parameters['unmaskedVendor']: + assert webgl_params['unmaskedVendor'] == None + else: + assert True + +# Test WebGLRenderingContext.getParameter for unmaskedRenderer +def test_unmasked_renderer(browser, webgl_params, expected): + if expected.webgl_parameters == 'REAL VALUE': + assert webgl_params['unmaskedRenderer'] == browser.real.webgl_parameters['unmaskedRenderer'] + else: + assert webgl_params['unmaskedRenderer'] != browser.real.webgl_parameters['unmaskedRenderer'] + +# Test WebGLRenderingContext.getParameter +def test_other_parameters(browser, webgl_params, expected): + if expected.webgl_parameters == 'SPOOF VALUE': + if browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS'] != None: + assert webgl_params['MAX_VERTEX_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS'] != None: + assert webgl_params['MAX_VERTEX_UNIFORM_BLOCKS'] in {browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS'],browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS']-1} + if browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS'] != None: + assert webgl_params['MAX_VERTEX_OUTPUT_COMPONENTS'] in {browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS'],browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_VARYING_COMPONENTS'] != None: + assert webgl_params['MAX_VARYING_COMPONENTS'] in {browser.real.webgl_parameters['MAX_VARYING_COMPONENTS'],browser.real.webgl_parameters['MAX_VARYING_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] != None: + assert webgl_params['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] in {browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'],browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS'] != None: + assert webgl_params['MAX_FRAGMENT_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS'] != None: + assert webgl_params['MAX_FRAGMENT_UNIFORM_BLOCKS'] in {browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS'],browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS']-1} + if browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS'] != None: + assert webgl_params['MAX_FRAGMENT_INPUT_COMPONENTS'] in {browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS'],browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS'] != None: + assert webgl_params['MAX_UNIFORM_BUFFER_BINDINGS'] in {browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS'],browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS']-1} + if browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS'] != None: + assert webgl_params['MAX_COMBINED_UNIFORM_BLOCKS'] in {browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS'],browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS']-1} + if browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] != None: + assert webgl_params['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] != None: + assert webgl_params['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS']-1} + if browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS'] != None: + assert webgl_params['MAX_VERTEX_ATTRIBS'] in {browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS'],browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS']-1} + if browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS'] != None: + assert webgl_params['MAX_VERTEX_UNIFORM_VECTORS'] in {browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS'],browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS']-1} + if browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] != None: + assert webgl_params['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] in {browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS'],browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS']-1} + if browser.real.webgl_parameters['MAX_TEXTURE_SIZE'] != None: + assert webgl_params['MAX_TEXTURE_SIZE'] in {browser.real.webgl_parameters['MAX_TEXTURE_SIZE'],browser.real.webgl_parameters['MAX_TEXTURE_SIZE']-1} + if browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE'] != None: + assert webgl_params['MAX_CUBE_MAP_TEXTURE_SIZE'] in {browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE'],browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE']-1} + if browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE'] != None: + assert webgl_params['MAX_3D_TEXTURE_SIZE'] in {browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE'],browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE']-1} + if browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'] != None: + assert webgl_params['MAX_ARRAY_TEXTURE_LAYERS'] in {browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'],browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS']-1} + elif expected.webgl_parameters == 'ZERO VALUE': + assert ((webgl_params['MAX_VERTEX_UNIFORM_COMPONENTS'] == 0) and + (webgl_params['MAX_VERTEX_UNIFORM_BLOCKS'] == 0) and + (webgl_params['MAX_VERTEX_OUTPUT_COMPONENTS'] == 0) and + (webgl_params['MAX_VARYING_COMPONENTS'] == 0) and + (webgl_params['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] == 0) and + (webgl_params['MAX_FRAGMENT_UNIFORM_COMPONENTS'] == 0) and + (webgl_params['MAX_FRAGMENT_UNIFORM_BLOCKS'] == 0) and + (webgl_params['MAX_FRAGMENT_INPUT_COMPONENTS'] == 0) and + (webgl_params['MAX_UNIFORM_BUFFER_BINDINGS'] == 0) and + (webgl_params['MAX_COMBINED_UNIFORM_BLOCKS'] == 0) and + (webgl_params['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] == 0) and + (webgl_params['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] == 0) and + (webgl_params['MAX_VERTEX_ATTRIBS'] == browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS']) and + (webgl_params['MAX_VERTEX_UNIFORM_VECTORS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS']) and + (webgl_params['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] == browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS']) and + (webgl_params['MAX_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_TEXTURE_SIZE']) and + (webgl_params['MAX_CUBE_MAP_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE']) and + (webgl_params['MAX_3D_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE']) and + (webgl_params['MAX_ARRAY_TEXTURE_LAYERS'] == browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'])) + else: + assert ((webgl_params['MAX_VERTEX_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS']) and + (webgl_params['MAX_VERTEX_UNIFORM_BLOCKS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS']) and + (webgl_params['MAX_VERTEX_OUTPUT_COMPONENTS'] == browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS']) and + (webgl_params['MAX_VARYING_COMPONENTS'] == browser.real.webgl_parameters['MAX_VARYING_COMPONENTS']) and + (webgl_params['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] == browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS']) and + (webgl_params['MAX_FRAGMENT_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS']) and + (webgl_params['MAX_FRAGMENT_UNIFORM_BLOCKS'] == browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS']) and + (webgl_params['MAX_FRAGMENT_INPUT_COMPONENTS'] == browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS']) and + (webgl_params['MAX_UNIFORM_BUFFER_BINDINGS'] == browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS']) and + (webgl_params['MAX_COMBINED_UNIFORM_BLOCKS'] == browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS']) and + (webgl_params['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS']) and + (webgl_params['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS']) and + (webgl_params['MAX_VERTEX_ATTRIBS'] == browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS']) and + (webgl_params['MAX_VERTEX_UNIFORM_VECTORS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS']) and + (webgl_params['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] == browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS']) and + (webgl_params['MAX_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_TEXTURE_SIZE']) and + (webgl_params['MAX_CUBE_MAP_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE']) and + (webgl_params['MAX_3D_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE']) and + (webgl_params['MAX_ARRAY_TEXTURE_LAYERS'] == browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'])) + +# Test WebGLRenderingContext.getShaderPrecisionFormat +def test_webgl_precisions(browser, expected): + precisions = get_webgl_precisions(browser.driver,"webglCanvas") + if expected.webgl_precisions == 'SPOOF VALUE': + assert precisions != browser.real.webgl_precisions + else: + assert precisions == browser.real.webgl_precisions + +# Test WebGLRenderingContext.readPixels +def test_webgl_read_pixels(browser, expected): + pixels = get_webgl_pixels(browser.driver,"webglCanvas") + if pixels == "ERROR": + print("\nWebGLRenderingContext.readPixels failed.") + assert False + if expected.webgl_pixels == 'SPOOF VALUE': + assert pixels != browser.real.webgl_pixels + else: + assert pixels == browser.real.webgl_pixels + +# Test HTMLCanvasElement.toDataURL on webgl canvas +def test_webgl_to_data_URL(browser, expected): + image = get_dataURL_canvas(browser.driver,"webglCanvas") + if expected.webgl_dataURL == 'SPOOF VALUE': + assert image != browser.real.webgl_dataURL + else: + assert image == browser.real.webgl_dataURL diff --git a/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py deleted file mode 100644 index 72502fd..0000000 --- a/tests/integration_tests/testing/tests_definition/test_ECMA_arrays.py +++ /dev/null @@ -1,48 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2022 Martin Bednar -# -# 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 . -# - -import pytest -from selenium.webdriver.common.by import By - -from configuration import get_config - -## Setup method - it is run before time tests execution starts. -# -# This setup method open testing page. -@pytest.fixture(scope='module', autouse=True) -def load_test_page(browser): - browser.driver.get(get_config("testing_page")) - - -## Test crypto.getRandomValues. -# Random values should be generated. No error in Javascript runtime should appear. -# \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. -# Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). -@pytest.mark.xfail -def test_crypto_getRandomValues(browser): - ul = browser.driver.find_element(By.ID,"getRandomValues") - if len(ul.text) > 0: - items = ul.find_elements(By.TAG_NAME,"li") - assert len(items) > 0 - else: - pytest.fail("No random value generated. Probable JavaScript error: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView.") diff --git a/tests/integration_tests/testing/tests_definition/test_NBS_setting.py b/tests/integration_tests/testing/tests_definition/test_NBS_setting.py deleted file mode 100644 index e26368b..0000000 --- a/tests/integration_tests/testing/tests_definition/test_NBS_setting.py +++ /dev/null @@ -1,57 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest -from selenium.webdriver.common.by import By -from time import sleep - - -def switch_NBS_setting(browser): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) - sleep(1) - browser.driver.find_elements(By.CLASS_NAME, 'slider')[1].click() - sleep(1) - - -def get_NBS_setting(browser): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) - sleep(2) - return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('#nbs_whitelist .switch_wrapper .switch .slider'),':before').getPropertyValue('content')")) - - -## Test turnning NBS off in popup. -## Sleep 0.5 second to changes take effect. -def test_switching_NBS(browser): - NBS_setting_values = ['"ON"', '"OFF"'] - - original_setting = get_NBS_setting(browser) - original_setting_index = NBS_setting_values.index(original_setting) - - # Range is saing how many times should NBS be switched. - for i in range(4): - switch_NBS_setting(browser) - assert get_NBS_setting(browser) == NBS_setting_values[(i + 1 + original_setting_index) % 2] - - # Return original value - if get_NBS_setting(browser) != original_setting: - switch_NBS_setting(browser) diff --git a/tests/integration_tests/testing/tests_definition/test_canvas.py b/tests/integration_tests/testing/tests_definition/test_canvas.py deleted file mode 100644 index e671c65..0000000 --- a/tests/integration_tests/testing/tests_definition/test_canvas.py +++ /dev/null @@ -1,104 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2020 Martin Bednar -# Copyright (C) 2021 Matus Svancar -# -# 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 . -# - -from values_getters import is_canvas_spoofed -from values_getters import get_dataURL_canvas -from values_getters import get_imageData_canvas -from values_getters import get_blob_canvas -from values_getters import get_point_in_path -from values_getters import get_point_in_stroke - - -## Test canvas - if canvas is spoofed: Reading from canvas returns white image. -## -## This test fails in Google Chrome on JShelter level 3 - expected failure because of known bug: -## selenium.common.exceptions.JavascriptException: Message: javascript error: -## Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'. -def test_canvas(browser, expected): - is_spoofed = is_canvas_spoofed(browser.driver) - if is_spoofed == "ERROR": - print("\nCan not read Canvas data.") - assert False - else: - if expected.protect_canvas: - assert is_spoofed - else: - assert not is_spoofed - -def test_getImageData(browser, expected): - image = get_imageData_canvas(browser.driver,"canvasx") - if image == "ERROR": - print("\n getImageData error.") - assert False - else: - if expected.canvas_imageData == 'SPOOF VALUE': - assert image != browser.real.canvas_imageData - else: - assert image == browser.real.canvas_imageData - - -def test_to_data_URL(browser, expected): - image = get_dataURL_canvas(browser.driver,"canvasx") - if image == "ERROR": - print("\n toDataURL error.") - assert False - else: - if expected.canvas_dataURL == 'SPOOF VALUE': - assert image != browser.real.canvas_dataURL - else: - assert image == browser.real.canvas_dataURL - - -def test_to_blob(browser, expected): - image = get_blob_canvas(browser.driver,"canvasx") - if image == "ERROR": - print("\n toBlob error.") - assert False - else: - if expected.canvas_blob == 'SPOOF VALUE': - assert image != browser.real.canvas_blob - else: - assert image == browser.real.canvas_blob - -def test_is_point_in_path(browser, expected): - point = get_point_in_path(browser.driver,"canvas4", (expected.canvas_point_path == 'FALSE VALUE')) - if point == "ERROR": - print("\n isPointInPath error.") - assert False - else: - if expected.canvas_point_path in {'SPOOF VALUE','FALSE VALUE'}: - assert point == False - else: - assert point == True - -def test_is_point_in_stroke(browser, expected): - point = get_point_in_stroke(browser.driver,"canvas5", (expected.canvas_point_stroke == 'FALSE VALUE')) - if point == "ERROR": - print("\n isPointInStroke error.") - assert False - else: - if expected.canvas_point_stroke in {'SPOOF VALUE','FALSE VALUE'} : - assert point == False - else: - assert point == True diff --git a/tests/integration_tests/testing/tests_definition/test_domain_level_setting.py b/tests/integration_tests/testing/tests_definition/test_domain_level_setting.py deleted file mode 100644 index 091cc57..0000000 --- a/tests/integration_tests/testing/tests_definition/test_domain_level_setting.py +++ /dev/null @@ -1,79 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest -from selenium.webdriver.common.by import By -from selenium.webdriver.support.select import Select -import random - - -domains = ["messenger.com", "email.seznam.cz", "facebook.com", "www.fit.vutbr.cz"] -levels = ['0', '2', '3', 'Experiment'] - - -def set_domain_level(browser, domain, level): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) - browser.driver.find_elements(By.ID, 'domain-text')[0].send_keys(domain) - select = Select(browser.driver.find_elements(By.ID, 'domain-level')[0]) - select.select_by_value(level) - browser.driver.find_elements(By.ID, 'add_domain')[0].click() - - -def unset_domain_level(browser, domain): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) - browser.driver.find_elements(By.ID, 'delete-dl-' + domain)[0].click() - -def change_domain_level(browser, domain, level): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) - select = Select(browser.driver.find_elements(By.ID, 'dl-change-' + domain)[0]) - select.select_by_value(level) - browser.driver.find_elements(By.ID, 'overwrite-dl-' + domain)[0].click() - - -def get_domain_level(browser, domain): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/options_domains.html")) - select = Select(browser.driver.find_elements(By.ID, 'dl-change-' + domain)[0]) - selected_option = select.first_selected_option - return selected_option.get_attribute("value") - - - -## Test setting a level for the selected domains. -def test_setting_domain_level(browser): - for i in range(len(domains)): - domain = domains[i] - level = random.choice(levels) - set_domain_level(browser, domain, level) - assert get_domain_level(browser, domain) == level - - -## Test changing a level for the selected domains. -def test_change_domain_level(browser): - for i in range(len(domains)): - domain = domains[i] - level = random.choice(levels) - change_domain_level(browser, domain, level) - assert get_domain_level(browser, domain) == level - - # Tear down. - unset_domain_level(browser, domain) diff --git a/tests/integration_tests/testing/tests_definition/test_gps.py b/tests/integration_tests/testing/tests_definition/test_gps.py deleted file mode 100644 index 91243fb..0000000 --- a/tests/integration_tests/testing/tests_definition/test_gps.py +++ /dev/null @@ -1,217 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest -from time import time - -from values_getters import get_position -from math_operations import is_in_accuracy, calc_distance - -## Setup method - it is run before gps tests execution starts. -# -# This setup method initialize variable position that contains current data about position and -# this variable is provided to gps tests and values in position variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def position(browser): - position = { - 'accuracy' : "null", - 'altitude' : "null", - 'altitudeaccurac' : "null", - 'heading' : "null", - 'latitude' : "null", - 'longitude' : "null", - 'speed' : "null", - 'timestamp' : "null" - } - try: - position = get_position(browser.driver) - except: - print("\nCan not read GPS data.") - return position - - -## Test accuracy of the latitude and longitude properties in meters. -def test_accuracy(browser, position, expected): - if expected.geolocation.accuracy['value'] == 'REAL VALUE': - if position['accuracy'] == "null": - # If current value is null, real value has to be null too. - assert position['accuracy'] == browser.real.geolocation.accuracy - else: - if expected.geolocation.accuracy['accuracy'] == 'EXACTLY': - # x is real position (position returned without JShelter) - # y should be real position too (position returned with JShelter level 0) - # - # It is clear that x and y will not be exact same values. This is due to the netural GPS inaccuracy. - # A small difference is tolerated. - # x.accuracy and y.accuracy will be probably different. - # But distance between x and y should be less than (x.accuracy + y.accuracy). - assert calc_distance(float(browser.real.geolocation.latitude), - float(browser.real.geolocation.longitude), - float(position['latitude']), - float(position['longitude'])) < (float(browser.real.geolocation.accuracy) + float(position['accuracy'])) - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['accuracy'], expected.geolocation.accuracy['accuracy']) - else: - # Should be spoofed value. - assert position['accuracy'] == expected.geolocation.accuracy['value'] - - -## Test position's altitude in meters, relative to sea level. -def test_altitude(browser, position, expected): - if expected.geolocation.altitude['value'] == 'REAL VALUE': - if position['altitude'] == "null": - # If current value is null, real value has to be null too. - assert position['altitude'] == browser.real.geolocation.altitude - else: - if expected.geolocation.altitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 10 meters is tolerated. - assert abs(float(position['altitude']) - float(browser.real.geolocation.altitude)) < 10 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['altitude'], expected.geolocation.altitude['accuracy']) - else: - # Should be spoofed value. - assert position['altitude'] == expected.geolocation.altitude['value'] - - -## Test accuracy of the altitude property in meters. -def test_altitudeaccurac(browser, position, expected): - if expected.geolocation.altitudeAccurac['value'] == 'REAL VALUE': - if position['altitudeaccurac'] == "null": - # If current value is null, real value has to be null too. - assert position['altitudeaccurac'] == browser.real.geolocation.altitudeAccurac - else: - if expected.geolocation.altitudeAccurac['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 10 meters is tolerated. - assert abs(float(position['altitudeaccurac']) - float(browser.real.geolocation.altitudeAccurac)) < 10 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['altitudeaccurac'], - expected.geolocation.altitudeAccurac['accuracy']) - else: - # Should be spoofed value. - assert position['altitudeaccurac'] == expected.geolocation.altitudeAccurac['value'] - - -## Test heading. -# -# Heading is the direction in which the device is traveling. This value, specified in degrees, -# indicates how far off from heading true north the device is. 0 degrees represents true north, -# and the direction is determined clockwise (east is 90 degrees and west is 270 degrees). -# If speed is 0, heading is NaN. If the device is unable to provide heading information, this value is null -def test_heading(browser, position, expected): - if expected.geolocation.heading['value'] == 'REAL VALUE': - if position['heading'] == "null": - # If current value is null, real value has to be null too. - assert position['heading'] == browser.real.geolocation.heading - else: - if expected.geolocation.heading['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 30 degrees is tolerated. - assert abs(float(position['heading']) - float(browser.real.geolocation.heading)) < 30 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['heading'], expected.geolocation.heading['accuracy']) - else: - # Should be spoofed value. - assert position['heading'] == expected.geolocation.heading['value'] - - -## Test position's latitude in decimal degrees. -def test_latitude(browser, position, expected): - if expected.geolocation.latitude['value'] == 'REAL VALUE': - if position['latitude'] == "null": - # If current value is null, real value has to be null too. - assert position['latitude'] == browser.real.geolocation.latitude - else: - if expected.geolocation.latitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 1 degrees is tolerated. - assert abs(float(position['latitude']) - float(browser.real.geolocation.latitude)) < 1 - else: - real_latitude = float(browser.real.geolocation.latitude) - spoofed_latitude = float(position['latitude']) - max_allowed_deviation = expected.geolocation.latitude['accuracy'] - assert abs(real_latitude - spoofed_latitude) < max_allowed_deviation - else: - # Should be spoofed value. - assert position['latitude'] == expected.geolocation.latitude['value'] - - -## Test position's longitude in decimal degrees. -def test_longitude(browser, position, expected): - if expected.geolocation.longitude['value'] == 'REAL VALUE': - if position['longitude'] == "null": - # If current value is null, real value has to be null too. - assert position['longitude'] == browser.real.geolocation.longitude - else: - if expected.geolocation.longitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 1 degrees is tolerated. - assert abs(float(position['longitude']) - float(browser.real.geolocation.longitude)) < 1 - else: - real_longitude = float(browser.real.geolocation.longitude) - spoofed_longitude = float(position['longitude']) - max_allowed_deviation = expected.geolocation.longitude['accuracy'] - assert abs(real_longitude - spoofed_longitude) < max_allowed_deviation - else: - # Should be spoofed value. - assert position['longitude'] == expected.geolocation.longitude['value'] - - -## Test speed (velocity) of the device in meters per second. This value can be null. -def test_speed(browser, position, expected): - if expected.geolocation.speed['value'] == 'REAL VALUE': - if position['speed'] == "null": - # If current value is null, real value has to be null too. - assert position['speed'] == browser.real.geolocation.speed - else: - if expected.geolocation.speed['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 5 meters per second is tolerated. - assert abs(float(position['speed']) - float(browser.real.geolocation.speed)) < 5 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['speed'], expected.geolocation.speed['accuracy']) - else: - # Should be spoofed value. - assert position['speed'] == expected.geolocation.speed['value'] - - -## Test timestamp. -def test_timestamp(position, expected): - if expected.geolocation.timestamp['value'] == 'REAL VALUE': - if expected.geolocation.timestamp['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal because executing command takes some time. - # A deviation of less than 2 seconds is tolerated. - assert abs(time() - int(position['timestamp'])/1000) < 2 - else: - timestamp_accuracy = expected.geolocation.timestamp['accuracy']*1000 - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['timestamp'], timestamp_accuracy) - else: - # Should be spoofed value. - assert position['timestamp'] == expected.geolocation.timestamp['value'] diff --git a/tests/integration_tests/testing/tests_definition/test_hw.py b/tests/integration_tests/testing/tests_definition/test_hw.py deleted file mode 100644 index a7bfb54..0000000 --- a/tests/integration_tests/testing/tests_definition/test_hw.py +++ /dev/null @@ -1,82 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest - -from values_getters import get_device, get_IOdevices - - -## Setup method - it is run before hw tests execution starts. -# -# This setup method initialize variable device that contains current data about device and -# this variable is provided to device tests and values in device variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def device(browser): - return get_device(browser.driver) - - -## Setup method - it is run before hw tests execution starts. -# -# This setup method initialize variable IOdevices that contains current data about IO devices and -# this variable is provided to device tests and values in IOdevices variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def IOdevices(browser): - return get_IOdevices(browser.driver) - - -## Test device memory. -def test_device_memory(browser, device, expected): - if expected.device.deviceMemory[browser.type] == 'SPOOF VALUE': - assert device['deviceMemory'] in expected.device.deviceMemory['valid_values'] - assert device['deviceMemory'] <= browser.real.device.deviceMemory - else: - assert device['deviceMemory'] == browser.real.device.deviceMemory - - -## Test hardware concurrency. -def test_hardware_concurrency(browser, device, expected): - if expected.device.hardwareConcurrency['value'] == 'REAL VALUE': - assert device['hardwareConcurrency'] == browser.real.device.hardwareConcurrency - elif expected.device.hardwareConcurrency['value'] == 'SPOOF VALUE': - expectedval = expected.device.hardwareConcurrency['valid_values'] - if expectedval == "UP TO REAL VALUE": - expectedval = range(browser.real.device.hardwareConcurrency + 1) - assert device['hardwareConcurrency'] in expectedval - else: - assert False # We should not get here - - -## Test IOdevices. -def test_IOdevices(browser, IOdevices, expected): - if expected.device.IOdevices == 'REAL VALUE': - assert len(IOdevices) == len(browser.real.device.IOdevices) - for i in range(len(IOdevices)): - assert IOdevices[i]['kind'] == browser.real.device.IOdevices[i]['kind'] - elif expected.device.IOdevices == 'EMPTY': - if IOdevices == 'ERROR': - assert IOdevices == 'ERROR' - else: - assert IOdevices == [] - assert len(IOdevices) == 0 - else: - assert len(IOdevices) in expected.device.IOdevices diff --git a/tests/integration_tests/testing/tests_definition/test_navigator.py b/tests/integration_tests/testing/tests_definition/test_navigator.py deleted file mode 100644 index ad15c3b..0000000 --- a/tests/integration_tests/testing/tests_definition/test_navigator.py +++ /dev/null @@ -1,144 +0,0 @@ -# -# JavaScript Restrictor is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Matus Svancar -# Copyright (C) 2022 Martin Bednar -# -# 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 . -# - -import pytest - -from values_getters import get_navigator - - -## Setup method - it is run before navigator tests execution starts. -# -# This setup method initialize variable navigator that contains current data about navigator and -# this variable is provided to navigator tests and values in device variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def navigator(browser): - return get_navigator(browser.driver) - - -## Test user agent. -def test_user_agent(browser, navigator, expected): - if expected.navigator.userAgent[browser.type] == 'REAL VALUE': - assert navigator['userAgent'] == browser.real.navigator.userAgent - else: - assert navigator['userAgent'] == expected.navigator.userAgent[browser.type] - - -## Test app version. -def test_app_version(browser, navigator, expected): - if expected.navigator.appVersion == 'REAL VALUE': - assert navigator['appVersion'] == browser.real.navigator.appVersion - else: - assert navigator['appVersion'] == expected.navigator.appVersion - - -## Test platform. -def test_platform(browser, navigator, expected): - if expected.navigator.platform == 'REAL VALUE': - assert navigator['platform'] == browser.real.navigator.platform - else: - assert navigator['platform'] == expected.navigator.platform - - -## Test vendor. -def test_vendor(browser, navigator, expected): - if expected.navigator.vendor[browser.type] == 'REAL VALUE': - assert navigator['vendor'] == browser.real.navigator.vendor - else: - assert navigator['vendor'] == expected.navigator.vendor[browser.type] - - -## Test language. -def test_language(browser, navigator, expected): - if expected.navigator.language == 'REAL VALUE': - assert navigator['language'] == browser.real.navigator.language - else: - assert navigator['language'] == expected.navigator.language - - -## Test languages. -def test_languages(browser, navigator, expected): - if expected.navigator.languages == 'REAL VALUE': - assert navigator['languages'] == browser.real.navigator.languages - else: - assert navigator['languages'] == expected.navigator.languages - - -## Test cookie enabled. -def test_cookie_enabled(browser, navigator, expected): - if expected.navigator.cookieEnabled == 'REAL VALUE': - assert navigator['cookieEnabled'] == browser.real.navigator.cookieEnabled - else: - assert navigator['cookieEnabled'] == expected.navigator.cookieEnabled - - -## Test doNotTrack flag. -def test_do_not_track(browser, navigator, expected): - if expected.navigator.doNotTrack == 'REAL VALUE': - assert navigator['doNotTrack'] == browser.real.navigator.doNotTrack - else: - assert navigator['doNotTrack'] == expected.navigator.doNotTrack - - -## Test oscpu -def test_oscpu(browser, navigator, expected): - if expected.navigator.oscpu == 'REAL VALUE': - assert navigator['oscpu'] == browser.real.navigator.oscpu - else: - assert navigator['oscpu'] == expected.navigator.oscpu - -## Test plugins count -def test_plugins_count(browser, navigator, expected): - if expected.navigator.plugins['count'][browser.type] == 'IGNORE': - return - elif expected.navigator.plugins['count'][browser.type] == 'REAL VALUE': - assert len(navigator['plugins']) == len(browser.real.navigator.plugins) - elif expected.navigator.plugins['count'][browser.type] == 'PLUS_2': - assert len(navigator['plugins']) == len(browser.real.navigator.plugins) + 2 - else: - assert len(navigator['plugins']) == expected.navigator.plugins['count'][browser.type] - -## Test plugins array value -def test_plugins(browser, navigator, expected): - if expected.navigator.plugins['count'][browser.type] == 'IGNORE': - return - elif expected.navigator.plugins['value'][browser.type] == 'REAL VALUE': - assert navigator['plugins'] == browser.real.navigator.plugins - elif expected.navigator.plugins['value'][browser.type] == 'EMPTY': - assert not navigator['plugins'] - else: - assert navigator['plugins'] != browser.real.navigator.plugins - -## Test mimeTypes -def test_mime_types(browser, navigator, expected): - if expected.navigator.mimeTypes == 'IGNORE': - return - elif expected.navigator.mimeTypes == 'EMPTY': - assert navigator['mimeTypes'] == [] - elif expected.navigator.mimeTypes == 'SPOOF VALUE': - if browser.real.navigator.mimeTypes == []: - assert navigator['mimeTypes'] == [] - else: - assert navigator['mimeTypes'] != browser.real.navigator.mimeTypes - else: - assert navigator['mimeTypes'] == browser.real.navigator.mimeTypes diff --git a/tests/integration_tests/testing/tests_definition/test_performance.py b/tests/integration_tests/testing/tests_definition/test_performance.py deleted file mode 100644 index 1020264..0000000 --- a/tests/integration_tests/testing/tests_definition/test_performance.py +++ /dev/null @@ -1,48 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2020 Martin Bednar -# -# 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 . -# - -import time -import random - -from math_operations import is_in_accuracy - - -## Test performance. -def test_performance(browser, expected): - is_performance_rounded = True - # Make 3 measurement. - for _ in range(3): - # Wait a while to value of performance will be changed. - time.sleep(random.randint(1, 3)) - performance = browser.driver.execute_script("return window.performance.now()") - if expected.performance['accuracy'] == 'EXACTLY': - if int(performance / 10) * 10 != performance: - # Performance was not rounded. At least one of three measurement has to say value was not rounded. - is_performance_rounded = False - else: - assert is_in_accuracy(performance, expected.performance['accuracy']) - - if expected.performance['accuracy'] == 'EXACTLY': - # At least one of three measurement has to say value was not rounded. - # is_performance_rounded should be false if EXACTLY value is required. - assert not is_performance_rounded diff --git a/tests/integration_tests/testing/tests_definition/test_referrer.py b/tests/integration_tests/testing/tests_definition/test_referrer.py deleted file mode 100644 index 1eb98b7..0000000 --- a/tests/integration_tests/testing/tests_definition/test_referrer.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2020 Martin Bednar -# -# 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 . -# - -import pytest - -from values_getters import get_referrer - - -## Setup method - it is run before referrer test execution starts. -# -# This setup method initialize variable referrer that contains current data about referrer and -# this variable is provided to referrer test and value in referrer variable is compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def referrer(browser): - return get_referrer(browser.driver) - - -## Test referrer - where the page was navigated from. -def test_referrer(browser, referrer, expected): - if expected.referrer == 'REAL VALUE': - assert referrer == browser.real.referrer - else: - assert referrer == expected.referrer diff --git a/tests/integration_tests/testing/tests_definition/test_time.py b/tests/integration_tests/testing/tests_definition/test_time.py deleted file mode 100644 index 364bc1c..0000000 --- a/tests/integration_tests/testing/tests_definition/test_time.py +++ /dev/null @@ -1,74 +0,0 @@ -# -# JavaScript Restrictor is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2022 Martin Bednar -# -# 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 . -# - -import pytest -from datetime import datetime -import time -import random - -from math_operations import is_in_accuracy -from configuration import get_config - - -## Setup method - it is run before time tests execution starts. -# -# This setup method open testing page - it is necessary in Mozilla Firefox. -# In Mozilla Firefox: Time is spoofed only when page is opened. -@pytest.fixture(scope='module', autouse=True) -def load_test_page(browser): - browser.driver.get(get_config("testing_page")) - - -## Test hours. -# Hours should be real value. Maximal deviation should be 1 (change hour during command execution or another timezone). -def test_hours_minutes_seconds(browser): - js_time = browser.driver.execute_script("let d = new Date();" - "return d.getHours()*60*60 + d.getMinutes()*60 + d.getSeconds()") - p_now = datetime.now() - p_time = p_now.hour * 60 * 60 + p_now.minute * 60 + p_now.second - # Values do not have to be strictly equal. - # A deviation of less than 1 is tolerated. - assert abs(js_time - p_time) <= 1 - - -## Test time accuracy. -def test_accuracy(browser, expected): - #Suppose time is rounded. - is_time_rounded = True - # Make 3 measurement. - for _ in range(3): - # Wait a while to value of time will be changed. - time.sleep(random.randint(1, 3)) - miliseconds = browser.driver.execute_script("let d = new Date();" - "return d.getMilliseconds()") - if expected.time['accuracy'] == 'EXACTLY': - if int(miliseconds / 10) * 10 != miliseconds: - # miliseconds was not rounded. At least one of three measurement has to say value was not rounded. - is_time_rounded = False - else: - assert is_in_accuracy(miliseconds, expected.time['accuracy']) - - if expected.time['accuracy'] == 'EXACTLY': - # At least one of three measurement has to say value was not rounded. - # is_time_rounded should be false if EXACTLY value is required. - assert not is_time_rounded diff --git a/tests/integration_tests/testing/tests_definition/test_toString.py b/tests/integration_tests/testing/tests_definition/test_toString.py deleted file mode 100644 index f75535c..0000000 --- a/tests/integration_tests/testing/tests_definition/test_toString.py +++ /dev/null @@ -1,41 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest - -from values_getters import get_methods_toString - - -## Setup method - it is run before toString tests execution starts. -# -# This setup method initialize variable methods_toString that contains methods.toString() and -# this variable is provided to methods_toString test and the methods.toString() in the variable are compared with real values. -@pytest.fixture(scope='module', autouse=True) -def methods_toString(browser): - return get_methods_toString(browser.driver) - - -## Test methods.toString(). They should be always unchanged by JShelter. -def test_methods_toString(browser, methods_toString): - for method in methods_toString: - assert methods_toString[method] == browser.real.methods_toString[method] diff --git a/tests/integration_tests/testing/tests_definition/test_webaudio.py b/tests/integration_tests/testing/tests_definition/test_webaudio.py deleted file mode 100644 index 5d322ef..0000000 --- a/tests/integration_tests/testing/tests_definition/test_webaudio.py +++ /dev/null @@ -1,99 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Matus Svancar -# -# 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 . -# -import pytest -from values_getters import get_audio - -## AudioContext and AnalyserNode tests -## -## All of these tests fail in Google Chrome on JShelter level 3 - expected failure because of known bug: -## selenium.common.exceptions.JavascriptException: Message: javascript error: -## Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'. - -@pytest.fixture(scope='module', autouse=True) -def audio_data(browser): - audio = None - try: - audio = get_audio(browser.driver) - except: - print("\nCan not read audio data.") - return audio - -## Test AudioContext.getChannelData -def test_channel_data(browser, audio_data, expected): - if audio_data: - if expected.audio.get_channel == 'SPOOF VALUE': - assert audio_data['get_channel'] != browser.real.audio.get_channel - else: - assert audio_data['get_channel'] == browser.real.audio.get_channel - else: - assert False - -## Test AudioContext.copyFromChannel -def test_copy_channel(browser, audio_data, expected): - if audio_data: - if expected.audio.copy_channel == 'SPOOF VALUE': - assert audio_data['copy_channel'] != browser.real.audio.copy_channel - else: - assert audio_data['copy_channel'] == browser.real.audio.copy_channel - else: - assert False - -## Test AnalyserNode.getByteTimeDomainData -def test_byte_time_domain(browser, audio_data, expected): - if audio_data: - if expected.audio.byte_time_domain == 'SPOOF VALUE': - assert audio_data['byte_time_domain'] != browser.real.audio.byte_time_domain - else: - assert audio_data['byte_time_domain'] == browser.real.audio.byte_time_domain - else: - assert False - -## Test AnalyserNode.getFloatTimeDomainData -def test_float_time_domain(browser, audio_data, expected): - if audio_data: - if expected.audio.float_time_domain == 'SPOOF VALUE': - assert audio_data['float_time_domain'] != browser.real.audio.float_time_domain - else: - assert audio_data['float_time_domain'] == browser.real.audio.float_time_domain - else: - assert False - -## Test AnalyserNode.getByteFrequencyData -def test_byte_frequency(browser, audio_data, expected): - if audio_data: - if expected.audio.byte_frequency == 'SPOOF VALUE': - assert audio_data['byte_frequency'] != browser.real.audio.byte_frequency - else: - assert audio_data['byte_frequency'] == browser.real.audio.byte_frequency - else: - assert False - -## Test AnalyserNode.getFloatFrequencyData -def test_float_frequency(browser, audio_data, expected): - if audio_data: - if expected.audio.float_frequency == 'SPOOF VALUE': - assert audio_data['float_frequency'] != browser.real.audio.float_frequency - else: - assert audio_data['float_frequency'] == browser.real.audio.float_frequency - else: - assert False diff --git a/tests/integration_tests/testing/tests_definition/test_webgl.py b/tests/integration_tests/testing/tests_definition/test_webgl.py deleted file mode 100644 index 74d5c7a..0000000 --- a/tests/integration_tests/testing/tests_definition/test_webgl.py +++ /dev/null @@ -1,157 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Matus Svancar -# -# 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 . -# -import pytest -from values_getters import get_webgl_params -from values_getters import get_webgl_pixels -from values_getters import get_dataURL_canvas -from values_getters import get_webgl_precisions - -@pytest.fixture(scope='module', autouse=True) -def webgl_params(browser): - return get_webgl_params(browser.driver, "webglCanvas") - -# Test WebGLRenderingContext.getParameter for unmaskedVendor -def test_unmasked_vendor(browser, webgl_params, expected): - if expected.webgl_parameters == 'REAL VALUE': - assert webgl_params['unmaskedVendor'] == browser.real.webgl_parameters['unmaskedVendor'] - else: - if webgl_params['unmaskedVendor'] == browser.real.webgl_parameters['unmaskedVendor']: - assert webgl_params['unmaskedVendor'] == None - else: - assert True - -# Test WebGLRenderingContext.getParameter for unmaskedRenderer -def test_unmasked_renderer(browser, webgl_params, expected): - if expected.webgl_parameters == 'REAL VALUE': - assert webgl_params['unmaskedRenderer'] == browser.real.webgl_parameters['unmaskedRenderer'] - else: - assert webgl_params['unmaskedRenderer'] != browser.real.webgl_parameters['unmaskedRenderer'] - -# Test WebGLRenderingContext.getParameter -def test_other_parameters(browser, webgl_params, expected): - if expected.webgl_parameters == 'SPOOF VALUE': - if browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS'] != None: - assert webgl_params['MAX_VERTEX_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS'] != None: - assert webgl_params['MAX_VERTEX_UNIFORM_BLOCKS'] in {browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS'],browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS']-1} - if browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS'] != None: - assert webgl_params['MAX_VERTEX_OUTPUT_COMPONENTS'] in {browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS'],browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_VARYING_COMPONENTS'] != None: - assert webgl_params['MAX_VARYING_COMPONENTS'] in {browser.real.webgl_parameters['MAX_VARYING_COMPONENTS'],browser.real.webgl_parameters['MAX_VARYING_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] != None: - assert webgl_params['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] in {browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'],browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS'] != None: - assert webgl_params['MAX_FRAGMENT_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS'] != None: - assert webgl_params['MAX_FRAGMENT_UNIFORM_BLOCKS'] in {browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS'],browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS']-1} - if browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS'] != None: - assert webgl_params['MAX_FRAGMENT_INPUT_COMPONENTS'] in {browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS'],browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS'] != None: - assert webgl_params['MAX_UNIFORM_BUFFER_BINDINGS'] in {browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS'],browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS']-1} - if browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS'] != None: - assert webgl_params['MAX_COMBINED_UNIFORM_BLOCKS'] in {browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS'],browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS']-1} - if browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] != None: - assert webgl_params['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] != None: - assert webgl_params['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] in {browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'],browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS']-1} - if browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS'] != None: - assert webgl_params['MAX_VERTEX_ATTRIBS'] in {browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS'],browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS']-1} - if browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS'] != None: - assert webgl_params['MAX_VERTEX_UNIFORM_VECTORS'] in {browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS'],browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS']-1} - if browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] != None: - assert webgl_params['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] in {browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS'],browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS']-1} - if browser.real.webgl_parameters['MAX_TEXTURE_SIZE'] != None: - assert webgl_params['MAX_TEXTURE_SIZE'] in {browser.real.webgl_parameters['MAX_TEXTURE_SIZE'],browser.real.webgl_parameters['MAX_TEXTURE_SIZE']-1} - if browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE'] != None: - assert webgl_params['MAX_CUBE_MAP_TEXTURE_SIZE'] in {browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE'],browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE']-1} - if browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE'] != None: - assert webgl_params['MAX_3D_TEXTURE_SIZE'] in {browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE'],browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE']-1} - if browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'] != None: - assert webgl_params['MAX_ARRAY_TEXTURE_LAYERS'] in {browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'],browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS']-1} - elif expected.webgl_parameters == 'ZERO VALUE': - assert ((webgl_params['MAX_VERTEX_UNIFORM_COMPONENTS'] == 0) and - (webgl_params['MAX_VERTEX_UNIFORM_BLOCKS'] == 0) and - (webgl_params['MAX_VERTEX_OUTPUT_COMPONENTS'] == 0) and - (webgl_params['MAX_VARYING_COMPONENTS'] == 0) and - (webgl_params['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] == 0) and - (webgl_params['MAX_FRAGMENT_UNIFORM_COMPONENTS'] == 0) and - (webgl_params['MAX_FRAGMENT_UNIFORM_BLOCKS'] == 0) and - (webgl_params['MAX_FRAGMENT_INPUT_COMPONENTS'] == 0) and - (webgl_params['MAX_UNIFORM_BUFFER_BINDINGS'] == 0) and - (webgl_params['MAX_COMBINED_UNIFORM_BLOCKS'] == 0) and - (webgl_params['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] == 0) and - (webgl_params['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] == 0) and - (webgl_params['MAX_VERTEX_ATTRIBS'] == browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS']) and - (webgl_params['MAX_VERTEX_UNIFORM_VECTORS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS']) and - (webgl_params['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] == browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS']) and - (webgl_params['MAX_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_TEXTURE_SIZE']) and - (webgl_params['MAX_CUBE_MAP_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE']) and - (webgl_params['MAX_3D_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE']) and - (webgl_params['MAX_ARRAY_TEXTURE_LAYERS'] == browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'])) - else: - assert ((webgl_params['MAX_VERTEX_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_COMPONENTS']) and - (webgl_params['MAX_VERTEX_UNIFORM_BLOCKS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_BLOCKS']) and - (webgl_params['MAX_VERTEX_OUTPUT_COMPONENTS'] == browser.real.webgl_parameters['MAX_VERTEX_OUTPUT_COMPONENTS']) and - (webgl_params['MAX_VARYING_COMPONENTS'] == browser.real.webgl_parameters['MAX_VARYING_COMPONENTS']) and - (webgl_params['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS'] == browser.real.webgl_parameters['MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS']) and - (webgl_params['MAX_FRAGMENT_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_COMPONENTS']) and - (webgl_params['MAX_FRAGMENT_UNIFORM_BLOCKS'] == browser.real.webgl_parameters['MAX_FRAGMENT_UNIFORM_BLOCKS']) and - (webgl_params['MAX_FRAGMENT_INPUT_COMPONENTS'] == browser.real.webgl_parameters['MAX_FRAGMENT_INPUT_COMPONENTS']) and - (webgl_params['MAX_UNIFORM_BUFFER_BINDINGS'] == browser.real.webgl_parameters['MAX_UNIFORM_BUFFER_BINDINGS']) and - (webgl_params['MAX_COMBINED_UNIFORM_BLOCKS'] == browser.real.webgl_parameters['MAX_COMBINED_UNIFORM_BLOCKS']) and - (webgl_params['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS']) and - (webgl_params['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS'] == browser.real.webgl_parameters['MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS']) and - (webgl_params['MAX_VERTEX_ATTRIBS'] == browser.real.webgl_parameters['MAX_VERTEX_ATTRIBS']) and - (webgl_params['MAX_VERTEX_UNIFORM_VECTORS'] == browser.real.webgl_parameters['MAX_VERTEX_UNIFORM_VECTORS']) and - (webgl_params['MAX_VERTEX_TEXTURE_IMAGE_UNITS'] == browser.real.webgl_parameters['MAX_VERTEX_TEXTURE_IMAGE_UNITS']) and - (webgl_params['MAX_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_TEXTURE_SIZE']) and - (webgl_params['MAX_CUBE_MAP_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_CUBE_MAP_TEXTURE_SIZE']) and - (webgl_params['MAX_3D_TEXTURE_SIZE'] == browser.real.webgl_parameters['MAX_3D_TEXTURE_SIZE']) and - (webgl_params['MAX_ARRAY_TEXTURE_LAYERS'] == browser.real.webgl_parameters['MAX_ARRAY_TEXTURE_LAYERS'])) - -# Test WebGLRenderingContext.getShaderPrecisionFormat -def test_webgl_precisions(browser, expected): - precisions = get_webgl_precisions(browser.driver,"webglCanvas") - if expected.webgl_precisions == 'SPOOF VALUE': - assert precisions != browser.real.webgl_precisions - else: - assert precisions == browser.real.webgl_precisions - -# Test WebGLRenderingContext.readPixels -def test_webgl_read_pixels(browser, expected): - pixels = get_webgl_pixels(browser.driver,"webglCanvas") - if pixels == "ERROR": - print("\nWebGLRenderingContext.readPixels failed.") - assert False - if expected.webgl_pixels == 'SPOOF VALUE': - assert pixels != browser.real.webgl_pixels - else: - assert pixels == browser.real.webgl_pixels - -# Test HTMLCanvasElement.toDataURL on webgl canvas -def test_webgl_to_data_URL(browser, expected): - image = get_dataURL_canvas(browser.driver,"webglCanvas") - if expected.webgl_dataURL == 'SPOOF VALUE': - assert image != browser.real.webgl_dataURL - else: - assert image == browser.real.webgl_dataURL From 9b74db69b198f03140c90c0736b1fbf2611e458e Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:00:45 +0000 Subject: [PATCH 32/38] Integration tests: Change order of tests. HW test has to be the first one otherwise it crashes (an unknown reason). --- diff --git a/tests/integration_tests/testing/tests_definition/test_01_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_01_ECMA_arrays.py deleted file mode 100644 index 72502fd..0000000 --- a/tests/integration_tests/testing/tests_definition/test_01_ECMA_arrays.py +++ /dev/null @@ -1,48 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2022 Martin Bednar -# -# 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 . -# - -import pytest -from selenium.webdriver.common.by import By - -from configuration import get_config - -## Setup method - it is run before time tests execution starts. -# -# This setup method open testing page. -@pytest.fixture(scope='module', autouse=True) -def load_test_page(browser): - browser.driver.get(get_config("testing_page")) - - -## Test crypto.getRandomValues. -# Random values should be generated. No error in Javascript runtime should appear. -# \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. -# Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). -@pytest.mark.xfail -def test_crypto_getRandomValues(browser): - ul = browser.driver.find_element(By.ID,"getRandomValues") - if len(ul.text) > 0: - items = ul.find_elements(By.TAG_NAME,"li") - assert len(items) > 0 - else: - pytest.fail("No random value generated. Probable JavaScript error: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView.") diff --git a/tests/integration_tests/testing/tests_definition/test_01_hw.py b/tests/integration_tests/testing/tests_definition/test_01_hw.py new file mode 100644 index 0000000..a7bfb54 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_01_hw.py @@ -0,0 +1,82 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest + +from values_getters import get_device, get_IOdevices + + +## Setup method - it is run before hw tests execution starts. +# +# This setup method initialize variable device that contains current data about device and +# this variable is provided to device tests and values in device variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def device(browser): + return get_device(browser.driver) + + +## Setup method - it is run before hw tests execution starts. +# +# This setup method initialize variable IOdevices that contains current data about IO devices and +# this variable is provided to device tests and values in IOdevices variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def IOdevices(browser): + return get_IOdevices(browser.driver) + + +## Test device memory. +def test_device_memory(browser, device, expected): + if expected.device.deviceMemory[browser.type] == 'SPOOF VALUE': + assert device['deviceMemory'] in expected.device.deviceMemory['valid_values'] + assert device['deviceMemory'] <= browser.real.device.deviceMemory + else: + assert device['deviceMemory'] == browser.real.device.deviceMemory + + +## Test hardware concurrency. +def test_hardware_concurrency(browser, device, expected): + if expected.device.hardwareConcurrency['value'] == 'REAL VALUE': + assert device['hardwareConcurrency'] == browser.real.device.hardwareConcurrency + elif expected.device.hardwareConcurrency['value'] == 'SPOOF VALUE': + expectedval = expected.device.hardwareConcurrency['valid_values'] + if expectedval == "UP TO REAL VALUE": + expectedval = range(browser.real.device.hardwareConcurrency + 1) + assert device['hardwareConcurrency'] in expectedval + else: + assert False # We should not get here + + +## Test IOdevices. +def test_IOdevices(browser, IOdevices, expected): + if expected.device.IOdevices == 'REAL VALUE': + assert len(IOdevices) == len(browser.real.device.IOdevices) + for i in range(len(IOdevices)): + assert IOdevices[i]['kind'] == browser.real.device.IOdevices[i]['kind'] + elif expected.device.IOdevices == 'EMPTY': + if IOdevices == 'ERROR': + assert IOdevices == 'ERROR' + else: + assert IOdevices == [] + assert len(IOdevices) == 0 + else: + assert len(IOdevices) in expected.device.IOdevices diff --git a/tests/integration_tests/testing/tests_definition/test_03_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_03_ECMA_arrays.py new file mode 100644 index 0000000..72502fd --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_03_ECMA_arrays.py @@ -0,0 +1,48 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2022 Martin Bednar +# +# 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 . +# + +import pytest +from selenium.webdriver.common.by import By + +from configuration import get_config + +## Setup method - it is run before time tests execution starts. +# +# This setup method open testing page. +@pytest.fixture(scope='module', autouse=True) +def load_test_page(browser): + browser.driver.get(get_config("testing_page")) + + +## Test crypto.getRandomValues. +# Random values should be generated. No error in Javascript runtime should appear. +# \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. +# Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). +@pytest.mark.xfail +def test_crypto_getRandomValues(browser): + ul = browser.driver.find_element(By.ID,"getRandomValues") + if len(ul.text) > 0: + items = ul.find_elements(By.TAG_NAME,"li") + assert len(items) > 0 + else: + pytest.fail("No random value generated. Probable JavaScript error: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView.") diff --git a/tests/integration_tests/testing/tests_definition/test_03_hw.py b/tests/integration_tests/testing/tests_definition/test_03_hw.py deleted file mode 100644 index a7bfb54..0000000 --- a/tests/integration_tests/testing/tests_definition/test_03_hw.py +++ /dev/null @@ -1,82 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest - -from values_getters import get_device, get_IOdevices - - -## Setup method - it is run before hw tests execution starts. -# -# This setup method initialize variable device that contains current data about device and -# this variable is provided to device tests and values in device variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def device(browser): - return get_device(browser.driver) - - -## Setup method - it is run before hw tests execution starts. -# -# This setup method initialize variable IOdevices that contains current data about IO devices and -# this variable is provided to device tests and values in IOdevices variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def IOdevices(browser): - return get_IOdevices(browser.driver) - - -## Test device memory. -def test_device_memory(browser, device, expected): - if expected.device.deviceMemory[browser.type] == 'SPOOF VALUE': - assert device['deviceMemory'] in expected.device.deviceMemory['valid_values'] - assert device['deviceMemory'] <= browser.real.device.deviceMemory - else: - assert device['deviceMemory'] == browser.real.device.deviceMemory - - -## Test hardware concurrency. -def test_hardware_concurrency(browser, device, expected): - if expected.device.hardwareConcurrency['value'] == 'REAL VALUE': - assert device['hardwareConcurrency'] == browser.real.device.hardwareConcurrency - elif expected.device.hardwareConcurrency['value'] == 'SPOOF VALUE': - expectedval = expected.device.hardwareConcurrency['valid_values'] - if expectedval == "UP TO REAL VALUE": - expectedval = range(browser.real.device.hardwareConcurrency + 1) - assert device['hardwareConcurrency'] in expectedval - else: - assert False # We should not get here - - -## Test IOdevices. -def test_IOdevices(browser, IOdevices, expected): - if expected.device.IOdevices == 'REAL VALUE': - assert len(IOdevices) == len(browser.real.device.IOdevices) - for i in range(len(IOdevices)): - assert IOdevices[i]['kind'] == browser.real.device.IOdevices[i]['kind'] - elif expected.device.IOdevices == 'EMPTY': - if IOdevices == 'ERROR': - assert IOdevices == 'ERROR' - else: - assert IOdevices == [] - assert len(IOdevices) == 0 - else: - assert len(IOdevices) in expected.device.IOdevices From bd89f45c093d1cb1aafdacc1c55db90cfcc7bb94 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:00:56 +0000 Subject: [PATCH 33/38] Integration tests: Change order of tests. --- diff --git a/tests/integration_tests/testing/tests_definition/test_02_NBS_setting.py b/tests/integration_tests/testing/tests_definition/test_02_NBS_setting.py deleted file mode 100644 index 691e7c5..0000000 --- a/tests/integration_tests/testing/tests_definition/test_02_NBS_setting.py +++ /dev/null @@ -1,57 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest -from selenium.webdriver.common.by import By -from time import sleep - - -def switch_NBS_setting(browser): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) - sleep(1) - browser.driver.find_elements(By.CLASS_NAME, 'slider')[1].click() - sleep(1) - - -def get_NBS_setting(browser): - browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) - sleep(2) - return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('#nbs_whitelist .switch_wrapper .switch .slider'),':before').getPropertyValue('content')")) - - -## Test turnning NBS off in popup. -## Sleep 0.5 second to changes take effect. -def test_switching_NBS(browser): - NBS_setting_values = ['"ON"', '"OFF"'] - - original_setting = get_NBS_setting(browser) - original_setting_index = NBS_setting_values.index(original_setting) - - # Range is saing how many times should NBS be switched. - for i in range(4): - switch_NBS_setting(browser) - assert get_NBS_setting(browser) == NBS_setting_values[(i + 1 + original_setting_index) % 2] - - # Return original value - if get_NBS_setting(browser) != original_setting: - switch_NBS_setting(browser) diff --git a/tests/integration_tests/testing/tests_definition/test_02_referrer.py b/tests/integration_tests/testing/tests_definition/test_02_referrer.py new file mode 100644 index 0000000..1eb98b7 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_02_referrer.py @@ -0,0 +1,43 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2020 Martin Bednar +# +# 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 . +# + +import pytest + +from values_getters import get_referrer + + +## Setup method - it is run before referrer test execution starts. +# +# This setup method initialize variable referrer that contains current data about referrer and +# this variable is provided to referrer test and value in referrer variable is compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def referrer(browser): + return get_referrer(browser.driver) + + +## Test referrer - where the page was navigated from. +def test_referrer(browser, referrer, expected): + if expected.referrer == 'REAL VALUE': + assert referrer == browser.real.referrer + else: + assert referrer == expected.referrer diff --git a/tests/integration_tests/testing/tests_definition/test_03_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_03_ECMA_arrays.py deleted file mode 100644 index 72502fd..0000000 --- a/tests/integration_tests/testing/tests_definition/test_03_ECMA_arrays.py +++ /dev/null @@ -1,48 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2022 Martin Bednar -# -# 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 . -# - -import pytest -from selenium.webdriver.common.by import By - -from configuration import get_config - -## Setup method - it is run before time tests execution starts. -# -# This setup method open testing page. -@pytest.fixture(scope='module', autouse=True) -def load_test_page(browser): - browser.driver.get(get_config("testing_page")) - - -## Test crypto.getRandomValues. -# Random values should be generated. No error in Javascript runtime should appear. -# \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. -# Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). -@pytest.mark.xfail -def test_crypto_getRandomValues(browser): - ul = browser.driver.find_element(By.ID,"getRandomValues") - if len(ul.text) > 0: - items = ul.find_elements(By.TAG_NAME,"li") - assert len(items) > 0 - else: - pytest.fail("No random value generated. Probable JavaScript error: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView.") diff --git a/tests/integration_tests/testing/tests_definition/test_03_gps.py b/tests/integration_tests/testing/tests_definition/test_03_gps.py new file mode 100644 index 0000000..91243fb --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_03_gps.py @@ -0,0 +1,217 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest +from time import time + +from values_getters import get_position +from math_operations import is_in_accuracy, calc_distance + +## Setup method - it is run before gps tests execution starts. +# +# This setup method initialize variable position that contains current data about position and +# this variable is provided to gps tests and values in position variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def position(browser): + position = { + 'accuracy' : "null", + 'altitude' : "null", + 'altitudeaccurac' : "null", + 'heading' : "null", + 'latitude' : "null", + 'longitude' : "null", + 'speed' : "null", + 'timestamp' : "null" + } + try: + position = get_position(browser.driver) + except: + print("\nCan not read GPS data.") + return position + + +## Test accuracy of the latitude and longitude properties in meters. +def test_accuracy(browser, position, expected): + if expected.geolocation.accuracy['value'] == 'REAL VALUE': + if position['accuracy'] == "null": + # If current value is null, real value has to be null too. + assert position['accuracy'] == browser.real.geolocation.accuracy + else: + if expected.geolocation.accuracy['accuracy'] == 'EXACTLY': + # x is real position (position returned without JShelter) + # y should be real position too (position returned with JShelter level 0) + # + # It is clear that x and y will not be exact same values. This is due to the netural GPS inaccuracy. + # A small difference is tolerated. + # x.accuracy and y.accuracy will be probably different. + # But distance between x and y should be less than (x.accuracy + y.accuracy). + assert calc_distance(float(browser.real.geolocation.latitude), + float(browser.real.geolocation.longitude), + float(position['latitude']), + float(position['longitude'])) < (float(browser.real.geolocation.accuracy) + float(position['accuracy'])) + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['accuracy'], expected.geolocation.accuracy['accuracy']) + else: + # Should be spoofed value. + assert position['accuracy'] == expected.geolocation.accuracy['value'] + + +## Test position's altitude in meters, relative to sea level. +def test_altitude(browser, position, expected): + if expected.geolocation.altitude['value'] == 'REAL VALUE': + if position['altitude'] == "null": + # If current value is null, real value has to be null too. + assert position['altitude'] == browser.real.geolocation.altitude + else: + if expected.geolocation.altitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 10 meters is tolerated. + assert abs(float(position['altitude']) - float(browser.real.geolocation.altitude)) < 10 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['altitude'], expected.geolocation.altitude['accuracy']) + else: + # Should be spoofed value. + assert position['altitude'] == expected.geolocation.altitude['value'] + + +## Test accuracy of the altitude property in meters. +def test_altitudeaccurac(browser, position, expected): + if expected.geolocation.altitudeAccurac['value'] == 'REAL VALUE': + if position['altitudeaccurac'] == "null": + # If current value is null, real value has to be null too. + assert position['altitudeaccurac'] == browser.real.geolocation.altitudeAccurac + else: + if expected.geolocation.altitudeAccurac['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 10 meters is tolerated. + assert abs(float(position['altitudeaccurac']) - float(browser.real.geolocation.altitudeAccurac)) < 10 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['altitudeaccurac'], + expected.geolocation.altitudeAccurac['accuracy']) + else: + # Should be spoofed value. + assert position['altitudeaccurac'] == expected.geolocation.altitudeAccurac['value'] + + +## Test heading. +# +# Heading is the direction in which the device is traveling. This value, specified in degrees, +# indicates how far off from heading true north the device is. 0 degrees represents true north, +# and the direction is determined clockwise (east is 90 degrees and west is 270 degrees). +# If speed is 0, heading is NaN. If the device is unable to provide heading information, this value is null +def test_heading(browser, position, expected): + if expected.geolocation.heading['value'] == 'REAL VALUE': + if position['heading'] == "null": + # If current value is null, real value has to be null too. + assert position['heading'] == browser.real.geolocation.heading + else: + if expected.geolocation.heading['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 30 degrees is tolerated. + assert abs(float(position['heading']) - float(browser.real.geolocation.heading)) < 30 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['heading'], expected.geolocation.heading['accuracy']) + else: + # Should be spoofed value. + assert position['heading'] == expected.geolocation.heading['value'] + + +## Test position's latitude in decimal degrees. +def test_latitude(browser, position, expected): + if expected.geolocation.latitude['value'] == 'REAL VALUE': + if position['latitude'] == "null": + # If current value is null, real value has to be null too. + assert position['latitude'] == browser.real.geolocation.latitude + else: + if expected.geolocation.latitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 1 degrees is tolerated. + assert abs(float(position['latitude']) - float(browser.real.geolocation.latitude)) < 1 + else: + real_latitude = float(browser.real.geolocation.latitude) + spoofed_latitude = float(position['latitude']) + max_allowed_deviation = expected.geolocation.latitude['accuracy'] + assert abs(real_latitude - spoofed_latitude) < max_allowed_deviation + else: + # Should be spoofed value. + assert position['latitude'] == expected.geolocation.latitude['value'] + + +## Test position's longitude in decimal degrees. +def test_longitude(browser, position, expected): + if expected.geolocation.longitude['value'] == 'REAL VALUE': + if position['longitude'] == "null": + # If current value is null, real value has to be null too. + assert position['longitude'] == browser.real.geolocation.longitude + else: + if expected.geolocation.longitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 1 degrees is tolerated. + assert abs(float(position['longitude']) - float(browser.real.geolocation.longitude)) < 1 + else: + real_longitude = float(browser.real.geolocation.longitude) + spoofed_longitude = float(position['longitude']) + max_allowed_deviation = expected.geolocation.longitude['accuracy'] + assert abs(real_longitude - spoofed_longitude) < max_allowed_deviation + else: + # Should be spoofed value. + assert position['longitude'] == expected.geolocation.longitude['value'] + + +## Test speed (velocity) of the device in meters per second. This value can be null. +def test_speed(browser, position, expected): + if expected.geolocation.speed['value'] == 'REAL VALUE': + if position['speed'] == "null": + # If current value is null, real value has to be null too. + assert position['speed'] == browser.real.geolocation.speed + else: + if expected.geolocation.speed['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 5 meters per second is tolerated. + assert abs(float(position['speed']) - float(browser.real.geolocation.speed)) < 5 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['speed'], expected.geolocation.speed['accuracy']) + else: + # Should be spoofed value. + assert position['speed'] == expected.geolocation.speed['value'] + + +## Test timestamp. +def test_timestamp(position, expected): + if expected.geolocation.timestamp['value'] == 'REAL VALUE': + if expected.geolocation.timestamp['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal because executing command takes some time. + # A deviation of less than 2 seconds is tolerated. + assert abs(time() - int(position['timestamp'])/1000) < 2 + else: + timestamp_accuracy = expected.geolocation.timestamp['accuracy']*1000 + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['timestamp'], timestamp_accuracy) + else: + # Should be spoofed value. + assert position['timestamp'] == expected.geolocation.timestamp['value'] diff --git a/tests/integration_tests/testing/tests_definition/test_04_NBS_setting.py b/tests/integration_tests/testing/tests_definition/test_04_NBS_setting.py new file mode 100644 index 0000000..691e7c5 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_04_NBS_setting.py @@ -0,0 +1,57 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest +from selenium.webdriver.common.by import By +from time import sleep + + +def switch_NBS_setting(browser): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) + sleep(1) + browser.driver.find_elements(By.CLASS_NAME, 'slider')[1].click() + sleep(1) + + +def get_NBS_setting(browser): + browser.driver.get(browser._jsr_options_page.replace("/options.html", "/popup.html")) + sleep(2) + return(browser.driver.execute_script("return window.getComputedStyle(document.querySelector('#nbs_whitelist .switch_wrapper .switch .slider'),':before').getPropertyValue('content')")) + + +## Test turnning NBS off in popup. +## Sleep 0.5 second to changes take effect. +def test_switching_NBS(browser): + NBS_setting_values = ['"ON"', '"OFF"'] + + original_setting = get_NBS_setting(browser) + original_setting_index = NBS_setting_values.index(original_setting) + + # Range is saing how many times should NBS be switched. + for i in range(4): + switch_NBS_setting(browser) + assert get_NBS_setting(browser) == NBS_setting_values[(i + 1 + original_setting_index) % 2] + + # Return original value + if get_NBS_setting(browser) != original_setting: + switch_NBS_setting(browser) diff --git a/tests/integration_tests/testing/tests_definition/test_04_canvas.py b/tests/integration_tests/testing/tests_definition/test_04_canvas.py deleted file mode 100644 index e671c65..0000000 --- a/tests/integration_tests/testing/tests_definition/test_04_canvas.py +++ /dev/null @@ -1,104 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2020 Martin Bednar -# Copyright (C) 2021 Matus Svancar -# -# 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 . -# - -from values_getters import is_canvas_spoofed -from values_getters import get_dataURL_canvas -from values_getters import get_imageData_canvas -from values_getters import get_blob_canvas -from values_getters import get_point_in_path -from values_getters import get_point_in_stroke - - -## Test canvas - if canvas is spoofed: Reading from canvas returns white image. -## -## This test fails in Google Chrome on JShelter level 3 - expected failure because of known bug: -## selenium.common.exceptions.JavascriptException: Message: javascript error: -## Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'. -def test_canvas(browser, expected): - is_spoofed = is_canvas_spoofed(browser.driver) - if is_spoofed == "ERROR": - print("\nCan not read Canvas data.") - assert False - else: - if expected.protect_canvas: - assert is_spoofed - else: - assert not is_spoofed - -def test_getImageData(browser, expected): - image = get_imageData_canvas(browser.driver,"canvasx") - if image == "ERROR": - print("\n getImageData error.") - assert False - else: - if expected.canvas_imageData == 'SPOOF VALUE': - assert image != browser.real.canvas_imageData - else: - assert image == browser.real.canvas_imageData - - -def test_to_data_URL(browser, expected): - image = get_dataURL_canvas(browser.driver,"canvasx") - if image == "ERROR": - print("\n toDataURL error.") - assert False - else: - if expected.canvas_dataURL == 'SPOOF VALUE': - assert image != browser.real.canvas_dataURL - else: - assert image == browser.real.canvas_dataURL - - -def test_to_blob(browser, expected): - image = get_blob_canvas(browser.driver,"canvasx") - if image == "ERROR": - print("\n toBlob error.") - assert False - else: - if expected.canvas_blob == 'SPOOF VALUE': - assert image != browser.real.canvas_blob - else: - assert image == browser.real.canvas_blob - -def test_is_point_in_path(browser, expected): - point = get_point_in_path(browser.driver,"canvas4", (expected.canvas_point_path == 'FALSE VALUE')) - if point == "ERROR": - print("\n isPointInPath error.") - assert False - else: - if expected.canvas_point_path in {'SPOOF VALUE','FALSE VALUE'}: - assert point == False - else: - assert point == True - -def test_is_point_in_stroke(browser, expected): - point = get_point_in_stroke(browser.driver,"canvas5", (expected.canvas_point_stroke == 'FALSE VALUE')) - if point == "ERROR": - print("\n isPointInStroke error.") - assert False - else: - if expected.canvas_point_stroke in {'SPOOF VALUE','FALSE VALUE'} : - assert point == False - else: - assert point == True diff --git a/tests/integration_tests/testing/tests_definition/test_06_canvas.py b/tests/integration_tests/testing/tests_definition/test_06_canvas.py new file mode 100644 index 0000000..e671c65 --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_06_canvas.py @@ -0,0 +1,104 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2020 Martin Bednar +# Copyright (C) 2021 Matus Svancar +# +# 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 . +# + +from values_getters import is_canvas_spoofed +from values_getters import get_dataURL_canvas +from values_getters import get_imageData_canvas +from values_getters import get_blob_canvas +from values_getters import get_point_in_path +from values_getters import get_point_in_stroke + + +## Test canvas - if canvas is spoofed: Reading from canvas returns white image. +## +## This test fails in Google Chrome on JShelter level 3 - expected failure because of known bug: +## selenium.common.exceptions.JavascriptException: Message: javascript error: +## Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'. +def test_canvas(browser, expected): + is_spoofed = is_canvas_spoofed(browser.driver) + if is_spoofed == "ERROR": + print("\nCan not read Canvas data.") + assert False + else: + if expected.protect_canvas: + assert is_spoofed + else: + assert not is_spoofed + +def test_getImageData(browser, expected): + image = get_imageData_canvas(browser.driver,"canvasx") + if image == "ERROR": + print("\n getImageData error.") + assert False + else: + if expected.canvas_imageData == 'SPOOF VALUE': + assert image != browser.real.canvas_imageData + else: + assert image == browser.real.canvas_imageData + + +def test_to_data_URL(browser, expected): + image = get_dataURL_canvas(browser.driver,"canvasx") + if image == "ERROR": + print("\n toDataURL error.") + assert False + else: + if expected.canvas_dataURL == 'SPOOF VALUE': + assert image != browser.real.canvas_dataURL + else: + assert image == browser.real.canvas_dataURL + + +def test_to_blob(browser, expected): + image = get_blob_canvas(browser.driver,"canvasx") + if image == "ERROR": + print("\n toBlob error.") + assert False + else: + if expected.canvas_blob == 'SPOOF VALUE': + assert image != browser.real.canvas_blob + else: + assert image == browser.real.canvas_blob + +def test_is_point_in_path(browser, expected): + point = get_point_in_path(browser.driver,"canvas4", (expected.canvas_point_path == 'FALSE VALUE')) + if point == "ERROR": + print("\n isPointInPath error.") + assert False + else: + if expected.canvas_point_path in {'SPOOF VALUE','FALSE VALUE'}: + assert point == False + else: + assert point == True + +def test_is_point_in_stroke(browser, expected): + point = get_point_in_stroke(browser.driver,"canvas5", (expected.canvas_point_stroke == 'FALSE VALUE')) + if point == "ERROR": + print("\n isPointInStroke error.") + assert False + else: + if expected.canvas_point_stroke in {'SPOOF VALUE','FALSE VALUE'} : + assert point == False + else: + assert point == True diff --git a/tests/integration_tests/testing/tests_definition/test_06_gps.py b/tests/integration_tests/testing/tests_definition/test_06_gps.py deleted file mode 100644 index 91243fb..0000000 --- a/tests/integration_tests/testing/tests_definition/test_06_gps.py +++ /dev/null @@ -1,217 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest -from time import time - -from values_getters import get_position -from math_operations import is_in_accuracy, calc_distance - -## Setup method - it is run before gps tests execution starts. -# -# This setup method initialize variable position that contains current data about position and -# this variable is provided to gps tests and values in position variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def position(browser): - position = { - 'accuracy' : "null", - 'altitude' : "null", - 'altitudeaccurac' : "null", - 'heading' : "null", - 'latitude' : "null", - 'longitude' : "null", - 'speed' : "null", - 'timestamp' : "null" - } - try: - position = get_position(browser.driver) - except: - print("\nCan not read GPS data.") - return position - - -## Test accuracy of the latitude and longitude properties in meters. -def test_accuracy(browser, position, expected): - if expected.geolocation.accuracy['value'] == 'REAL VALUE': - if position['accuracy'] == "null": - # If current value is null, real value has to be null too. - assert position['accuracy'] == browser.real.geolocation.accuracy - else: - if expected.geolocation.accuracy['accuracy'] == 'EXACTLY': - # x is real position (position returned without JShelter) - # y should be real position too (position returned with JShelter level 0) - # - # It is clear that x and y will not be exact same values. This is due to the netural GPS inaccuracy. - # A small difference is tolerated. - # x.accuracy and y.accuracy will be probably different. - # But distance between x and y should be less than (x.accuracy + y.accuracy). - assert calc_distance(float(browser.real.geolocation.latitude), - float(browser.real.geolocation.longitude), - float(position['latitude']), - float(position['longitude'])) < (float(browser.real.geolocation.accuracy) + float(position['accuracy'])) - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['accuracy'], expected.geolocation.accuracy['accuracy']) - else: - # Should be spoofed value. - assert position['accuracy'] == expected.geolocation.accuracy['value'] - - -## Test position's altitude in meters, relative to sea level. -def test_altitude(browser, position, expected): - if expected.geolocation.altitude['value'] == 'REAL VALUE': - if position['altitude'] == "null": - # If current value is null, real value has to be null too. - assert position['altitude'] == browser.real.geolocation.altitude - else: - if expected.geolocation.altitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 10 meters is tolerated. - assert abs(float(position['altitude']) - float(browser.real.geolocation.altitude)) < 10 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['altitude'], expected.geolocation.altitude['accuracy']) - else: - # Should be spoofed value. - assert position['altitude'] == expected.geolocation.altitude['value'] - - -## Test accuracy of the altitude property in meters. -def test_altitudeaccurac(browser, position, expected): - if expected.geolocation.altitudeAccurac['value'] == 'REAL VALUE': - if position['altitudeaccurac'] == "null": - # If current value is null, real value has to be null too. - assert position['altitudeaccurac'] == browser.real.geolocation.altitudeAccurac - else: - if expected.geolocation.altitudeAccurac['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 10 meters is tolerated. - assert abs(float(position['altitudeaccurac']) - float(browser.real.geolocation.altitudeAccurac)) < 10 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['altitudeaccurac'], - expected.geolocation.altitudeAccurac['accuracy']) - else: - # Should be spoofed value. - assert position['altitudeaccurac'] == expected.geolocation.altitudeAccurac['value'] - - -## Test heading. -# -# Heading is the direction in which the device is traveling. This value, specified in degrees, -# indicates how far off from heading true north the device is. 0 degrees represents true north, -# and the direction is determined clockwise (east is 90 degrees and west is 270 degrees). -# If speed is 0, heading is NaN. If the device is unable to provide heading information, this value is null -def test_heading(browser, position, expected): - if expected.geolocation.heading['value'] == 'REAL VALUE': - if position['heading'] == "null": - # If current value is null, real value has to be null too. - assert position['heading'] == browser.real.geolocation.heading - else: - if expected.geolocation.heading['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 30 degrees is tolerated. - assert abs(float(position['heading']) - float(browser.real.geolocation.heading)) < 30 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['heading'], expected.geolocation.heading['accuracy']) - else: - # Should be spoofed value. - assert position['heading'] == expected.geolocation.heading['value'] - - -## Test position's latitude in decimal degrees. -def test_latitude(browser, position, expected): - if expected.geolocation.latitude['value'] == 'REAL VALUE': - if position['latitude'] == "null": - # If current value is null, real value has to be null too. - assert position['latitude'] == browser.real.geolocation.latitude - else: - if expected.geolocation.latitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 1 degrees is tolerated. - assert abs(float(position['latitude']) - float(browser.real.geolocation.latitude)) < 1 - else: - real_latitude = float(browser.real.geolocation.latitude) - spoofed_latitude = float(position['latitude']) - max_allowed_deviation = expected.geolocation.latitude['accuracy'] - assert abs(real_latitude - spoofed_latitude) < max_allowed_deviation - else: - # Should be spoofed value. - assert position['latitude'] == expected.geolocation.latitude['value'] - - -## Test position's longitude in decimal degrees. -def test_longitude(browser, position, expected): - if expected.geolocation.longitude['value'] == 'REAL VALUE': - if position['longitude'] == "null": - # If current value is null, real value has to be null too. - assert position['longitude'] == browser.real.geolocation.longitude - else: - if expected.geolocation.longitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 1 degrees is tolerated. - assert abs(float(position['longitude']) - float(browser.real.geolocation.longitude)) < 1 - else: - real_longitude = float(browser.real.geolocation.longitude) - spoofed_longitude = float(position['longitude']) - max_allowed_deviation = expected.geolocation.longitude['accuracy'] - assert abs(real_longitude - spoofed_longitude) < max_allowed_deviation - else: - # Should be spoofed value. - assert position['longitude'] == expected.geolocation.longitude['value'] - - -## Test speed (velocity) of the device in meters per second. This value can be null. -def test_speed(browser, position, expected): - if expected.geolocation.speed['value'] == 'REAL VALUE': - if position['speed'] == "null": - # If current value is null, real value has to be null too. - assert position['speed'] == browser.real.geolocation.speed - else: - if expected.geolocation.speed['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 5 meters per second is tolerated. - assert abs(float(position['speed']) - float(browser.real.geolocation.speed)) < 5 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['speed'], expected.geolocation.speed['accuracy']) - else: - # Should be spoofed value. - assert position['speed'] == expected.geolocation.speed['value'] - - -## Test timestamp. -def test_timestamp(position, expected): - if expected.geolocation.timestamp['value'] == 'REAL VALUE': - if expected.geolocation.timestamp['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal because executing command takes some time. - # A deviation of less than 2 seconds is tolerated. - assert abs(time() - int(position['timestamp'])/1000) < 2 - else: - timestamp_accuracy = expected.geolocation.timestamp['accuracy']*1000 - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['timestamp'], timestamp_accuracy) - else: - # Should be spoofed value. - assert position['timestamp'] == expected.geolocation.timestamp['value'] diff --git a/tests/integration_tests/testing/tests_definition/test_09_ECMA_arrays.py b/tests/integration_tests/testing/tests_definition/test_09_ECMA_arrays.py new file mode 100644 index 0000000..72502fd --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_09_ECMA_arrays.py @@ -0,0 +1,48 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2022 Martin Bednar +# +# 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 . +# + +import pytest +from selenium.webdriver.common.by import By + +from configuration import get_config + +## Setup method - it is run before time tests execution starts. +# +# This setup method open testing page. +@pytest.fixture(scope='module', autouse=True) +def load_test_page(browser): + browser.driver.get(get_config("testing_page")) + + +## Test crypto.getRandomValues. +# Random values should be generated. No error in Javascript runtime should appear. +# \bug Known bug: JShelter, Firefox, level 3: Uncaught TypeError: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView. +# Bug is caused by passing a proxy object to the function, but the actual object is expected (not the proxy). +@pytest.mark.xfail +def test_crypto_getRandomValues(browser): + ul = browser.driver.find_element(By.ID,"getRandomValues") + if len(ul.text) > 0: + items = ul.find_elements(By.TAG_NAME,"li") + assert len(items) > 0 + else: + pytest.fail("No random value generated. Probable JavaScript error: Crypto.getRandomValues: Argument 1 does not implement interface ArrayBufferView.") diff --git a/tests/integration_tests/testing/tests_definition/test_09_referrer.py b/tests/integration_tests/testing/tests_definition/test_09_referrer.py deleted file mode 100644 index 1eb98b7..0000000 --- a/tests/integration_tests/testing/tests_definition/test_09_referrer.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2020 Martin Bednar -# -# 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 . -# - -import pytest - -from values_getters import get_referrer - - -## Setup method - it is run before referrer test execution starts. -# -# This setup method initialize variable referrer that contains current data about referrer and -# this variable is provided to referrer test and value in referrer variable is compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def referrer(browser): - return get_referrer(browser.driver) - - -## Test referrer - where the page was navigated from. -def test_referrer(browser, referrer, expected): - if expected.referrer == 'REAL VALUE': - assert referrer == browser.real.referrer - else: - assert referrer == expected.referrer From e31ccec75d9a4cc4338d6733d22dbdc1635b4a57 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:01:08 +0000 Subject: [PATCH 34/38] Integration tests: Delete referrer test. The referrer is not spoofed anymore. --- diff --git a/tests/integration_tests/testing/tests_definition/test_02_referrer.py b/tests/integration_tests/testing/tests_definition/test_02_referrer.py deleted file mode 100644 index 1eb98b7..0000000 --- a/tests/integration_tests/testing/tests_definition/test_02_referrer.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2020 Martin Bednar -# -# 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 . -# - -import pytest - -from values_getters import get_referrer - - -## Setup method - it is run before referrer test execution starts. -# -# This setup method initialize variable referrer that contains current data about referrer and -# this variable is provided to referrer test and value in referrer variable is compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def referrer(browser): - return get_referrer(browser.driver) - - -## Test referrer - where the page was navigated from. -def test_referrer(browser, referrer, expected): - if expected.referrer == 'REAL VALUE': - assert referrer == browser.real.referrer - else: - assert referrer == expected.referrer From f19d1546a476c1ad1787e597223e689fe2542718 Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:01:22 +0000 Subject: [PATCH 35/38] Integration tests: Update accuracy of time. Spoofing has changed. Time precision is no longer rounded to hundreds, but noise is added. This means tests can not check rounding. Time values seems to be exact (but actually with noise). --- diff --git a/tests/integration_tests/testing/values_expected.py b/tests/integration_tests/testing/values_expected.py index 799ade3..2f3694e 100644 --- a/tests/integration_tests/testing/values_expected.py +++ b/tests/integration_tests/testing/values_expected.py @@ -181,7 +181,7 @@ level2 = TestedValues( cookie_enabled='REAL VALUE', oscpu='REAL VALUE', gps_accuracy={'value': 'REAL VALUE', - 'accuracy': 100}, + 'accuracy': 1}, altitude={'value': 'REAL VALUE', 'accuracy': 100}, altitude_accurac={'value': 'REAL VALUE', @@ -197,7 +197,7 @@ level2 = TestedValues( speed={'value': 'REAL VALUE', 'accuracy': 100}, timestamp={'value': 'REAL VALUE', - 'accuracy': 0.1}, + 'accuracy': 0.001}, device_memory={BrowserType.FIREFOX: None, BrowserType.CHROME: 'SPOOF VALUE', 'valid_values': {0.25,0.5,1,2,4,8}}, @@ -206,7 +206,7 @@ level2 = TestedValues( IOdevices= {0,1,2,3,4,5,6,7,8,9}, referrer='REAL VALUE', time={'value': 'REAL VALUE', - 'accuracy': 0.1}, + 'accuracy': 1}, plugins={'count': {BrowserType.FIREFOX: 0, BrowserType.CHROME: 'IGNORE'}, 'value': {BrowserType.FIREFOX: 'EMPTY', @@ -219,7 +219,7 @@ level2 = TestedValues( byte_frequency= 'SPOOF VALUE', float_frequency= 'SPOOF VALUE', performance={'value': 'REAL VALUE', - 'accuracy': 100}, + 'accuracy': 1}, protect_canvas=False, canvas_imageData = 'SPOOF VALUE', canvas_dataURL = 'SPOOF VALUE', From 59b867fd8ee543af7916a3c8feece6194254f3aa Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:01:32 +0000 Subject: [PATCH 36/38] Integration tests: Move GPS tests to the end. Difficulties are sometimes with GPS tests. Run them at the end. If they crash, do not prevent other tests from running. --- diff --git a/tests/integration_tests/testing/tests_definition/test_03_gps.py b/tests/integration_tests/testing/tests_definition/test_03_gps.py deleted file mode 100644 index 91243fb..0000000 --- a/tests/integration_tests/testing/tests_definition/test_03_gps.py +++ /dev/null @@ -1,217 +0,0 @@ -# -# JShelter is a browser extension which increases level -# of security, anonymity and privacy of the user while browsing the -# internet. -# -# Copyright (C) 2021 Martin Bednar -# -# 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 . -# - -import pytest -from time import time - -from values_getters import get_position -from math_operations import is_in_accuracy, calc_distance - -## Setup method - it is run before gps tests execution starts. -# -# This setup method initialize variable position that contains current data about position and -# this variable is provided to gps tests and values in position variable are compared with expected values. -@pytest.fixture(scope='module', autouse=True) -def position(browser): - position = { - 'accuracy' : "null", - 'altitude' : "null", - 'altitudeaccurac' : "null", - 'heading' : "null", - 'latitude' : "null", - 'longitude' : "null", - 'speed' : "null", - 'timestamp' : "null" - } - try: - position = get_position(browser.driver) - except: - print("\nCan not read GPS data.") - return position - - -## Test accuracy of the latitude and longitude properties in meters. -def test_accuracy(browser, position, expected): - if expected.geolocation.accuracy['value'] == 'REAL VALUE': - if position['accuracy'] == "null": - # If current value is null, real value has to be null too. - assert position['accuracy'] == browser.real.geolocation.accuracy - else: - if expected.geolocation.accuracy['accuracy'] == 'EXACTLY': - # x is real position (position returned without JShelter) - # y should be real position too (position returned with JShelter level 0) - # - # It is clear that x and y will not be exact same values. This is due to the netural GPS inaccuracy. - # A small difference is tolerated. - # x.accuracy and y.accuracy will be probably different. - # But distance between x and y should be less than (x.accuracy + y.accuracy). - assert calc_distance(float(browser.real.geolocation.latitude), - float(browser.real.geolocation.longitude), - float(position['latitude']), - float(position['longitude'])) < (float(browser.real.geolocation.accuracy) + float(position['accuracy'])) - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['accuracy'], expected.geolocation.accuracy['accuracy']) - else: - # Should be spoofed value. - assert position['accuracy'] == expected.geolocation.accuracy['value'] - - -## Test position's altitude in meters, relative to sea level. -def test_altitude(browser, position, expected): - if expected.geolocation.altitude['value'] == 'REAL VALUE': - if position['altitude'] == "null": - # If current value is null, real value has to be null too. - assert position['altitude'] == browser.real.geolocation.altitude - else: - if expected.geolocation.altitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 10 meters is tolerated. - assert abs(float(position['altitude']) - float(browser.real.geolocation.altitude)) < 10 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['altitude'], expected.geolocation.altitude['accuracy']) - else: - # Should be spoofed value. - assert position['altitude'] == expected.geolocation.altitude['value'] - - -## Test accuracy of the altitude property in meters. -def test_altitudeaccurac(browser, position, expected): - if expected.geolocation.altitudeAccurac['value'] == 'REAL VALUE': - if position['altitudeaccurac'] == "null": - # If current value is null, real value has to be null too. - assert position['altitudeaccurac'] == browser.real.geolocation.altitudeAccurac - else: - if expected.geolocation.altitudeAccurac['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 10 meters is tolerated. - assert abs(float(position['altitudeaccurac']) - float(browser.real.geolocation.altitudeAccurac)) < 10 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['altitudeaccurac'], - expected.geolocation.altitudeAccurac['accuracy']) - else: - # Should be spoofed value. - assert position['altitudeaccurac'] == expected.geolocation.altitudeAccurac['value'] - - -## Test heading. -# -# Heading is the direction in which the device is traveling. This value, specified in degrees, -# indicates how far off from heading true north the device is. 0 degrees represents true north, -# and the direction is determined clockwise (east is 90 degrees and west is 270 degrees). -# If speed is 0, heading is NaN. If the device is unable to provide heading information, this value is null -def test_heading(browser, position, expected): - if expected.geolocation.heading['value'] == 'REAL VALUE': - if position['heading'] == "null": - # If current value is null, real value has to be null too. - assert position['heading'] == browser.real.geolocation.heading - else: - if expected.geolocation.heading['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 30 degrees is tolerated. - assert abs(float(position['heading']) - float(browser.real.geolocation.heading)) < 30 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['heading'], expected.geolocation.heading['accuracy']) - else: - # Should be spoofed value. - assert position['heading'] == expected.geolocation.heading['value'] - - -## Test position's latitude in decimal degrees. -def test_latitude(browser, position, expected): - if expected.geolocation.latitude['value'] == 'REAL VALUE': - if position['latitude'] == "null": - # If current value is null, real value has to be null too. - assert position['latitude'] == browser.real.geolocation.latitude - else: - if expected.geolocation.latitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 1 degrees is tolerated. - assert abs(float(position['latitude']) - float(browser.real.geolocation.latitude)) < 1 - else: - real_latitude = float(browser.real.geolocation.latitude) - spoofed_latitude = float(position['latitude']) - max_allowed_deviation = expected.geolocation.latitude['accuracy'] - assert abs(real_latitude - spoofed_latitude) < max_allowed_deviation - else: - # Should be spoofed value. - assert position['latitude'] == expected.geolocation.latitude['value'] - - -## Test position's longitude in decimal degrees. -def test_longitude(browser, position, expected): - if expected.geolocation.longitude['value'] == 'REAL VALUE': - if position['longitude'] == "null": - # If current value is null, real value has to be null too. - assert position['longitude'] == browser.real.geolocation.longitude - else: - if expected.geolocation.longitude['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 1 degrees is tolerated. - assert abs(float(position['longitude']) - float(browser.real.geolocation.longitude)) < 1 - else: - real_longitude = float(browser.real.geolocation.longitude) - spoofed_longitude = float(position['longitude']) - max_allowed_deviation = expected.geolocation.longitude['accuracy'] - assert abs(real_longitude - spoofed_longitude) < max_allowed_deviation - else: - # Should be spoofed value. - assert position['longitude'] == expected.geolocation.longitude['value'] - - -## Test speed (velocity) of the device in meters per second. This value can be null. -def test_speed(browser, position, expected): - if expected.geolocation.speed['value'] == 'REAL VALUE': - if position['speed'] == "null": - # If current value is null, real value has to be null too. - assert position['speed'] == browser.real.geolocation.speed - else: - if expected.geolocation.speed['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal. - # A deviation of less than 5 meters per second is tolerated. - assert abs(float(position['speed']) - float(browser.real.geolocation.speed)) < 5 - else: - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['speed'], expected.geolocation.speed['accuracy']) - else: - # Should be spoofed value. - assert position['speed'] == expected.geolocation.speed['value'] - - -## Test timestamp. -def test_timestamp(position, expected): - if expected.geolocation.timestamp['value'] == 'REAL VALUE': - if expected.geolocation.timestamp['accuracy'] == 'EXACTLY': - # Values do not have to be strictly equal because executing command takes some time. - # A deviation of less than 2 seconds is tolerated. - assert abs(time() - int(position['timestamp'])/1000) < 2 - else: - timestamp_accuracy = expected.geolocation.timestamp['accuracy']*1000 - # Should be rounded real value in accuracy. - assert is_in_accuracy(position['timestamp'], timestamp_accuracy) - else: - # Should be spoofed value. - assert position['timestamp'] == expected.geolocation.timestamp['value'] diff --git a/tests/integration_tests/testing/tests_definition/test_14_gps.py b/tests/integration_tests/testing/tests_definition/test_14_gps.py new file mode 100644 index 0000000..91243fb --- /dev/null +++ b/tests/integration_tests/testing/tests_definition/test_14_gps.py @@ -0,0 +1,217 @@ +# +# JShelter is a browser extension which increases level +# of security, anonymity and privacy of the user while browsing the +# internet. +# +# Copyright (C) 2021 Martin Bednar +# +# 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 . +# + +import pytest +from time import time + +from values_getters import get_position +from math_operations import is_in_accuracy, calc_distance + +## Setup method - it is run before gps tests execution starts. +# +# This setup method initialize variable position that contains current data about position and +# this variable is provided to gps tests and values in position variable are compared with expected values. +@pytest.fixture(scope='module', autouse=True) +def position(browser): + position = { + 'accuracy' : "null", + 'altitude' : "null", + 'altitudeaccurac' : "null", + 'heading' : "null", + 'latitude' : "null", + 'longitude' : "null", + 'speed' : "null", + 'timestamp' : "null" + } + try: + position = get_position(browser.driver) + except: + print("\nCan not read GPS data.") + return position + + +## Test accuracy of the latitude and longitude properties in meters. +def test_accuracy(browser, position, expected): + if expected.geolocation.accuracy['value'] == 'REAL VALUE': + if position['accuracy'] == "null": + # If current value is null, real value has to be null too. + assert position['accuracy'] == browser.real.geolocation.accuracy + else: + if expected.geolocation.accuracy['accuracy'] == 'EXACTLY': + # x is real position (position returned without JShelter) + # y should be real position too (position returned with JShelter level 0) + # + # It is clear that x and y will not be exact same values. This is due to the netural GPS inaccuracy. + # A small difference is tolerated. + # x.accuracy and y.accuracy will be probably different. + # But distance between x and y should be less than (x.accuracy + y.accuracy). + assert calc_distance(float(browser.real.geolocation.latitude), + float(browser.real.geolocation.longitude), + float(position['latitude']), + float(position['longitude'])) < (float(browser.real.geolocation.accuracy) + float(position['accuracy'])) + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['accuracy'], expected.geolocation.accuracy['accuracy']) + else: + # Should be spoofed value. + assert position['accuracy'] == expected.geolocation.accuracy['value'] + + +## Test position's altitude in meters, relative to sea level. +def test_altitude(browser, position, expected): + if expected.geolocation.altitude['value'] == 'REAL VALUE': + if position['altitude'] == "null": + # If current value is null, real value has to be null too. + assert position['altitude'] == browser.real.geolocation.altitude + else: + if expected.geolocation.altitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 10 meters is tolerated. + assert abs(float(position['altitude']) - float(browser.real.geolocation.altitude)) < 10 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['altitude'], expected.geolocation.altitude['accuracy']) + else: + # Should be spoofed value. + assert position['altitude'] == expected.geolocation.altitude['value'] + + +## Test accuracy of the altitude property in meters. +def test_altitudeaccurac(browser, position, expected): + if expected.geolocation.altitudeAccurac['value'] == 'REAL VALUE': + if position['altitudeaccurac'] == "null": + # If current value is null, real value has to be null too. + assert position['altitudeaccurac'] == browser.real.geolocation.altitudeAccurac + else: + if expected.geolocation.altitudeAccurac['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 10 meters is tolerated. + assert abs(float(position['altitudeaccurac']) - float(browser.real.geolocation.altitudeAccurac)) < 10 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['altitudeaccurac'], + expected.geolocation.altitudeAccurac['accuracy']) + else: + # Should be spoofed value. + assert position['altitudeaccurac'] == expected.geolocation.altitudeAccurac['value'] + + +## Test heading. +# +# Heading is the direction in which the device is traveling. This value, specified in degrees, +# indicates how far off from heading true north the device is. 0 degrees represents true north, +# and the direction is determined clockwise (east is 90 degrees and west is 270 degrees). +# If speed is 0, heading is NaN. If the device is unable to provide heading information, this value is null +def test_heading(browser, position, expected): + if expected.geolocation.heading['value'] == 'REAL VALUE': + if position['heading'] == "null": + # If current value is null, real value has to be null too. + assert position['heading'] == browser.real.geolocation.heading + else: + if expected.geolocation.heading['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 30 degrees is tolerated. + assert abs(float(position['heading']) - float(browser.real.geolocation.heading)) < 30 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['heading'], expected.geolocation.heading['accuracy']) + else: + # Should be spoofed value. + assert position['heading'] == expected.geolocation.heading['value'] + + +## Test position's latitude in decimal degrees. +def test_latitude(browser, position, expected): + if expected.geolocation.latitude['value'] == 'REAL VALUE': + if position['latitude'] == "null": + # If current value is null, real value has to be null too. + assert position['latitude'] == browser.real.geolocation.latitude + else: + if expected.geolocation.latitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 1 degrees is tolerated. + assert abs(float(position['latitude']) - float(browser.real.geolocation.latitude)) < 1 + else: + real_latitude = float(browser.real.geolocation.latitude) + spoofed_latitude = float(position['latitude']) + max_allowed_deviation = expected.geolocation.latitude['accuracy'] + assert abs(real_latitude - spoofed_latitude) < max_allowed_deviation + else: + # Should be spoofed value. + assert position['latitude'] == expected.geolocation.latitude['value'] + + +## Test position's longitude in decimal degrees. +def test_longitude(browser, position, expected): + if expected.geolocation.longitude['value'] == 'REAL VALUE': + if position['longitude'] == "null": + # If current value is null, real value has to be null too. + assert position['longitude'] == browser.real.geolocation.longitude + else: + if expected.geolocation.longitude['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 1 degrees is tolerated. + assert abs(float(position['longitude']) - float(browser.real.geolocation.longitude)) < 1 + else: + real_longitude = float(browser.real.geolocation.longitude) + spoofed_longitude = float(position['longitude']) + max_allowed_deviation = expected.geolocation.longitude['accuracy'] + assert abs(real_longitude - spoofed_longitude) < max_allowed_deviation + else: + # Should be spoofed value. + assert position['longitude'] == expected.geolocation.longitude['value'] + + +## Test speed (velocity) of the device in meters per second. This value can be null. +def test_speed(browser, position, expected): + if expected.geolocation.speed['value'] == 'REAL VALUE': + if position['speed'] == "null": + # If current value is null, real value has to be null too. + assert position['speed'] == browser.real.geolocation.speed + else: + if expected.geolocation.speed['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal. + # A deviation of less than 5 meters per second is tolerated. + assert abs(float(position['speed']) - float(browser.real.geolocation.speed)) < 5 + else: + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['speed'], expected.geolocation.speed['accuracy']) + else: + # Should be spoofed value. + assert position['speed'] == expected.geolocation.speed['value'] + + +## Test timestamp. +def test_timestamp(position, expected): + if expected.geolocation.timestamp['value'] == 'REAL VALUE': + if expected.geolocation.timestamp['accuracy'] == 'EXACTLY': + # Values do not have to be strictly equal because executing command takes some time. + # A deviation of less than 2 seconds is tolerated. + assert abs(time() - int(position['timestamp'])/1000) < 2 + else: + timestamp_accuracy = expected.geolocation.timestamp['accuracy']*1000 + # Should be rounded real value in accuracy. + assert is_in_accuracy(position['timestamp'], timestamp_accuracy) + else: + # Should be spoofed value. + assert position['timestamp'] == expected.geolocation.timestamp['value'] From dd7f783fa1f1ea452bd75a0b5c9bb17dbf98c12a Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:01:41 +0000 Subject: [PATCH 37/38] Integration tests: Rename JSR to JShelter on the Chrome Options page. --- diff --git a/tests/integration_tests/testing/web_browser.py b/tests/integration_tests/testing/web_browser.py index b96e5de..812723e 100644 --- a/tests/integration_tests/testing/web_browser.py +++ b/tests/integration_tests/testing/web_browser.py @@ -95,10 +95,11 @@ class Browser: if self.type == BrowserType.CHROME: self.driver.get('chrome://system/') WebDriverWait(self.driver, 10).until( - ec.presence_of_element_located((By.ID, 'extensions-value-btn')) + ec.presence_of_element_located((By.ID, 'expandAll')) ) - for elem in self.driver.find_element_by_id('extensions-value').text.splitlines(): - if 'JavaScript Restrictor' in elem: + self.driver.find_element(By.ID, 'expandAll').click() + for elem in self.driver.find_element(By.ID, 'extensions-value').text.splitlines(): + if 'JShelter' in elem: self._jsr_options_page = "chrome-extension://" + elem.split(':')[0][:-1] + "/options.html" ## Create new browser of given type (Chrome, Firefox). From e9edd17f9f0f789db7f1c1a14cb0df8830282aeb Mon Sep 17 00:00:00 2001 From: martinbednar Date: Mar 07 2022 13:02:00 +0000 Subject: [PATCH 38/38] Integration tests: Ignore the NBS switch test in Chrome. Not able to test NBS switch in Google Chrome. Can not show popup.html in Chrome. Popup.html is not accesible and testable. --- diff --git a/tests/integration_tests/testing/tests_definition/test_04_NBS_setting.py b/tests/integration_tests/testing/tests_definition/test_04_NBS_setting.py index 691e7c5..e54227d 100644 --- a/tests/integration_tests/testing/tests_definition/test_04_NBS_setting.py +++ b/tests/integration_tests/testing/tests_definition/test_04_NBS_setting.py @@ -24,6 +24,7 @@ import pytest from selenium.webdriver.common.by import By from time import sleep +from web_browser_type import BrowserType def switch_NBS_setting(browser): @@ -42,6 +43,11 @@ def get_NBS_setting(browser): ## Test turnning NBS off in popup. ## Sleep 0.5 second to changes take effect. def test_switching_NBS(browser): + if browser.type == BrowserType.CHROME: + # Not able to test NBS switch in Google Chrome. + # Can not show popup.html in Chrome. Popup.html is not accesible and testable. + assert True + return() NBS_setting_values = ['"ON"', '"OFF"'] original_setting = get_NBS_setting(browser)