summaryrefslogtreecommitdiffstats
path: root/browser/components/resistfingerprinting/test/mochitest
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/resistfingerprinting/test/mochitest')
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/.eslintrc.js7
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/decode_error.mp4bin0 -> 344124 bytes
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/file_animation_api.html104
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/mochitest.ini29
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_animation_api.html78
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_bug1354633_media_error.html53
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_bug1382499_touch_api.html70
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_bug863246_resource_uri.html43
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_device_sensor_event.html50
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_geolocation.html68
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info.html23
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info_iframe.html45
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_iframe.html18
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_keyboard_event.html61
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_pointer_event.html242
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/test_speech_synthesis.html105
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/worker_child.js28
-rw-r--r--browser/components/resistfingerprinting/test/mochitest/worker_grandchild.js10
18 files changed, 1034 insertions, 0 deletions
diff --git a/browser/components/resistfingerprinting/test/mochitest/.eslintrc.js b/browser/components/resistfingerprinting/test/mochitest/.eslintrc.js
new file mode 100644
index 0000000000..16ee78885f
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ rules: {
+ "no-eval": "off",
+ },
+};
diff --git a/browser/components/resistfingerprinting/test/mochitest/decode_error.mp4 b/browser/components/resistfingerprinting/test/mochitest/decode_error.mp4
new file mode 100644
index 0000000000..ee72e2dd75
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/decode_error.mp4
Binary files differ
diff --git a/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html b/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html
new file mode 100644
index 0000000000..376fddf343
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1382545</title>
+<script>
+ function waitForCondition(aCond, aCallback, aErrorMsg) {
+ var tries = 0;
+ var interval = setInterval(() => {
+ if (tries >= 30) {
+ opener.ok(false, aErrorMsg);
+ moveOn();
+ return;
+ }
+ var conditionPassed;
+ try {
+ conditionPassed = aCond();
+ } catch (e) {
+ opener.ok(false, `${e}\n${e.stack}`);
+ conditionPassed = false;
+ }
+ if (conditionPassed) {
+ moveOn();
+ }
+ tries++;
+ }, 100);
+ var moveOn = () => { clearInterval(interval); aCallback(); };
+ }
+
+ function runTest() {
+ let expectedPrecision = opener.expectedPrecision / 1000;
+ let isRounded = (x) => {
+ let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision);
+ // First we do the perfectly normal check that should work just fine
+ if (rounded === x || x === 0)
+ return true;
+
+ // When we're diving by non-whole numbers, we may not get perfect
+ // multiplication/division because of floating points.
+ // When dealing with ms since epoch, a double's precision is on the order
+ // of 1/5 of a microsecond, so we use a value a little higher than that as
+ // our epsilon.
+ // To be clear, this error is introduced in our re-calculation of 'rounded'
+ // above in JavaScript.
+ if (Math.abs(rounded - x + expectedPrecision) < .0005) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0005) {
+ return true;
+ }
+
+ // Then we handle the case where you're sub-millisecond and the timer is not
+ // We check that the timer is not sub-millisecond by assuming it is not if it
+ // returns an even number of milliseconds
+ if (expectedPrecision < 1 && Math.round(x) == x) {
+ if (Math.round(rounded) == x) {
+ return true;
+ }
+ }
+
+ // We are temporarily disabling this extra debugging failure because we expect to return false in some instances
+ // When we correct things we will re-enable it for debugging assistance
+ // opener.ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x +
+ // " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) +
+ // " Fuzzy 2: " + Math.abs(rounded - x));
+
+ return false;
+ };
+ const testDiv = document.getElementById("testDiv");
+ const animation = testDiv.animate({ opacity: [0, 1] }, 100000);
+ animation.play();
+
+ waitForCondition(
+ () => animation.currentTime > 100,
+ () => {
+ // We have disabled Time Precision Reduction for CSS Animations, so we expect those tests to fail.
+ // If we are testing that preference, we accept either rounded or not rounded values as A-OK.
+ var maybeAcceptEverything = function(value) {
+ if (opener.prefName.includes("privacy.reduceTimerPrecision") &&
+ !opener.prefName.includes("privacy.resistFingerprinting"))
+ return true;
+ return value;
+ };
+
+ opener.ok(maybeAcceptEverything(isRounded(animation.startTime)),
+ "pref: " + opener.prefName + " - animation.startTime with precision " + expectedPrecision + " is not rounded: " + animation.startTime);
+ opener.ok(maybeAcceptEverything(isRounded(animation.currentTime)),
+ "pref: " + opener.prefName + " - animation.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.currentTime);
+ opener.ok(maybeAcceptEverything(isRounded(animation.timeline.currentTime)),
+ "pref: " + opener.prefName + " - animation.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.timeline.currentTime);
+ if (document.timeline) {
+ opener.ok(maybeAcceptEverything(isRounded(document.timeline.currentTime)),
+ "pref: " + opener.prefName + " - document.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + document.timeline.currentTime);
+ }
+ opener.done();
+ window.close();
+ },
+ "animation failed to start");
+ }
+</script>
+</head>
+<body onload="runTest();">
+<div id="testDiv">test</div>
+</body>
+</html>
diff --git a/browser/components/resistfingerprinting/test/mochitest/mochitest.ini b/browser/components/resistfingerprinting/test/mochitest/mochitest.ini
new file mode 100644
index 0000000000..2429f5e4dc
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/mochitest.ini
@@ -0,0 +1,29 @@
+[DEFAULT]
+skip-if = toolkit == 'android' # bug 1730213
+tags = resistfingerprinting
+
+support-files =
+ file_animation_api.html
+ worker_child.js
+ worker_grandchild.js
+ !/dom/tests/mochitest/geolocation/network_geolocation.sjs
+
+[test_animation_api.html]
+[test_bug1354633_media_error.html]
+support-files = decode_error.mp4
+[test_bug1382499_touch_api.html]
+[test_bug863246_resource_uri.html]
+[test_device_sensor_event.html]
+[test_geolocation.html]
+scheme = https
+fail-if = xorigin
+[test_hide_gamepad_info.html]
+scheme = https
+support-files = test_hide_gamepad_info_iframe.html
+[test_iframe.html]
+[test_keyboard_event.html]
+[test_pointer_event.html]
+ support-files =
+ ../../../../../dom/events/test/pointerevents/mochitest_support_external.js
+[test_speech_synthesis.html]
+skip-if = verify
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_animation_api.html b/browser/components/resistfingerprinting/test/mochitest/test_animation_api.html
new file mode 100644
index 0000000000..e754eeac7d
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_animation_api.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1382545
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1382545</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1382545 */
+ SimpleTest.waitForExplicitFinish();
+
+ // Used by file_animation_api.html
+ var prefName = "";
+ var expectedPrecision = 0;
+ var resistFingerprinting = false;
+ var reduceTimerPrecision = false;
+
+ function runTest() {
+ // No matter what we set the precision to, if we're in ResistFingerprinting mode
+ // we use the larger of the precision pref and the constant RFP time-atom
+ if (resistFingerprinting) {
+ const RFP_TIME_ATOM_MS = 16.667;
+ expectedPrecision = Math.max(1000*RFP_TIME_ATOM_MS, expectedPrecision);
+ }
+ window.open("file_animation_api.html");
+ }
+
+ function setupTest(rfp, rtp, ep) {
+ // Set globals
+ expectedPrecision = ep;
+ resistFingerprinting = rfp;
+ reduceTimerPrecision = rtp;
+ prefName = "";
+ prefName += resistFingerprinting ? "privacy.resistFingerprinting " : "";
+ prefName += reduceTimerPrecision ? "privacy.reduceTimerPrecision " : "";
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["dom.animations-api.timelines.enabled", true],
+ ["privacy.resistFingerprinting", resistFingerprinting],
+ ["privacy.reduceTimerPrecision", reduceTimerPrecision],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision],
+ ],
+ }, runTest);
+ }
+
+ var testIndx = 0;
+ var testSequence = [
+ [true, false, 100000],
+ [false, true, 100000],
+ [true, false, 50000],
+ [false, true, 50000],
+ [true, false, 100],
+ [false, true, 100],
+ [true, true, 13],
+ [false, true, 13],
+ ];
+
+ window.onload = () => {
+ setupTest(testSequence[testIndx][0], testSequence[testIndx][1], testSequence[testIndx][2]);
+ };
+
+ function done() {
+ testIndx++;
+ if (testIndx == testSequence.length) {
+ SimpleTest.finish();
+ } else {
+ setupTest(testSequence[testIndx][0], testSequence[testIndx][1], testSequence[testIndx][2]);
+ }
+ }
+ </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_bug1354633_media_error.html b/browser/components/resistfingerprinting/test/mochitest/test_bug1354633_media_error.html
new file mode 100644
index 0000000000..1155ab1778
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_bug1354633_media_error.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+/* global SimpleTest SpecialPowers */
+
+let errorMessageMap = {};
+
+let testPromise = (resistFingerprinting, src, allowlist) => new Promise(resolve => {
+ let video = document.createElement("video");
+ video.src = src;
+ video.controls = "true";
+ video.onerror = () => {
+ let message = video.error.message;
+ if (!resistFingerprinting) {
+ SimpleTest.isnot(message, "", "Message should not be blank");
+ SimpleTest.info(src + ": " + message);
+ errorMessageMap[src] = message;
+ } else if (allowlist) {
+ SimpleTest.is(message, allowlist, "Error message in allowlist: " + allowlist);
+ } else {
+ SimpleTest.is(message, "", "Blank error message: " + errorMessageMap[src]);
+ }
+ resolve();
+ };
+ document.body.appendChild(video);
+});
+
+async function testBody(resistFingerprinting) {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["privacy.resistFingerprinting", resistFingerprinting],
+ ],
+ });
+ await testPromise(
+ resistFingerprinting,
+ "load_error.mp4",
+ "404: Not Found" // allowlist
+ );
+ await testPromise(
+ resistFingerprinting,
+ "decode_error.mp4",
+ false // allowlist
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+document.addEventListener("DOMContentLoaded", async () => {
+ await testBody(false);
+ await testBody(true);
+ SimpleTest.finish();
+});
+</script>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_bug1382499_touch_api.html b/browser/components/resistfingerprinting/test/mochitest/test_bug1382499_touch_api.html
new file mode 100644
index 0000000000..c440d37cf2
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_bug1382499_touch_api.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script>
+/* global SimpleTest SpecialPowers synthesizeTouch */
+
+SimpleTest.waitForExplicitFinish();
+
+function promiseEvent(target, eventName) {
+ return new Promise(resolve => {
+ target.addEventListener(eventName, resolve, {once: true});
+ });
+}
+
+function promiseTouchEvent(target, type, offsetX, offsetY, params) {
+ let touchEventPromise = promiseEvent(target, type);
+ params.type = type;
+ synthesizeTouch(target, offsetX, offsetY, params);
+ return touchEventPromise;
+}
+
+document.addEventListener("DOMContentLoaded", async () => {
+ const target0 = document.getElementById("target0");
+ const touchParams = {force: 1.0, angle: 1.0, rx: 2, ry: 3};
+ await SpecialPowers.pushPrefEnv({set: [["dom.w3c_touch_events.enabled", 1]]});
+
+ for (let seq of [0, 1, 2, 3]) {
+ let resist = false;
+ if (seq == 0) {
+ resist = true;
+ await SpecialPowers.pushPrefEnv({set: [["privacy.resistFingerprinting", true]]});
+ } else if (seq == 1) {
+ await SpecialPowers.pushPrefEnv({set: [["privacy.resistFingerprinting", false]]});
+ } else if (seq == 2) {
+ resist = true;
+ await SpecialPowers.pushPrefEnv({set: [
+ ["privacy.fingerprintingProtection", true],
+ ["privacy.fingerprintingProtection.overrides", "+TouchEvents"]
+ ]});
+ } else {
+ await SpecialPowers.pushPrefEnv({set: [
+ ["privacy.fingerprintingProtection", true],
+ ["privacy.fingerprintingProtection.overrides", "-TouchEvents"]
+ ]});
+ }
+
+ info("starting test with fingerprinting resistance " + (resist ? "on" : "off") + " sequence number " + seq);
+ let touchEvent = await promiseTouchEvent(target0, "touchstart", 5, 5, touchParams);
+ info("touch event received");
+ let touch = touchEvent.touches[0];
+
+ if (resist) {
+ is(touch.screenX, touch.clientX, "touch.screenX should be the same as touch.clientX");
+ is(touch.screenY, touch.clientY, "touch.screenY should be the same as touch.clientY");
+ // radiusX/radiusY may differ from the original rx/ry because of AppUnitsPerCSSPixel and AppUnitsPerDevPixel.
+ // So only check if the values are spoofed.
+ is(touch.radiusX, 0, "touch.radiusX");
+ is(touch.radiusY, 0, "touch.radiusY");
+ }
+ is(touch.force, resist ? 0.0 : touchParams.force, "touch.force");
+ is(touch.rotationAngle, resist ? 0 : touchParams.angle, "touch.rotationAngle");
+ await SpecialPowers.popPrefEnv();
+ }
+
+ SimpleTest.finish();
+});
+</script>
+<div id="target0">target 0</div>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_bug863246_resource_uri.html b/browser/components/resistfingerprinting/test/mochitest/test_bug863246_resource_uri.html
new file mode 100644
index 0000000000..fda1c04200
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_bug863246_resource_uri.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf8">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+/* global SimpleTest SpecialPowers add_task */
+
+function testResourceUri(aTest, aUri, aContentAccessible) {
+ return new Promise((aResolve) => {
+ let link = document.createElement("link");
+ link.rel = "stylesheet";
+ link.onload = () => {
+ SimpleTest.ok(aContentAccessible, aTest);
+ aResolve();
+ };
+ link.onerror = () => {
+ SimpleTest.ok(!aContentAccessible, aTest);
+ aResolve();
+ };
+ link.href = aUri;
+ document.head.appendChild(link);
+ });
+}
+
+add_task(async function() {
+ await testResourceUri(
+ "resource://content-accessible is content-accessible",
+ "resource://content-accessible/viewsource.css",
+ true);
+ await testResourceUri(
+ "resource://gre-resources is not content-accessible",
+ "resource://gre-resources/html.css",
+ false);
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.all_resource_uri_content_accessible", true],
+ ],
+ });
+ await testResourceUri(
+ "security.all_resource_uri_content_accessible = true, resource://gre-resources is now content-accessible",
+ "resource://gre-resources/html.css",
+ true);
+});
+</script>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_device_sensor_event.html b/browser/components/resistfingerprinting/test/mochitest/test_device_sensor_event.html
new file mode 100644
index 0000000000..7ec4dce94f
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_device_sensor_event.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1369319
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1369319</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1369319 */
+ SimpleTest.waitForExplicitFinish();
+ window.onload = () => {
+ SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["device.sensors.test.events", true],
+ ["privacy.resistFingerprinting", true],
+ ],
+ }, doTest);
+ }, window);
+ };
+
+ function doTest() {
+ window.addEventListener("devicemotion", () => {
+ ok(false, "The device motion event should not be fired.");
+ }, {once: true});
+
+ window.addEventListener("TestEvent", () => {
+ // If we receive this event without receiving a 'devicemotion' event, this means
+ // the device sensor event has been blocked correctly.
+ ok(true, "Got the 'TestEvent' event.");
+ SimpleTest.finish();
+ }, {once: true});
+
+ window.dispatchEvent(new CustomEvent("TestEvent"));
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_geolocation.html b/browser/components/resistfingerprinting/test/mochitest/test_geolocation.html
new file mode 100644
index 0000000000..95394ddb56
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_geolocation.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1372069
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1372069</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ const BASE_GEO_URL = "http://mochi.test:8888/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs";
+
+ /** Test for Bug 1372069 */
+ /** Modified for Bug 1441295 */
+ SimpleTest.waitForExplicitFinish();
+ window.onload = () => {
+ SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", true],
+ ["geo.prompt.testing", true],
+ ["geo.prompt.testing.allow", true],
+ ["geo.provider.network.url", BASE_GEO_URL],
+ ],
+ }, doTest_getCurrentPosition);
+ }, window);
+ };
+
+ function doTest_getCurrentPosition() {
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ ok(true, "Success callback is expected to be called");
+ doTest_watchPosition();
+ },
+ (error) => {
+ ok(false, "Should be able to call success callback, Got error. code = " + error.code);
+ doTest_watchPosition();
+ }
+ );
+ }
+
+ function doTest_watchPosition() {
+ let wid = navigator.geolocation.watchPosition(
+ (position) => {
+ ok(true, "Success callback is expected to be called");
+ navigator.geolocation.clearWatch(wid);
+ SimpleTest.finish();
+ },
+ (error) => {
+ ok(false, "Should be able to call success callback, Got error. code = " + error.code);
+ navigator.geolocation.clearWatch(wid);
+ SimpleTest.finish();
+ }
+ );
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info.html b/browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info.html
new file mode 100644
index 0000000000..08fdb0c852
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf8">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+/* global SimpleTest SpecialPowers */
+
+SimpleTest.waitForExplicitFinish();
+document.addEventListener("DOMContentLoaded", function() {
+ SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.gamepad.test.enabled", true],
+ ["privacy.resistFingerprinting", true],
+ ],
+ }, function() {
+ // This test loads in an iframe, to ensure that the navigator instance is
+ // loaded with the correct value of the preference.
+ var iframe = document.createElement("iframe");
+ iframe.allow = "gamepad";
+ iframe.src = "test_hide_gamepad_info_iframe.html";
+ document.body.appendChild(iframe);
+ });
+});
+</script>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info_iframe.html b/browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info_iframe.html
new file mode 100644
index 0000000000..5946e1ce6e
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_hide_gamepad_info_iframe.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset="utf8">
+<!--<script src="/tests/SimpleTest/SimpleTest.js"></script>-->
+<script>
+var SimpleTest = window.parent.SimpleTest;
+
+function forceFail() {
+ SimpleTest.ok(
+ false,
+ "privacy.resistFingerprinting is true, should not receive any gamepad events"
+ );
+}
+
+window.addEventListener("gamepadconnected", forceFail);
+window.addEventListener("gamepaddisconnected", forceFail);
+window.addEventListener("gamepadbuttondown", forceFail);
+
+window.addEventListener("load", async () => {
+ const service = navigator.requestGamepadServiceTest();
+ const buttonIndex = await service.addGamepad(
+ "test gamepad", // id
+ service.standardMapping,
+ service.noHand,
+ 4, // buttons
+ 2,
+ 0,
+ 0,
+ 0
+ );
+
+ // Press a button to make the gamepad visible to the page.
+ await service.newButtonEvent(buttonIndex, 0, true, true);
+
+ const { length } = navigator.getGamepads();
+ SimpleTest.is(
+ length,
+ 0,
+ "privacy.resistFingerprinting is true, navigator.getGamepads() should always return an empty array"
+ );
+
+ // Attempt to force gamepad events to be fired, by simulating gamepad disconnect
+ await service.removeGamepad(buttonIndex);
+ SimpleTest.finish();
+});
+</script>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_iframe.html b/browser/components/resistfingerprinting/test/mochitest/test_iframe.html
new file mode 100644
index 0000000000..f01809b28c
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_iframe.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<body>
+<script>
+ add_task(async function() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", true]],
+ });
+ is(screen.width, window.innerWidth, "Width should be spoofed");
+ is(screen.height, window.innerHeight, "Height should be spoofed");
+ let iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+ is(iframe.contentWindow.screen.width, iframe.contentWindow.innerWidth, "Width should be spoofed in iframe");
+ is(iframe.contentWindow.screen.height, iframe.contentWindow.innerHeight, "Height should be spoofed in iframe");
+ });
+</script>
+</body>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_keyboard_event.html b/browser/components/resistfingerprinting/test/mochitest/test_keyboard_event.html
new file mode 100644
index 0000000000..72f2d29b90
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_keyboard_event.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1222285
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1222285</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1222285 */
+ SimpleTest.waitForExplicitFinish();
+
+ window.onload = () => {
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", true],
+ ],
+ }, doTestForSystemEventGroup);
+ };
+
+ // This test makes sure that system event group will still get real keyboard event.
+ function doTestForSystemEventGroup() {
+ SpecialPowers.addSystemEventListener(document, "keydown",
+ function eventHandler(aEvent) {
+ SpecialPowers.removeSystemEventListener(document,
+ "keydown", eventHandler, true);
+
+ is(aEvent.code, "Minus", "The system group event should get real code.");
+ is(aEvent.keyCode, 63, "The system group event should get real keyCode.");
+
+ doTestModifiersForSystemEventGroup();
+ }, true);
+
+ // Send key event to the system group.
+ synthesizeKey("\u00DF", {code: "Minus", keyCode: 63});
+ }
+
+ // Test that will system group event still get suppressed modifier keys
+ function doTestModifiersForSystemEventGroup() {
+ SpecialPowers.addSystemEventListener(document, "keydown",
+ function eventHandler(aEvent) {
+ SpecialPowers.removeSystemEventListener(document,
+ "keydown", eventHandler, true);
+ is(aEvent.key, "Alt", "The system group event get the suppressed keyboard event.");
+
+ SimpleTest.finish();
+ }, true);
+
+ // Send key event to the system group.
+ synthesizeKey("KEY_Alt", {altKey: true});
+ }
+
+ </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_pointer_event.html b/browser/components/resistfingerprinting/test/mochitest/test_pointer_event.html
new file mode 100644
index 0000000000..5b8271274e
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_pointer_event.html
@@ -0,0 +1,242 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1363508
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Pointer Events spoofing</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="target0" style="width: 50px; height: 50px; background: green"></div>
+<div id="target1" style="width: 50px; height: 50px; background: black"></div>
+<script type="application/javascript">
+
+ /** Test for Bug 1363508 */
+ SimpleTest.waitForExplicitFinish();
+
+ var target0 = window.document.getElementById("target0");
+ var target1 = window.document.getElementById("target1");
+ var utils = SpecialPowers.Ci.nsIDOMWindowUtils;
+
+ // A helper function to check that whether the pointer is spoofed correctly.
+ function checkPointerEvent(aEvent) {
+ is(aEvent.pointerId, utils.DEFAULT_MOUSE_POINTER_ID,
+ "The spoofed pointer event should always have the mouse pointer id.");
+ is(aEvent.width, 1, "The spoofed pointer event should always have width as 1.");
+ is(aEvent.height, 1, "The spoofed pointer event should always have width as 1.");
+ if (aEvent.buttons === 0) {
+ is(aEvent.pressure, 0.0,
+ "The spoofed pointer event should have pressure as 0.0 if it is not in a active buttons state.");
+ } else {
+ is(aEvent.pressure, 0.5,
+ "The spoofed pointer event should have pressure as 0.5 if it is in a active buttons state.");
+ }
+ is(aEvent.tangentialPressure, 0, "The spoofed pointer event should always have tangentialPressure as 0.");
+ is(aEvent.tiltX, 0, "The spoofed pointer event should always have tiltX as 0.");
+ is(aEvent.tiltY, 0, "The spoofed pointer event should always have tiltY as 0.");
+ is(aEvent.twist, 0, "The spoofed pointer event should always have twist as 0.");
+ is(aEvent.pointerType, "mouse", "The spoofed pointer event should always has mouse pointerType.");
+ is(aEvent.isPrimary, true, "The spoofed pointer event should only receive primary pointer events.");
+ }
+
+ // A helper function to create a promise for waiting the event.
+ function promiseForEvent(aEventType, aCheckFunc) {
+ return new Promise(resolve => {
+ target0.addEventListener(aEventType, (event) => {
+ is(event.type, aEventType, "receive " + event.type + " on target0");
+ aCheckFunc(event);
+ resolve();
+ }, { once: true });
+ });
+ }
+
+ // A test for pointer events from touch interface.
+ async function doTestForTouchPointerEvent() {
+ let eventPromises = [
+ promiseForEvent("pointerover", checkPointerEvent),
+ promiseForEvent("pointerenter", checkPointerEvent),
+ promiseForEvent("pointerdown", checkPointerEvent),
+ promiseForEvent("pointermove", checkPointerEvent),
+ promiseForEvent("pointerup", checkPointerEvent),
+ promiseForEvent("pointerout", checkPointerEvent),
+ promiseForEvent("pointerleave", checkPointerEvent),
+ ];
+
+ synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
+ synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 });
+
+ await Promise.all(eventPromises);
+ }
+
+ // A test for pointercancel event.
+ async function doTestForTouchPointerCancelEvent() {
+ let eventPromises = [
+ promiseForEvent("pointerover", checkPointerEvent),
+ promiseForEvent("pointerenter", checkPointerEvent),
+ promiseForEvent("pointerdown", checkPointerEvent),
+ promiseForEvent("pointermove", checkPointerEvent),
+ promiseForEvent("pointercancel", checkPointerEvent),
+ promiseForEvent("pointerout", checkPointerEvent),
+ promiseForEvent("pointerleave", checkPointerEvent),
+ ];
+
+ synthesizeTouch(target0, 5, 5, { type: "touchstart" });
+ synthesizeTouch(target0, 6, 6, { type: "touchmove" });
+ synthesizeTouch(target0, 6, 6, { type: "touchcancel" });
+
+ await Promise.all(eventPromises);
+ }
+
+ // A test for pointer events from pen interface.
+ async function doTestForPenPointerEvent() {
+ let eventPromises = [
+ promiseForEvent("pointerover", checkPointerEvent),
+ promiseForEvent("pointerenter", checkPointerEvent),
+ promiseForEvent("pointerdown", checkPointerEvent),
+ promiseForEvent("pointermove", checkPointerEvent),
+ promiseForEvent("pointerup", checkPointerEvent),
+ promiseForEvent("pointerout", checkPointerEvent),
+ promiseForEvent("pointerleave", checkPointerEvent),
+ ];
+
+ synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_PEN });
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN });
+ synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_PEN });
+ synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN });
+
+ await Promise.all(eventPromises);
+ }
+
+ // A test for gotpointercapture and lostpointercapture events.
+ // We would also test releasePointerCapture for only accepting spoofed pointer
+ // Id here.
+ async function doTestForPointerCapture() {
+ // We test for both mouse and touch to see whether the capture events are
+ // filed properly. We don't check pen here since it won't file capture
+ // events.
+ let inputSources = [ MouseEvent.MOZ_SOURCE_MOUSE,
+ MouseEvent.MOZ_SOURCE_TOUCH ];
+
+ for (let inputSource of inputSources) {
+ function eventHandler(event) {
+ checkPointerEvent(event);
+ if (event.type === "pointerdown") {
+ target0.setPointerCapture(event.pointerId);
+ } else if (event.type === "pointermove") {
+ if (inputSource === MouseEvent.MOZ_SOURCE_TOUCH) {
+ try {
+ target0.releasePointerCapture(utils.DEFAULT_TOUCH_POINTER_ID);
+ ok(false, "The releasePointerCapture should fail here, but it is not.");
+ } catch (e) {
+ ok(true, "The releasePointerCapture fails properly.");
+ }
+ }
+ target0.releasePointerCapture(event.pointerId);
+ }
+ }
+
+ let eventPromises = [
+ promiseForEvent("pointerover", eventHandler),
+ promiseForEvent("pointerenter", eventHandler),
+ promiseForEvent("pointerdown", eventHandler),
+ promiseForEvent("gotpointercapture", eventHandler),
+ promiseForEvent("pointermove", eventHandler),
+ promiseForEvent("lostpointercapture", eventHandler),
+ promiseForEvent("pointerup", eventHandler),
+ promiseForEvent("pointerout", eventHandler),
+ promiseForEvent("pointerleave", eventHandler),
+ ];
+
+ synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource });
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource });
+ synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource });
+ synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource });
+
+ await Promise.all(eventPromises);
+ }
+ }
+
+ // A test for setPointerCapture() for only accepting spoofed pointer id.
+ async function doTestForSetPointerCapture() {
+ function eventHandler(event) {
+ checkPointerEvent(event);
+ if (event.type === "pointerdown") {
+ try {
+ target0.setPointerCapture(utils.DEFAULT_TOUCH_POINTER_ID);
+ ok(false, "The setPointerCapture should fail here, but it is not.");
+ } catch (e) {
+ ok(true, "The setPointerCapture fails properly.");
+ }
+ }
+ }
+
+ let eventPromises = [
+ promiseForEvent("pointerover", eventHandler),
+ promiseForEvent("pointerenter", eventHandler),
+ promiseForEvent("pointerdown", eventHandler),
+ promiseForEvent("pointermove", eventHandler),
+ promiseForEvent("pointerup", eventHandler),
+ promiseForEvent("pointerout", eventHandler),
+ promiseForEvent("pointerleave", eventHandler),
+ ];
+
+ synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
+ synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH });
+
+ await Promise.all(eventPromises);
+ }
+
+ // A test for assuring that script generated events won't be spoofed.
+ function doTestNoSpoofingForScriptGeneratedEvent() {
+ return new Promise(resolve => {
+ // Generate a custom pointer event by script.
+ let pointerEventCustom = new PointerEvent("pointerover", {
+ pointerId: utils.DEFAULT_TOUCH_POINTER_ID,
+ pointerType: "touch",
+ width: 5,
+ height: 5,
+ pressure: 0.75,
+ tangentialPressure: 0.5,
+ isPrimary: false,
+ });
+
+ target0.addEventListener("pointerover", (event) => {
+ // Check that script generated event is not spoofed.
+ is(event.pointerType, "touch", "The pointerEvent.pointerType is not spoofed.");
+ is(event.width, 5, "The pointerEvent.width is not spoofed.");
+ is(event.height, 5, "The pointerEvent.height is not spoofed.");
+ is(event.pressure, 0.75, "The pointerEvent.pressure is not spoofed.");
+ is(event.tangentialPressure, 0.5, "The pointerEvent.tangentialPressure is not spoofed.");
+ is(event.isPrimary, false, "The pointerEvent.isPrimary is not spoofed.");
+ resolve();
+ }, { once: true });
+
+ target0.dispatchEvent(pointerEventCustom);
+ });
+ }
+
+ async function doTests() {
+ await doTestForTouchPointerEvent();
+ await doTestForTouchPointerCancelEvent();
+ await doTestForPenPointerEvent();
+ await doTestForPointerCapture();
+ await doTestForSetPointerCapture();
+ await doTestNoSpoofingForScriptGeneratedEvent();
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["privacy.resistFingerprinting", true]]},
+ doTests);
+ });
+
+</script>
+</body>
+</html>
diff --git a/browser/components/resistfingerprinting/test/mochitest/test_speech_synthesis.html b/browser/components/resistfingerprinting/test/mochitest/test_speech_synthesis.html
new file mode 100644
index 0000000000..a1778a0a0d
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/test_speech_synthesis.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1333641
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1333641</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1333641 */
+ SimpleTest.waitForExplicitFinish();
+ window.onload = setupSpeechSynthesis;
+
+ // This function setup the speechSynthesis and flip 'privacy.resistFingerprinting'
+ // after it has been setup correctly.
+ function setupSpeechSynthesis() {
+ window.speechSynthesis.addEventListener("voiceschanged", () => {
+ isnot(window.speechSynthesis.getVoices().length, 0, "Voices added");
+ SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", true]],
+ }, doGetVoicesTest);
+ }, window);
+ }, {once: true});
+
+ is(window.speechSynthesis.getVoices().length, 0, "No voices added initially");
+ }
+
+ function doGetVoicesTest() {
+ is(window.speechSynthesis.getVoices().length, 0,
+ "There should be no voices after fingerprinting resistance is enabled.");
+ doVoiceschangedEventTest();
+ }
+
+ function doVoiceschangedEventTest() {
+ window.speechSynthesis.addEventListener("voiceschanged", () => {
+ ok(false, "The voiceschanged event should not be fired.");
+ doSpeakTestAsync();
+ }, {once: true});
+
+ window.addEventListener("TestEvent", () => {
+ // If we receive this event without receiving a 'voiceschanged' event, this means
+ // the voiceschanged event has been blocked correctly.
+ ok(true, "Got the 'TestEvent' event.");
+ doSpeakTestAsync();
+ }, {once: true});
+
+ // Notify 'synth-voices-changed' for triggering the voiceschanged event.
+ SpecialPowers.Services.obs.notifyObservers(null, "synth-voices-changed");
+ window.dispatchEvent(new CustomEvent("TestEvent"));
+ }
+
+ // This tests Speak() and its asynchronousness.
+ function doSpeakTestAsync() {
+ // For non-e10s, this test will always fail since the event will be triggered immediately
+ // after speak() is called. So, new added events after speak() won't be called. We skip
+ // this test if it is non-e10s.
+ if (SpecialPowers.Services.appinfo.browserTabsRemoteAutostart) {
+ let utterance = new window.SpeechSynthesisUtterance("Hello, world!");
+ window.speechSynthesis.speak(utterance);
+
+ utterance.addEventListener("start", () => {
+ ok(false, "speechSynthesis should not start speaking if fingerprinting resistance is enabled.");
+ doSpeakTestSync();
+ }, {once: true});
+
+ utterance.addEventListener("error", () => {
+ ok(true, "speechSynthesis.speak should fail if fingerprinting resistance is enabled.");
+ doSpeakTestSync();
+ }, {once: true});
+ } else {
+ doSpeakTestSync();
+ }
+ }
+
+ // This tests Speak() and its synchronousness.
+ function doSpeakTestSync() {
+ let utterance = new window.SpeechSynthesisUtterance("Hello, world!");
+ utterance.addEventListener("start", () => {
+ ok(false, "speechSynthesis should not start speaking if fingerprinting resistance is enabled.");
+ SimpleTest.finish();
+ }, {once: true});
+
+ utterance.addEventListener("error", () => {
+ ok(true, "speechSynthesis.speak should fail if fingerprinting resistance is enabled.");
+ SimpleTest.finish();
+ }, {once: true});
+
+ window.speechSynthesis.speak(utterance);
+ }
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/browser/components/resistfingerprinting/test/mochitest/worker_child.js b/browser/components/resistfingerprinting/test/mochitest/worker_child.js
new file mode 100644
index 0000000000..fa340fc652
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/worker_child.js
@@ -0,0 +1,28 @@
+let timeStampCodes;
+let worker = new Worker("worker_grandchild.js");
+
+function listenToParent(event) {
+ self.removeEventListener("message", listenToParent);
+ timeStampCodes = event.data;
+
+ let timeStamps = [];
+ for (let timeStampCode of timeStampCodes) {
+ timeStamps.push(eval(timeStampCode));
+ }
+ // Send the timeStamps to the parent.
+ postMessage(timeStamps);
+
+ // Tell the grandchild to start.
+ worker.postMessage(timeStampCodes);
+}
+
+// The worker grandchild will send results back.
+function listenToChild(event) {
+ worker.removeEventListener("message", listenToChild);
+ // Pass the results to the parent.
+ postMessage(event.data);
+ worker.terminate();
+}
+
+worker.addEventListener("message", listenToChild);
+self.addEventListener("message", listenToParent);
diff --git a/browser/components/resistfingerprinting/test/mochitest/worker_grandchild.js b/browser/components/resistfingerprinting/test/mochitest/worker_grandchild.js
new file mode 100644
index 0000000000..ef9940d7ab
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/mochitest/worker_grandchild.js
@@ -0,0 +1,10 @@
+self.addEventListener("message", function (event) {
+ let timeStampCodes = event.data;
+
+ let timeStamps = [];
+ for (let timeStampCode of timeStampCodes) {
+ timeStamps.push(eval(timeStampCode));
+ }
+ // Send the timeStamps to the parent.
+ postMessage(timeStamps);
+});