--- a/browser/components/resistfingerprinting/test/browser/browser_performanceAPI.js
+++ b/browser/components/resistfingerprinting/test/browser/browser_performanceAPI.js
@@ -25,140 +25,266 @@ const PERFORMANCE_TIMINGS = [
"domInteractive",
"domContentLoadedEventStart",
"domContentLoadedEventEnd",
"domComplete",
"loadEventStart",
"loadEventEnd",
];
+let isRounded = (x, expectedPrecision) => {
+ 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
+ if (Math.abs(rounded - x + expectedPrecision) < .0000001) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0000001) {
+ 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;
+ }
+ }
+
+ 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;
+};
+
add_task(async function runRPTests() {
- await SpecialPowers.pushPrefEnv({"set":
- //Run one set of tests with both true to confirm p.rP overrides p.rTP
- [["privacy.resistFingerprinting", true],
- ["privacy.reduceTimerPrecision", true]]
- });
-
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_dummy.html");
- await ContentTask.spawn(tab.linkedBrowser, PERFORMANCE_TIMINGS, async function(list) {
- const isRounded = x => (Math.floor(x / 100) * 100) === x;
+ let runTests = async function(data) {
+ let timerlist = data.list;
+ let expectedPrecision = data.precision;
+ // eslint beleives that isrounded is available in this scope, but if you
+ // remove the assignment, you will see it is not
+ // eslint-disable-next-line
+ let isRounded = eval(data.isRoundedFunc);
- ok(isRounded(content.performance.timeOrigin), `For resistFingerprinting, performance.timeOrigin is not correctly rounded: ` + content.performance.timeOrigin);
+ ok(isRounded(content.performance.timeOrigin, expectedPrecision), `For resistFingerprinting, performance.timeOrigin is not correctly rounded: ` + content.performance.timeOrigin);
// Check that whether the performance timing API is correctly spoofed.
- for (let time of list) {
+ for (let time of timerlist) {
is(content.performance.timing[time], 0, `For resistFingerprinting, the timing(${time}) is not correctly spoofed.`);
}
// Try to add some entries.
content.performance.mark("Test");
content.performance.mark("Test-End");
content.performance.measure("Test-Measure", "Test", "Test-End");
// Check that no entries for performance.getEntries/getEntriesByType/getEntriesByName.
is(content.performance.getEntries().length, 0, "For resistFingerprinting, there should be no entries for performance.getEntries()");
is(content.performance.getEntriesByType("resource").length, 0, "For resistFingerprinting, there should be no entries for performance.getEntriesByType()");
is(content.performance.getEntriesByName("Test", "mark").length, 0, "For resistFingerprinting, there should be no entries for performance.getEntriesByName()");
+ };
+
+ let expectedPrecision = 100;
+ await SpecialPowers.pushPrefEnv({"set":
+ // Run one set of tests with both true to confirm p.rP overrides p.rTP
+ [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]
});
+ await ContentTask.spawn(tab.linkedBrowser, { list: PERFORMANCE_TIMINGS, precision: expectedPrecision, isRoundedFunc: isRounded.toString() }, runTests);
+
+ expectedPrecision = 13;
+ await SpecialPowers.pushPrefEnv({"set":
+ // Run one set of tests with both true to confirm p.rP overrides p.rTP
+ [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, { list: PERFORMANCE_TIMINGS, precision: expectedPrecision, isRoundedFunc: isRounded.toString() }, runTests);
+
+ expectedPrecision = .13;
+ await SpecialPowers.pushPrefEnv({"set":
+ // Run one set of tests with both true to confirm p.rP overrides p.rTP
+ [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, { list: PERFORMANCE_TIMINGS, precision: expectedPrecision, isRoundedFunc: isRounded.toString() }, runTests);
await BrowserTestUtils.removeTab(tab);
});
add_task(async function runRPTestsForWorker() {
- await SpecialPowers.pushPrefEnv({"set":
- [["privacy.resistFingerprinting", true],
- ["privacy.reduceTimerPrecision", false]]
- });
-
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_dummy.html");
- await ContentTask.spawn(tab.linkedBrowser, null, async function() {
+ let runTest = async function(expectedPrecision) {
await new Promise(resolve => {
let worker = new content.Worker("file_workerPerformance.js");
worker.onmessage = function(e) {
if (e.data.type == "status") {
ok(e.data.status, e.data.msg);
} else if (e.data.type == "finish") {
resolve();
} else {
ok(false, "Unknown message type");
resolve();
}
};
- worker.postMessage({type: "runRPTests"});
+ worker.postMessage({type: "runRPTests", precision: expectedPrecision});
});
+ };
+
+ let expectedPrecision = 100;
+ // Run one set of tests with both true to confirm p.rP overrides p.rTP
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]]
});
+ await ContentTask.spawn(tab.linkedBrowser, expectedPrecision, runTest);
+
+ expectedPrecision = 13;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, expectedPrecision, runTest);
+
+ expectedPrecision = .13;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, expectedPrecision, runTest);
await BrowserTestUtils.removeTab(tab);
});
add_task(async function runRTPTests() {
- await SpecialPowers.pushPrefEnv({"set":
- [["privacy.resistFingerprinting", false],
- ["privacy.reduceTimerPrecision", true]]
- });
-
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_dummy.html");
- await ContentTask.spawn(tab.linkedBrowser, PERFORMANCE_TIMINGS, async function(list) {
- const isRounded = x => (Math.floor(x / 100) * 100) === x;
+ let runTests = async function(data) {
+ let timerlist = data.list;
+ let expectedPrecision = data.precision;
+ // eslint beleives that isrounded is available in this scope, but if you
+ // remove the assignment, you will see it is not
+ // eslint-disable-next-line
+ let isRounded = eval(data.isRoundedFunc);
- ok(isRounded(content.performance.timeOrigin), `For reduceTimerPrecision, performance.timeOrigin is not correctly rounded: ` + content.performance.timeOrigin);
+ ok(isRounded(content.performance.timeOrigin, expectedPrecision), `For reduceTimerPrecision, performance.timeOrigin is not correctly rounded: ` + content.performance.timeOrigin);
// Check that whether the performance timing API is correctly spoofed.
- for (let time of list) {
- ok(isRounded(content.performance.timing[time]), `For reduceTimerPrecision, the timing(${time}) is not correctly rounded.`);
+ for (let time of timerlist) {
+ ok(isRounded(content.performance.timing[time], expectedPrecision), `For reduceTimerPrecision(` + expectedPrecision + `), the timing(${time}) is not correctly rounded: ` + content.performance.timing[time]);
}
// Try to add some entries.
content.performance.mark("Test");
content.performance.mark("Test-End");
content.performance.measure("Test-Measure", "Test", "Test-End");
- // Check that no entries for performance.getEntries/getEntriesByType/getEntriesByName.
+ // Check the entries for performance.getEntries/getEntriesByType/getEntriesByName.
is(content.performance.getEntries().length, 4, "For reduceTimerPrecision, there should be 4 entries for performance.getEntries()");
- for(var i=0; i<4; i++) {
+ for (var i = 0; i < 4; i++) {
let startTime = content.performance.getEntries()[i].startTime;
let duration = content.performance.getEntries()[i].duration;
- ok(isRounded(startTime), "For reduceTimerPrecision, performance.getEntries(" + i.toString() + ").startTime is not rounded: " + startTime.toString());
- ok(isRounded(duration), "For reduceTimerPrecision, performance.getEntries(" + i.toString() + ").duration is not rounded: " + duration.toString());
+ ok(isRounded(startTime, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").startTime is not rounded: " + startTime);
+ ok(isRounded(duration, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").duration is not rounded: " + duration);
}
is(content.performance.getEntriesByType("mark").length, 2, "For reduceTimerPrecision, there should be 2 entries for performance.getEntriesByType()");
is(content.performance.getEntriesByName("Test", "mark").length, 1, "For reduceTimerPrecision, there should be 1 entry for performance.getEntriesByName()");
+ content.performance.clearMarks();
+ content.performance.clearMeasures();
+ content.performance.clearResourceTimings();
+ };
+ let expectedPrecision = 100;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, { list: PERFORMANCE_TIMINGS, precision: expectedPrecision, isRoundedFunc: isRounded.toString() }, runTests);
+
+ expectedPrecision = 13;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]
});
+ await ContentTask.spawn(tab.linkedBrowser, { list: PERFORMANCE_TIMINGS, precision: expectedPrecision, isRoundedFunc: isRounded.toString() }, runTests);
+
+ expectedPrecision = .13;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, { list: PERFORMANCE_TIMINGS, precision: expectedPrecision, isRoundedFunc: isRounded.toString() }, runTests);
await BrowserTestUtils.removeTab(tab);
});
add_task(async function runRTPTestsForWorker() {
- await SpecialPowers.pushPrefEnv({"set":
- [["privacy.resistFingerprinting", false],
- ["privacy.reduceTimerPrecision", true]]
- });
-
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_dummy.html");
- await ContentTask.spawn(tab.linkedBrowser, null, async function() {
+ let runTest = async function(expectedPrecision) {
await new Promise(resolve => {
let worker = new content.Worker("file_workerPerformance.js");
worker.onmessage = function(e) {
if (e.data.type == "status") {
ok(e.data.status, e.data.msg);
} else if (e.data.type == "finish") {
resolve();
} else {
ok(false, "Unknown message type");
resolve();
}
};
- worker.postMessage({type: "runRTPTests"});
+ worker.postMessage({type: "runRTPTests", precision: expectedPrecision});
});
+ };
+
+ let expectedPrecision = 100;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]]
});
+ await ContentTask.spawn(tab.linkedBrowser, expectedPrecision, runTest);
+ expectedPrecision = 13;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, expectedPrecision, runTest);
+
+ expectedPrecision = .13;
+ await SpecialPowers.pushPrefEnv({"set":
+ [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]]
+ });
+ await ContentTask.spawn(tab.linkedBrowser, expectedPrecision, runTest);
await BrowserTestUtils.removeTab(tab);
-});
\ No newline at end of file
+});
--- a/browser/components/resistfingerprinting/test/browser/file_workerPerformance.js
+++ b/browser/components/resistfingerprinting/test/browser/file_workerPerformance.js
@@ -5,57 +5,85 @@ function ok(a, msg) {
function is(a, b, msg) {
ok(a === b, msg);
}
function finish() {
postMessage({type: "finish"});
}
-function runRPTests() {
- const isRounded = x => (Math.floor(x / 100) * 100) === x;
- //ok(isRounded(performance.timeOrigin), `For resistFingerprinting, performance.timeOrigin is not correctly rounded: ` + performance.timeOrigin);
+let isRounded = (x, expectedPrecision) => {
+ 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
+ if (Math.abs(rounded - x + expectedPrecision) < .0000001) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0000001) {
+ 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;
+ }
+ }
+
+ 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;
+};
+
+function runRPTests(expectedPrecision) {
+ ok(isRounded(performance.timeOrigin, expectedPrecision), `In a worker, for resistFingerprinting, performance.timeOrigin is not correctly rounded: ` + performance.timeOrigin);
// Try to add some entries.
performance.mark("Test");
performance.mark("Test-End");
performance.measure("Test-Measure", "Test", "Test-End");
// Check that no entries for performance.getEntries/getEntriesByType/getEntriesByName.
- is(performance.getEntries().length, 0, "For resistFingerprinting: No entries for performance.getEntries() for workers");
- is(performance.getEntriesByType("resource").length, 0, "For resistFingerprinting: No entries for performance.getEntriesByType() for workers");
- is(performance.getEntriesByName("Test", "mark").length, 0, "For resistFingerprinting: No entries for performance.getEntriesByName() for workers");
+ is(performance.getEntries().length, 0, "In a worker, for resistFingerprinting: No entries for performance.getEntries() for workers");
+ is(performance.getEntriesByType("resource").length, 0, "In a worker, for resistFingerprinting: No entries for performance.getEntriesByType() for workers");
+ is(performance.getEntriesByName("Test", "mark").length, 0, "In a worker, for resistFingerprinting: No entries for performance.getEntriesByName() for workers");
finish();
}
-function runRTPTests() {
- const isRounded = x => (Math.floor(x / 100) * 100) === x;
- //ok(isRounded(performance.timeOrigin), `For reduceTimerPrecision, performance.timeOrigin is not correctly rounded: ` + performance.timeOrigin);
+function runRTPTests(expectedPrecision) {
+ ok(isRounded(performance.timeOrigin, expectedPrecision), `In a worker, for reduceTimerPrecision, performance.timeOrigin is not correctly rounded: ` + performance.timeOrigin);
// Try to add some entries.
performance.mark("Test");
performance.mark("Test-End");
performance.measure("Test-Measure", "Test", "Test-End");
- // Check that no entries for performance.getEntries/getEntriesByType/getEntriesByName.
- is(performance.getEntries().length, 3, "For reduceTimerPrecision: Incorrect number of entries for performance.getEntries() for workers: " + performance.getEntries().length);
- for(var i=0; i<3; i++) {
+ // Check the entries in performance.getEntries/getEntriesByType/getEntriesByName.
+ is(performance.getEntries().length, 3, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntries() for workers: " + performance.getEntries().length);
+ for (var i = 0; i < 3; i++) {
let startTime = performance.getEntries()[i].startTime;
let duration = performance.getEntries()[i].duration;
- ok(isRounded(startTime), "For reduceTimerPrecision, performance.getEntries(" + i.toString() + ").startTime is not rounded: " + startTime.toString());
- ok(isRounded(duration), "For reduceTimerPrecision, performance.getEntries(" + i.toString() + ").duration is not rounded: " + duration.toString());
+ ok(isRounded(startTime, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").startTime is not rounded: " + startTime.toString());
+ ok(isRounded(duration, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").duration is not rounded: " + duration.toString());
}
- is(performance.getEntriesByType("mark").length, 2, "For reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByType() for workers: " + performance.getEntriesByType("resource").length);
- is(performance.getEntriesByName("Test", "mark").length, 1, "For reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByName() for workers: " + performance.getEntriesByName("Test", "mark").length);
+ is(performance.getEntriesByType("mark").length, 2, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByType() for workers: " + performance.getEntriesByType("resource").length);
+ is(performance.getEntriesByName("Test", "mark").length, 1, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByName() for workers: " + performance.getEntriesByName("Test", "mark").length);
finish();
}
self.onmessage = function(e) {
if (e.data.type === "runRPTests") {
- runRPTests();
+ runRPTests(e.data.precision);
} else if (e.data.type === "runRTPTests") {
- runRTPTests();
+ runRTPTests(e.data.precision);
} else {
ok(false, "Unknown message type");
}
};
--- a/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html
+++ b/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html
@@ -23,33 +23,62 @@
moveOn();
}
tries++;
}, 100);
var moveOn = () => { clearInterval(interval); aCallback(); };
}
function runTest() {
- const isRounded = x => (Math.floor(x / 100) * 100) === x;
+ 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
+ if (Math.abs(rounded - x + expectedPrecision) < .0000001) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0000001) {
+ 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;
+ }
+ }
+
+ 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,
() => {
opener.ok(isRounded(animation.startTime),
- "pref: " + opener.currentPref + " - animation.startTime is not rounded");
+ "pref: " + opener.currentPref + " - animation.startTime with precision " + expectedPrecision + " is not rounded: " + animation.startTime);
opener.ok(isRounded(animation.currentTime),
- "pref: " + opener.currentPref + " - animation.currentTime is not rounded");
+ "pref: " + opener.currentPref + " - animation.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.currentTime);
opener.ok(isRounded(animation.timeline.currentTime),
- "pref: " + opener.currentPref + " - animation.timeline.currentTime is not rounded");
+ "pref: " + opener.currentPref + " - animation.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.timeline.currentTime);
if (document.timeline) {
opener.ok(isRounded(document.timeline.currentTime),
- "pref: " + opener.currentPref + " - document.timeline.currentTime is not rounded");
+ "pref: " + opener.currentPref + " - document.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + document.timeline.currentTime);
}
opener.done();
window.close();
},
"animation failed to start");
}
</script>
</head>
--- a/browser/components/resistfingerprinting/test/mochitest/test_animation_api.html
+++ b/browser/components/resistfingerprinting/test/mochitest/test_animation_api.html
@@ -9,52 +9,131 @@ https://bugzilla.mozilla.org/show_bug.cg
<script type="application/javascript" 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();
var currentPref = "";
+ var expectedPrecision = 0;
window.onload = () => {
currentPref = "privacy.resistFingerprinting";
+ expectedPrecision = 100000;
SpecialPowers.pushPrefEnv({"set":
[
["privacy.resistFingerprinting", true],
["dom.animations-api.core.enabled", true],
- ["privacy.reduceTimerPrecision", false]
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
]
}, runTest);
};
function runTest() {
window.open("file_animation_api.html");
}
let completed = 0;
- const numTests = 2;
+ const numTests = 8;
function done() {
completed++;
if (completed == numTests) {
SimpleTest.finish();
} else {
nextTest();
}
}
function nextTest() {
+ // ----------------------------------------------
if (completed == 1) {
currentPref = "privacy.reduceTimerPrecision";
+ expectedPrecision = 100000;
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", false],
+ ["dom.animations-api.core.enabled", true],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
+ ]
+ }, runTest);
+ // ----------------------------------------------
+ } else if (completed == 2) {
+ currentPref = "privacy.resistFingerprinting";
+ expectedPrecision = 50000;
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", true],
+ ["dom.animations-api.core.enabled", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
+ ]
+ }, runTest);
+ // ----------------------------------------------
+ } else if (completed == 3) {
+ currentPref = "privacy.reduceTimerPrecision";
+ expectedPrecision = 50000;
SpecialPowers.pushPrefEnv({"set":
[
["privacy.resistFingerprinting", false],
["dom.animations-api.core.enabled", true],
- ["privacy.reduceTimerPrecision", true]
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
+ ]
+ }, runTest);
+ // ----------------------------------------------
+ } else if (completed == 4) {
+ currentPref = "privacy.resistFingerprinting";
+ expectedPrecision = 100;
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", true],
+ ["dom.animations-api.core.enabled", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
]
}, runTest);
+ // ----------------------------------------------
+ } else if (completed == 5) {
+ currentPref = "privacy.reduceTimerPrecision";
+ expectedPrecision = 100;
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", false],
+ ["dom.animations-api.core.enabled", true],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
+ ]
+ }, runTest);
+ // ----------------------------------------------
+ } else if (completed == 6) {
+ currentPref = "privacy.resistFingerprinting";
+ expectedPrecision = 13;
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", true],
+ ["dom.animations-api.core.enabled", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
+ ]
+ }, runTest);
+ // ----------------------------------------------
+ } else if (completed == 7) {
+ currentPref = "privacy.reduceTimerPrecision";
+ expectedPrecision = 13;
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["privacy.resistFingerprinting", false],
+ ["dom.animations-api.core.enabled", true],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
+ ]
+ }, runTest);
+ // ----------------------------------------------
} else {
ok(false, "I seem to have asked for " + numTests +
" tests, but don't know how to run them all.");
SimpleTest.finish();
}
}
</script>
</head>
--- a/browser/components/resistfingerprinting/test/mochitest/test_reduce_time_precision.html
+++ b/browser/components/resistfingerprinting/test/mochitest/test_reduce_time_precision.html
@@ -34,118 +34,268 @@ https://trac.torproject.org/projects/tor
const timeStampCodes = [
"performance.now()",
"new Date().getTime()",
"new Event(\"\").timeStamp",
"new File([], \"\").lastModified",
"new File([], \"\").lastModifiedDate.getTime()",
];
- const kExpectedResolution = 100;
+ let isRounded = (x, expectedPrecision) => {
+ 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
+ if (Math.abs(rounded - x + expectedPrecision) < .0000001) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0000001) {
+ return true;
+ }
- function* checkWorker(worker, prefname) {
+ // 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;
+ }
+ }
+
+ 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;
+ };
+
+ async function checkWorker(worker, prefname, expectedPrecision) {
// The child worker will send the results back.
- let checkTimeStamps = () => new Promise(function(resolve) {
+ let checkWorkerTimeStamps = () => new Promise(function(resolve) {
let onMessage = function(event) {
worker.removeEventListener("message", onMessage);
let timeStamps = event.data;
for (let i = 0; i < timeStampCodes.length; i++) {
let timeStamp = timeStamps[i];
- is(timeStamp % kExpectedResolution, 0,
+ ok(isRounded(timeStamp, expectedPrecision),
"pref: " + prefname + " - '" +
"'" + timeStampCodes[i] +
- "' should be rounded to nearest 100 ms in workers; saw " +
+ "' should be rounded to nearest " + expectedPrecision + " us in workers; saw " +
timeStamp);
}
resolve();
};
worker.addEventListener("message", onMessage);
});
// Send the codes to its child worker.
worker.postMessage(timeStampCodes);
// First, check the child's results.
- yield checkTimeStamps();
+ await checkWorkerTimeStamps();
// Then, check the grandchild's results.
- yield checkTimeStamps();
+ await checkWorkerTimeStamps();
worker.terminate();
}
- add_task(async function testWorkerRFP() {
- // Create one worker before setting the pref, and one after, in order to
- // check that the resolution is updated whether or not the worker was
- // already started
- let worker1 = new Worker("worker_child.js");
- await SpecialPowers.pushPrefEnv({
- "set": [["privacy.resistFingerprinting", true],
- ["privacy.reduceTimerPrecision", false]]});
- let worker2 = new Worker("worker_child.js");
- // Allow ~550 ms to elapse, so we can get non-zero
- // time values for all elements.
- await new Promise(resolve => window.setTimeout(resolve, 550));
- await checkWorker(worker1, "privacy.resistFingerprinting");
- await checkWorker(worker2, "privacy.resistFingerprinting");
- });
-
- add_task(async function testWorkerRTP() {
- // Create one worker before setting the pref, and one after, in order to
- // check that the resolution is updated whether or not the worker was
- // already started
- let worker1 = new Worker("worker_child.js");
- await SpecialPowers.pushPrefEnv({
- "set": [["privacy.resistFingerprinting", false],
- ["privacy.reduceTimerPrecision", true]]});
- let worker2 = new Worker("worker_child.js");
- // Allow ~550 ms to elapse, so we can get non-zero
- // time values for all elements.
- await new Promise(resolve => window.setTimeout(resolve, 550));
- await checkWorker(worker1, "privacy.reduceTimerPrecision");
- await checkWorker(worker2, "privacy.reduceTimerPrecision");
- });
-
- add_task(async function testDOMRFP() {
- await SpecialPowers.pushPrefEnv({
- "set": [["privacy.resistFingerprinting", true],
- ["privacy.reduceTimerPrecision", false]]});
+ function checkTimestamps(pref, expectedPrecision) {
+ // These are measured in seconds, so we need to scale them up
let timeStampCodesDOM = timeStampCodes.concat([
"audioContext.currentTime * 1000",
"canvasStream.currentTime * 1000",
]);
// Loop through each timeStampCode, evaluate it,
- // and check if it is rounded to the nearest 100 ms.
+ // and check if it is rounded
for (let timeStampCode of timeStampCodesDOM) {
let timeStamp = eval(timeStampCode);
- is(timeStamp % kExpectedResolution, 0,
- "pref: privacy.resistFingerprinting - '" +
+ ok(isRounded(timeStamp, expectedPrecision),
+ "pref: " + pref + " - '" +
"'" + timeStampCode +
- "' should be rounded to nearest 100 ms; saw " +
+ "' should be rounded to nearest " +
+ expectedPrecision + " us; saw " +
timeStamp);
}
+ }
+
+
+ add_task(async function testWorkerRFP1() {
+ // Create one worker before setting the pref, and one after, in order to
+ // check that the resolution is updated whether or not the worker was
+ // already started
+ let expectedPrecision = 100;
+ let worker1 = new Worker("worker_child.js");
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ let worker2 = new Worker("worker_child.js");
+ // Allow ~550 ms to elapse, so we can get non-zero
+ // time values for all elements.
+ await new Promise(resolve => window.setTimeout(resolve, 550));
+ await checkWorker(worker1, "privacy.resistFingerprinting", expectedPrecision);
+ await checkWorker(worker2, "privacy.resistFingerprinting", expectedPrecision);
});
- add_task(async function testDOMRTP() {
+ add_task(async function testWorkerRFP2() {
+ // Create one worker before setting the pref, and one after, in order to
+ // check that the resolution is updated whether or not the worker was
+ // already started
+ let expectedPrecision = 13;
+ let worker1 = new Worker("worker_child.js");
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ let worker2 = new Worker("worker_child.js");
+ // Allow ~550 ms to elapse, so we can get non-zero
+ // time values for all elements.
+ await new Promise(resolve => window.setTimeout(resolve, 550));
+ await checkWorker(worker1, "privacy.resistFingerprinting", expectedPrecision);
+ await checkWorker(worker2, "privacy.resistFingerprinting", expectedPrecision);
+ });
+
+ add_task(async function testWorkerRFP3() {
+ // Create one worker before setting the pref, and one after, in order to
+ // check that the resolution is updated whether or not the worker was
+ // already started
+ let expectedPrecision = .13;
+ let worker1 = new Worker("worker_child.js");
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ let worker2 = new Worker("worker_child.js");
+ // Allow ~550 ms to elapse, so we can get non-zero
+ // time values for all elements.
+ await new Promise(resolve => window.setTimeout(resolve, 550));
+ await checkWorker(worker1, "privacy.resistFingerprinting", expectedPrecision);
+ await checkWorker(worker2, "privacy.resistFingerprinting", expectedPrecision);
+ });
+
+ add_task(async function testWorkerRTP1() {
+ // Create one worker before setting the pref, and one after, in order to
+ // check that the resolution is updated whether or not the worker was
+ // already started
+ let expectedPrecision = 100;
+ let worker1 = new Worker("worker_child.js");
await SpecialPowers.pushPrefEnv({
"set": [["privacy.resistFingerprinting", false],
- ["privacy.reduceTimerPrecision", true]]});
- let timeStampCodesDOM = timeStampCodes.concat([
- "audioContext.currentTime * 1000",
- "canvasStream.currentTime * 1000",
- ]);
- // Loop through each timeStampCode, evaluate it,
- // and check if it is rounded to the nearest 100 ms.
- for (let timeStampCode of timeStampCodesDOM) {
- let timeStamp = eval(timeStampCode);
- is(timeStamp % kExpectedResolution, 0,
- "pref: privacy.reduceTimerPrecision - '" +
- timeStampCode +
- "' should be rounded to nearest 100 ms; saw " +
- timeStamp);
- }
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ let worker2 = new Worker("worker_child.js");
+ // Allow ~550 ms to elapse, so we can get non-zero
+ // time values for all elements.
+ await new Promise(resolve => window.setTimeout(resolve, 550));
+ await checkWorker(worker1, "privacy.reduceTimerPrecision", expectedPrecision);
+ await checkWorker(worker2, "privacy.reduceTimerPrecision", expectedPrecision);
+ });
+
+ add_task(async function testWorkerRTP2() {
+ // Create one worker before setting the pref, and one after, in order to
+ // check that the resolution is updated whether or not the worker was
+ // already started
+ let expectedPrecision = 13;
+ let worker1 = new Worker("worker_child.js");
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ let worker2 = new Worker("worker_child.js");
+ // Allow ~550 ms to elapse, so we can get non-zero
+ // time values for all elements.
+ await new Promise(resolve => window.setTimeout(resolve, 550));
+ await checkWorker(worker1, "privacy.reduceTimerPrecision", expectedPrecision);
+ await checkWorker(worker2, "privacy.reduceTimerPrecision", expectedPrecision);
+ });
+
+ add_task(async function testWorkerRTP3() {
+ // Create one worker before setting the pref, and one after, in order to
+ // check that the resolution is updated whether or not the worker was
+ // already started
+ let expectedPrecision = .13;
+ let worker1 = new Worker("worker_child.js");
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ let worker2 = new Worker("worker_child.js");
+ // Allow ~550 ms to elapse, so we can get non-zero
+ // time values for all elements.
+ await new Promise(resolve => window.setTimeout(resolve, 550));
+ await checkWorker(worker1, "privacy.reduceTimerPrecision", expectedPrecision);
+ await checkWorker(worker2, "privacy.reduceTimerPrecision", expectedPrecision);
+ });
+
+ add_task(async function testDOMRFP1() {
+ let expectedPrecision = 100;
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ checkTimestamps("privacy.resistFingerprinting", expectedPrecision);
+ });
+
+ add_task(async function testDOMRFP2() {
+ let expectedPrecision = 13;
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ checkTimestamps("privacy.resistFingerprinting", expectedPrecision);
+ });
+
+ add_task(async function testDOMRFP3() {
+ let expectedPrecision = .13;
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", true],
+ ["privacy.reduceTimerPrecision", false],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ checkTimestamps("privacy.resistFingerprinting", expectedPrecision);
+ });
+
+ add_task(async function testDOMRTP1() {
+ let expectedPrecision = 100;
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ checkTimestamps("privacy.reduceTimerPrecision", expectedPrecision);
+ });
+
+ add_task(async function testDOMRTP2() {
+ let expectedPrecision = 13;
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ checkTimestamps("privacy.reduceTimerPrecision", expectedPrecision);
+ });
+
+ add_task(async function testDOMRTP3() {
+ let expectedPrecision = .13;
+ await SpecialPowers.pushPrefEnv({
+ "set": [["privacy.resistFingerprinting", false],
+ ["privacy.reduceTimerPrecision", true],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision * 1000]
+ ]});
+ checkTimestamps("privacy.reduceTimerPrecision", expectedPrecision);
});
</script>
</body>
</html>
--- a/dom/ipc/ContentPrefs.cpp
+++ b/dom/ipc/ContentPrefs.cpp
@@ -281,18 +281,18 @@ const char* mozilla::dom::ContentPrefs::
"network.tcp.keepalive.probe_count",
"network.tcp.keepalive.retry_interval",
"network.tcp.sendbuffer",
"nglayout.debug.invalidation",
"privacy.donottrackheader.enabled",
"privacy.firstparty.isolate",
"privacy.firstparty.isolate.restrict_opener_access",
"privacy.reduceTimerPrecision",
- "privacy.reduceTimerPrecision.microseconds",
"privacy.resistFingerprinting",
+ "privacy.resistFingerprinting.reduceTimerPrecision.microseconds",
"privacy.resistFingerprinting.target_video_res",
"privacy.resistFingerprinting.video_dropped_ratio",
"privacy.resistFingerprinting.video_frames_per_sec",
"privacy.trackingprotection.lower_network_priority",
"privacy.window.maxInnerHeight",
"privacy.window.maxInnerWidth",
"security.csp.enable",
"security.data_uri.block_toplevel_data_uri_navigations",