summaryrefslogtreecommitdiffstats
path: root/toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js')
-rw-r--r--toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js559
1 files changed, 559 insertions, 0 deletions
diff --git a/toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js b/toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js
new file mode 100644
index 0000000000..1a882fc63d
--- /dev/null
+++ b/toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js
@@ -0,0 +1,559 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { RemoteSettings } = ChromeUtils.importESModule(
+ "resource://services-settings/remote-settings.sys.mjs"
+);
+
+const COLLECTION_NAME = "fingerprinting-protection-overrides";
+
+const TOP_DOMAIN = "https://example.com";
+const THIRD_PARTY_DOMAIN = "https://example.org";
+
+const SPOOFED_HW_CONCURRENCY = 2;
+const DEFAULT_HW_CONCURRENCY = navigator.hardwareConcurrency;
+
+const TEST_TOP_PAGE =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ TOP_DOMAIN
+ ) + "empty.html";
+const TEST_THIRD_PARTY_PAGE =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ THIRD_PARTY_DOMAIN
+ ) + "empty.html";
+
+const TEST_CASES = [
+ // Test the wildcard entry.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "*",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: true,
+ firstParty: true,
+ thirdParty: true,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test the entry that only applies to the first-party context.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.com",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: true,
+ firstParty: true,
+ thirdParty: false,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test the entry that applies to every context under the first-party domain.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.com",
+ thirdPartyDomain: "*",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: true,
+ firstParty: true,
+ thirdParty: true,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test the entry that applies to the specific third-party domain under the first-party domain.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.com",
+ thirdPartyDomain: "example.org",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: false,
+ firstParty: false,
+ thirdParty: true,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test the entry that applies to the every third-party domain under any first-party domains.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "*",
+ thirdPartyDomain: "example.org",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: false,
+ firstParty: false,
+ thirdParty: true,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test a entry that doesn't apply to the current contexts. The first-party
+ // domain is different.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.net",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test a entry that doesn't apply to the current contexts. The first-party
+ // domain is different.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.net",
+ thirdPartyDomain: "*",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test a entry that doesn't apply to a the current contexts. Both first-party
+ // and third-party domains are different.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.net",
+ thirdPartyDomain: "example.com",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: false,
+ },
+ },
+ },
+ // Test multiple entries that enable HW concurrency in the first-party context
+ // and WindowOuter in the third-party context.
+ {
+ entires: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.com",
+ },
+ {
+ id: "2",
+ last_modified: 1000000000000001,
+ overrides: "+NavigatorHWConcurrency",
+ firstPartyDomain: "example.com",
+ thirdPartyDomain: "example.org",
+ },
+ ],
+ expects: {
+ windowOuter: {
+ top: true,
+ firstParty: true,
+ thirdParty: false,
+ },
+ hwConcurrency: {
+ top: false,
+ firstParty: false,
+ thirdParty: true,
+ },
+ },
+ },
+];
+
+async function openAndSetupTestPage() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+
+ // Create a first-party and a third-party iframe in the tab.
+ let { firstPartyBC, thirdPartyBC } = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [TEST_TOP_PAGE, TEST_THIRD_PARTY_PAGE],
+ async (firstPartySrc, thirdPartySrc) => {
+ let firstPartyFrame = content.document.createElement("iframe");
+ let loading = new content.Promise(resolve => {
+ firstPartyFrame.onload = resolve;
+ });
+ content.document.body.appendChild(firstPartyFrame);
+ firstPartyFrame.src = firstPartySrc;
+ await loading;
+
+ let thirdPartyFrame = content.document.createElement("iframe");
+ loading = new content.Promise(resolve => {
+ thirdPartyFrame.onload = resolve;
+ });
+ content.document.body.appendChild(thirdPartyFrame);
+ thirdPartyFrame.src = thirdPartySrc;
+ await loading;
+
+ return {
+ firstPartyBC: firstPartyFrame.browsingContext,
+ thirdPartyBC: thirdPartyFrame.browsingContext,
+ };
+ }
+ );
+
+ return { tab, firstPartyBC, thirdPartyBC };
+}
+
+async function openAndSetupTestPageForPopup() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+
+ // Create a third-party iframe and a pop-up from this iframe.
+ let { thirdPartyFrameBC, popupBC } = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [TEST_THIRD_PARTY_PAGE],
+ async thirdPartySrc => {
+ let thirdPartyFrame = content.document.createElement("iframe");
+ let loading = new content.Promise(resolve => {
+ thirdPartyFrame.onload = resolve;
+ });
+ content.document.body.appendChild(thirdPartyFrame);
+ thirdPartyFrame.src = thirdPartySrc;
+ await loading;
+
+ let popupBC = await SpecialPowers.spawn(
+ thirdPartyFrame,
+ [thirdPartySrc],
+ async src => {
+ let win;
+ let loading = new content.Promise(resolve => {
+ win = content.open(src);
+ win.onload = resolve;
+ });
+ await loading;
+
+ return win.browsingContext;
+ }
+ );
+
+ return {
+ thirdPartyFrameBC: thirdPartyFrame.browsingContext,
+ popupBC,
+ };
+ }
+ );
+
+ return { tab, thirdPartyFrameBC, popupBC };
+}
+
+async function verifyResultInTab(tab, firstPartyBC, thirdPartyBC, expected) {
+ let testWindowOuter = enabled => {
+ if (enabled) {
+ ok(
+ content.wrappedJSObject.outerHeight ==
+ content.wrappedJSObject.innerHeight &&
+ content.wrappedJSObject.outerWidth ==
+ content.wrappedJSObject.innerWidth,
+ "Fingerprinting target WindowOuterSize is enabled for WindowOuterSize."
+ );
+ } else {
+ ok(
+ content.wrappedJSObject.outerHeight !=
+ content.wrappedJSObject.innerHeight ||
+ content.wrappedJSObject.outerWidth !=
+ content.wrappedJSObject.innerWidth,
+ "Fingerprinting target WindowOuterSize is not enabled for WindowOuterSize."
+ );
+ }
+ };
+
+ let testHWConcurrency = expected => {
+ is(
+ content.wrappedJSObject.navigator.hardwareConcurrency,
+ expected,
+ "The hardware concurrency is expected."
+ );
+ };
+
+ info(
+ `Verify top-level context with fingerprinting protection is ${
+ expected.top ? "enabled" : "not enabled"
+ }.`
+ );
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [expected.windowOuter.top],
+ testWindowOuter
+ );
+ let expectHWConcurrencyTop = expected.hwConcurrency.top
+ ? SPOOFED_HW_CONCURRENCY
+ : DEFAULT_HW_CONCURRENCY;
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [expectHWConcurrencyTop],
+ testHWConcurrency
+ );
+
+ let workerTopResult = await runFunctionInWorker(
+ tab.linkedBrowser,
+ async _ => {
+ return navigator.hardwareConcurrency;
+ }
+ );
+ is(
+ workerTopResult,
+ expectHWConcurrencyTop,
+ "The top worker reports the expected HW concurrency."
+ );
+
+ info(
+ `Verify first-party context with fingerprinting protection is ${
+ expected.firstParty ? "enabled" : "not enabled"
+ }.`
+ );
+ await SpecialPowers.spawn(
+ firstPartyBC,
+ [expected.windowOuter.firstParty],
+ testWindowOuter
+ );
+ let expectHWConcurrencyFirstParty = expected.hwConcurrency.firstParty
+ ? SPOOFED_HW_CONCURRENCY
+ : DEFAULT_HW_CONCURRENCY;
+ await SpecialPowers.spawn(
+ firstPartyBC,
+ [expectHWConcurrencyFirstParty],
+ testHWConcurrency
+ );
+
+ let workerFirstPartyResult = await runFunctionInWorker(
+ firstPartyBC,
+ async _ => {
+ return navigator.hardwareConcurrency;
+ }
+ );
+ is(
+ workerFirstPartyResult,
+ expectHWConcurrencyFirstParty,
+ "The first-party worker reports the expected HW concurrency."
+ );
+
+ info(
+ `Verify third-party context with fingerprinting protection is ${
+ expected.thirdParty ? "enabled" : "not enabled"
+ }.`
+ );
+ await SpecialPowers.spawn(
+ thirdPartyBC,
+ [expected.windowOuter.thirdParty],
+ testWindowOuter
+ );
+ let expectHWConcurrencyThirdParty = expected.hwConcurrency.thirdParty
+ ? SPOOFED_HW_CONCURRENCY
+ : DEFAULT_HW_CONCURRENCY;
+ await SpecialPowers.spawn(
+ thirdPartyBC,
+ [expectHWConcurrencyThirdParty],
+ testHWConcurrency
+ );
+
+ let workerThirdPartyResult = await runFunctionInWorker(
+ thirdPartyBC,
+ async _ => {
+ return navigator.hardwareConcurrency;
+ }
+ );
+ is(
+ workerThirdPartyResult,
+ expectHWConcurrencyThirdParty,
+ "The third-party worker reports the expected HW concurrency."
+ );
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["privacy.fingerprintingProtection.remoteOverrides.testing", true],
+ ["privacy.fingerprintingProtection", true],
+ ["privacy.fingerprintingProtection.pbmode", true],
+ ],
+ });
+
+ registerCleanupFunction(() => {
+ Services.rfp.cleanAllOverrides();
+ });
+});
+
+add_task(async function () {
+ // Add initial empty record.
+ let db = RemoteSettings(COLLECTION_NAME).db;
+ await db.importChanges({}, Date.now(), []);
+
+ for (let test of TEST_CASES) {
+ // Create a promise for waiting the overrides get updated.
+ let promise = promiseObserver("fpp-test:set-overrides-finishes");
+
+ // Trigger the fingerprinting overrides update by a remote settings sync.
+ await RemoteSettings(COLLECTION_NAME).emit("sync", {
+ data: {
+ current: test.entires,
+ },
+ });
+ await promise;
+
+ ok(true, "Got overrides update");
+
+ let { tab, firstPartyBC, thirdPartyBC } = await openAndSetupTestPage();
+
+ await verifyResultInTab(tab, firstPartyBC, thirdPartyBC, test.expects);
+
+ BrowserTestUtils.removeTab(tab);
+ }
+
+ db.clear();
+});
+
+// A test to verify that a pop-up inherits overrides from the third-party iframe
+// that opens it.
+add_task(async function test_popup_inheritance() {
+ // Add initial empty record.
+ let db = RemoteSettings(COLLECTION_NAME).db;
+ await db.importChanges({}, Date.now(), []);
+
+ // Create a promise for waiting the overrides get updated.
+ let promise = promiseObserver("fpp-test:set-overrides-finishes");
+
+ // Trigger the fingerprinting overrides update by a remote settings sync.
+ await RemoteSettings(COLLECTION_NAME).emit("sync", {
+ data: {
+ current: [
+ {
+ id: "1",
+ last_modified: 1000000000000001,
+ overrides: "+WindowOuterSize",
+ firstPartyDomain: "example.com",
+ thirdPartyDomain: "example.org",
+ },
+ ],
+ },
+ });
+ await promise;
+
+ let { tab, thirdPartyFrameBC, popupBC } =
+ await openAndSetupTestPageForPopup();
+
+ // Ensure the third-party iframe has the correct overrides.
+ await SpecialPowers.spawn(thirdPartyFrameBC, [], _ => {
+ ok(
+ content.wrappedJSObject.outerHeight ==
+ content.wrappedJSObject.innerHeight &&
+ content.wrappedJSObject.outerWidth ==
+ content.wrappedJSObject.innerWidth,
+ "Fingerprinting target WindowOuterSize is enabled for third-party iframe."
+ );
+ });
+
+ // Verify the popup inherits overrides from the opener.
+ await SpecialPowers.spawn(popupBC, [], _ => {
+ ok(
+ content.wrappedJSObject.outerHeight ==
+ content.wrappedJSObject.innerHeight &&
+ content.wrappedJSObject.outerWidth ==
+ content.wrappedJSObject.innerWidth,
+ "Fingerprinting target WindowOuterSize is enabled for the pop-up."
+ );
+
+ content.close();
+ });
+
+ BrowserTestUtils.removeTab(tab);
+
+ db.clear();
+});