Source code

Revision control

Copy as Markdown

Other Tools

/* 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";
ChromeUtils.defineESModuleGetters(this, {
ContentBlockingAllowList:
});
const TEST_PATH =
"components/resistfingerprinting/test/browser/";
const PERFORMANCE_TIMINGS = [
"navigationStart",
"unloadEventStart",
"unloadEventEnd",
"redirectStart",
"redirectEnd",
"fetchStart",
"domainLookupStart",
"domainLookupEnd",
"connectStart",
"connectEnd",
"secureConnectionStart",
"requestStart",
"responseStart",
"responseEnd",
"domLoading",
"domInteractive",
"domContentLoadedEventStart",
"domContentLoadedEventEnd",
"domComplete",
"loadEventStart",
"loadEventEnd",
];
/**
* Sets up tests for making sure that performance APIs have been correctly
* spoofed or disabled.
*/
let setupPerformanceAPISpoofAndDisableTest = async function (
resistFingerprinting,
reduceTimerPrecision,
crossOriginIsolated,
expectedPrecision,
runTests,
workerCall
) {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", resistFingerprinting],
["privacy.reduceTimerPrecision", reduceTimerPrecision],
[
"privacy.resistFingerprinting.reduceTimerPrecision.microseconds",
expectedPrecision * 1000,
],
["browser.tabs.remote.useCrossOriginOpenerPolicy", crossOriginIsolated],
["browser.tabs.remote.useCrossOriginEmbedderPolicy", crossOriginIsolated],
],
});
let url = crossOriginIsolated
`/test/browser/coop_header.sjs?crossOriginIsolated=${crossOriginIsolated}`
: TEST_PATH + "file_dummy.html";
let win = await BrowserTestUtils.openNewBrowserWindow();
let tab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, url);
// No matter what we set the precision to, if we're in ResistFingerprinting
// mode we use the larger of the precision pref and the RFP time-atom constant
if (resistFingerprinting) {
const RFP_TIME_ATOM_MS = 16.667;
expectedPrecision = Math.max(RFP_TIME_ATOM_MS, expectedPrecision);
}
await SpecialPowers.spawn(
tab.linkedBrowser,
[
{
list: PERFORMANCE_TIMINGS,
resistFingerprinting,
precision: expectedPrecision,
isRoundedFunc: isTimeValueRounded.toString(),
workerCall,
},
],
runTests
);
if (crossOriginIsolated) {
let remoteType = tab.linkedBrowser.remoteType;
ok(
remoteType.startsWith(E10SUtils.WEB_REMOTE_COOP_COEP_TYPE_PREFIX),
`${remoteType} expected to be coop+coep`
);
}
await BrowserTestUtils.closeWindow(win);
};
let isTimeValueRounded = (x, expectedPrecision, console) => {
const nearestExpected = Math.round(x / expectedPrecision) * expectedPrecision;
// First we do the perfectly normal check that should work just fine
if (x === nearestExpected) {
return true;
}
// When we're dividing 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.
const error = Math.abs(x - nearestExpected);
if (console) {
console.log(
"Additional Debugging Info: Expected Precision: " +
expectedPrecision +
" Measured Value: " +
x +
" Nearest Expected Vaue: " +
nearestExpected +
" Error: " +
error
);
}
if (Math.abs(error) < 0.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 (
Math.round(expectedPrecision) != expectedPrecision &&
Math.round(x) == x
) {
let acceptableIntRounding = false;
acceptableIntRounding |= Math.floor(nearestExpected) == x;
acceptableIntRounding |= Math.ceil(nearestExpected) == x;
if (acceptableIntRounding) {
return true;
}
}
return false;
};
let setupAndRunCrossOriginIsolatedTest = async function (
options,
expectedPrecision,
runTests,
workerCall
) {
let prefsToSet = [
[
"privacy.resistFingerprinting.reduceTimerPrecision.microseconds",
expectedPrecision * 1000,
],
];
if (options.resistFingerprinting !== undefined) {
prefsToSet = prefsToSet.concat([
["privacy.resistFingerprinting", options.resistFingerprinting],
]);
} else {
options.resistFingerprinting = false;
}
if (options.resistFingerprintingPBMOnly !== undefined) {
prefsToSet = prefsToSet.concat([
[
"privacy.resistFingerprinting.pbmode",
options.resistFingerprintingPBMOnly,
],
]);
} else {
options.resistFingerprintingPBMOnly = false;
}
if (options.reduceTimerPrecision !== undefined) {
prefsToSet = prefsToSet.concat([
["privacy.reduceTimerPrecision", options.reduceTimerPrecision],
]);
} else {
options.reduceTimerPrecision = false;
}
if (options.crossOriginIsolated !== undefined) {
prefsToSet = prefsToSet.concat([
[
"browser.tabs.remote.useCrossOriginOpenerPolicy",
options.crossOriginIsolated,
],
[
"browser.tabs.remote.useCrossOriginEmbedderPolicy",
options.crossOriginIsolated,
],
]);
} else {
options.crossOriginIsolated = false;
}
if (options.openPrivateWindow === undefined) {
options.openPrivateWindow = false;
}
if (options.shouldBeRounded === undefined) {
options.shouldBeRounded = true;
}
console.log(prefsToSet);
await SpecialPowers.pushPrefEnv({ set: prefsToSet });
let win = await BrowserTestUtils.openNewBrowserWindow({
private: options.openPrivateWindow,
});
let tab = await BrowserTestUtils.openNewForegroundTab(
win.gBrowser,
`/test/browser/coop_header.sjs?crossOriginIsolated=${options.crossOriginIsolated}`
);
// No matter what we set the precision to, if we're in ResistFingerprinting
// mode we use the larger of the precision pref and the RFP time-atom constant
if (
options.resistFingerprinting ||
(options.resistFingerprintingPBMOnly && options.openPrivateWindow)
) {
const RFP_TIME_ATOM_MS = 16.667;
expectedPrecision = Math.max(RFP_TIME_ATOM_MS, expectedPrecision);
}
await SpecialPowers.spawn(
tab.linkedBrowser,
[
{
precision: expectedPrecision,
isRoundedFunc: isTimeValueRounded.toString(),
workerCall,
options,
},
],
runTests
);
if (options.crossOriginIsolated) {
let remoteType = tab.linkedBrowser.remoteType;
ok(
remoteType.startsWith(E10SUtils.WEB_REMOTE_COOP_COEP_TYPE_PREFIX),
`${remoteType} expected to be coop+coep`
);
}
await BrowserTestUtils.closeWindow(win);
await SpecialPowers.popPrefEnv();
};
// This function calculates the maximum available window dimensions and returns
// them as an object.
async function calcMaximumAvailSize(aChromeWidth, aChromeHeight) {
let chromeUIWidth;
let chromeUIHeight;
let testPath =
"components/resistfingerprinting/test/browser/";
// If the chrome UI dimensions is not given, we will calculate it.
if (!aChromeWidth || !aChromeHeight) {
let win = await BrowserTestUtils.openNewBrowserWindow();
let tab = await BrowserTestUtils.openNewForegroundTab(
win.gBrowser,
testPath + "file_dummy.html"
);
let contentSize = await SpecialPowers.spawn(
tab.linkedBrowser,
[],
async function () {
let result = {
width: content.innerWidth,
height: content.innerHeight,
};
return result;
}
);
// Calculate the maximum available window size which is depending on the
// available screen space.
chromeUIWidth = win.outerWidth - contentSize.width;
chromeUIHeight = win.outerHeight - contentSize.height;
BrowserTestUtils.removeTab(tab);
await BrowserTestUtils.closeWindow(win);
} else {
chromeUIWidth = aChromeWidth;
chromeUIHeight = aChromeHeight;
}
let availWidth = window.screen.availWidth;
let availHeight = window.screen.availHeight;
// Ideally, we would round the window size as 1000x1000. But the available
// screen space might not suffice. So, we decide the size according to the
// available screen size.
let availContentWidth = Math.min(1000, availWidth - chromeUIWidth);
let availContentHeight;
// If it is GTK window, we would consider the system decorations when we
// calculating avail content height since the system decorations won't be
// reported when we get available screen dimensions.
if (AppConstants.MOZ_WIDGET_GTK) {
availContentHeight = Math.min(1000, -40 + availHeight - chromeUIHeight);
} else {
availContentHeight = Math.min(1000, availHeight - chromeUIHeight);
}
// Rounded the desire size to the nearest 200x100.
let maxAvailWidth = availContentWidth - (availContentWidth % 200);
let maxAvailHeight = availContentHeight - (availContentHeight % 100);
return { maxAvailWidth, maxAvailHeight };
}
async function calcPopUpWindowChromeUISize() {
let testPath =
"components/resistFingerprinting/test/browser/";
// open a popup window to acquire the chrome UI size of it.
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
testPath + "file_dummy.html"
);
let result = await SpecialPowers.spawn(
tab.linkedBrowser,
[],
async function () {
let win;
await new Promise(resolve => {
win = content.open("about:blank", "", "width=1000,height=1000");
win.onload = () => resolve();
});
let res = {
chromeWidth: win.outerWidth - win.innerWidth,
chromeHeight: win.outerHeight - win.innerHeight,
};
win.close();
return res;
}
);
BrowserTestUtils.removeTab(tab);
return result;
}
async function testWindowOpen(
aBrowser,
aSettingWidth,
aSettingHeight,
aTargetWidth,
aTargetHeight,
aMaxAvailWidth,
aMaxAvailHeight
) {
// If the target size is greater than the maximum available content size,
// we set the target size to it.
if (aTargetWidth > aMaxAvailWidth) {
aTargetWidth = aMaxAvailWidth;
}
if (aTargetHeight > aMaxAvailHeight) {
aTargetHeight = aMaxAvailHeight;
}
// Create the testing window features.
let winFeatures = "width=" + aSettingWidth + ",height=" + aSettingHeight;
let testParams = {
winFeatures,
targetWidth: aTargetWidth,
targetHeight: aTargetHeight,
};
await SpecialPowers.spawn(aBrowser, [testParams], async function (input) {
// Call window.open() with window features.
await new Promise(resolve => {
let win = content.open("http://example.net/", "", input.winFeatures);
win.onload = () => {
is(
win.screen.width,
input.targetWidth,
"The screen.width has a correct rounded value"
);
is(
win.screen.height,
input.targetHeight,
"The screen.height has a correct rounded value"
);
is(
win.innerWidth,
input.targetWidth,
"The window.innerWidth has a correct rounded value"
);
is(
win.innerHeight,
input.targetHeight,
"The window.innerHeight has a correct rounded value"
);
win.close();
resolve();
};
});
});
}
async function testWindowSizeSetting(
aBrowser,
aSettingWidth,
aSettingHeight,
aTargetWidth,
aTargetHeight,
aInitWidth,
aInitHeight,
aTestOuter,
aMaxAvailWidth,
aMaxAvailHeight,
aPopupChromeUIWidth,
aPopupChromeUIHeight
) {
// If the target size is greater than the maximum available content size,
// we set the target size to it.
if (aTargetWidth > aMaxAvailWidth) {
aTargetWidth = aMaxAvailWidth;
}
if (aTargetHeight > aMaxAvailHeight) {
aTargetHeight = aMaxAvailHeight;
}
let testParams = {
initWidth: aInitWidth,
initHeight: aInitHeight,
settingWidth: aSettingWidth + (aTestOuter ? aPopupChromeUIWidth : 0),
settingHeight: aSettingHeight + (aTestOuter ? aPopupChromeUIHeight : 0),
targetWidth: aTargetWidth,
targetHeight: aTargetHeight,
testOuter: aTestOuter,
};
await SpecialPowers.spawn(aBrowser, [testParams], async function (input) {
let win;
// Open a new window and wait until it loads.
await new Promise(resolve => {
// Given a initial window size which should be different from target
// size. We need this to trigger 'onresize' event.
let initWinFeatures =
"width=" + input.initWidth + ",height=" + input.initHeight;
win = content.open("http://example.net/", "", initWinFeatures);
win.onload = () => resolve();
});
// Test inner/outerWidth.
await new Promise(resolve => {
win.addEventListener(
"resize",
() => {
is(
win.screen.width,
input.targetWidth,
"The screen.width has a correct rounded value"
);
is(
win.innerWidth,
input.targetWidth,
"The window.innerWidth has a correct rounded value"
);
resolve();
},
{ once: true }
);
if (input.testOuter) {
win.outerWidth = input.settingWidth;
} else {
win.innerWidth = input.settingWidth;
}
});
win.close();
// Open a new window and wait until it loads.
await new Promise(resolve => {
// Given a initial window size which should be different from target
// size. We need this to trigger 'onresize' event.
let initWinFeatures =
"width=" + input.initWidth + ",height=" + input.initHeight;
win = content.open("http://example.net/", "", initWinFeatures);
win.onload = () => resolve();
});
// Test inner/outerHeight.
await new Promise(resolve => {
win.addEventListener(
"resize",
() => {
is(
win.screen.height,
input.targetHeight,
"The screen.height has a correct rounded value"
);
is(
win.innerHeight,
input.targetHeight,
"The window.innerHeight has a correct rounded value"
);
resolve();
},
{ once: true }
);
if (input.testOuter) {
win.outerHeight = input.settingHeight;
} else {
win.innerHeight = input.settingHeight;
}
});
win.close();
});
}
class RoundedWindowTest {
// testOuter is optional. run() can be invoked with only 1 parameter.
static run(testCases, testOuter) {
// "this" is the calling class itself.
// e.g. when invoked by RoundedWindowTest.run(), "this" is "class RoundedWindowTest".
let test = new this(testCases);
add_task(async () => test.setup());
add_task(async () => {
if (testOuter == undefined) {
// If testOuter is not given, do tests for both inner and outer.
await test.doTests(false);
await test.doTests(true);
} else {
await test.doTests(testOuter);
}
});
}
constructor(testCases) {
this.testCases = testCases;
}
async setup() {
await SpecialPowers.pushPrefEnv({
set: [["privacy.resistFingerprinting", true]],
});
// Calculate the popup window's chrome UI size for tests of outerWidth/Height.
let popUpChromeUISize = await calcPopUpWindowChromeUISize();
this.popupChromeUIWidth = popUpChromeUISize.chromeWidth;
this.popupChromeUIHeight = popUpChromeUISize.chromeHeight;
// Calculate the maximum available size.
let maxAvailSize = await calcMaximumAvailSize(
this.popupChromeUIWidth,
this.popupChromeUIHeight
);
this.maxAvailWidth = maxAvailSize.maxAvailWidth;
this.maxAvailHeight = maxAvailSize.maxAvailHeight;
}
async doTests(testOuter) {
// Open a tab to test.
this.tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_PATH + "file_dummy.html"
);
for (let test of this.testCases) {
await this.doTest(test, testOuter);
}
BrowserTestUtils.removeTab(this.tab);
}
async doTest() {
throw new Error("RoundedWindowTest.doTest must be overridden.");
}
}
class WindowSettingTest extends RoundedWindowTest {
async doTest(test, testOuter) {
await testWindowSizeSetting(
this.tab.linkedBrowser,
test.settingWidth,
test.settingHeight,
test.targetWidth,
test.targetHeight,
test.initWidth,
test.initHeight,
testOuter,
this.maxAvailWidth,
this.maxAvailHeight,
this.popupChromeUIWidth,
this.popupChromeUIHeight
);
}
}
class OpenTest extends RoundedWindowTest {
async doTest(test) {
await testWindowOpen(
this.tab.linkedBrowser,
test.settingWidth,
test.settingHeight,
test.targetWidth,
test.targetHeight,
this.maxAvailWidth,
this.maxAvailHeight,
this.popupChromeUIWidth,
this.popupChromeUIHeight
);
}
}
// ============================================================
const FRAMER_DOMAIN = "example.com";
const IFRAME_DOMAIN = "example.org";
const CROSS_ORIGIN_DOMAIN = "example.net";
async function runActualTest(uri, testFunction, expectedResults, extraData) {
let browserWin = gBrowser;
let openedWin = null;
let pbmWindow =
"private_window" in extraData && extraData.private_window === true;
if (pbmWindow) {
openedWin = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
browserWin = openedWin.gBrowser;
}
let tab = await BrowserTestUtils.openNewForegroundTab(browserWin, uri);
if ("etp_reload" in extraData) {
ContentBlockingAllowList.add(tab.linkedBrowser);
await BrowserTestUtils.reloadTab(tab);
}
/*
* We expect that `runTheTest` is going to be able to communicate with the iframe
* or tab that it opens, but if it cannot (because we are using noopener), we kind
* of hack around and get the data directly.
*/
if ("noopener" in extraData) {
var popupTabPromise = BrowserTestUtils.waitForNewTab(
browserWin,
extraData.await_uri
);
}
// In SpecialPowers.spawn, extraData goes through a structuredClone, which cannot clone
// functions. await_uri is sometimes a function. This filters out keys that are used by
// this function (runActualTest) and not by runTheTest or testFunction. It avoids the
// cloning issue, and avoids polluting the object in those called functions.
let filterExtraData = function (x) {
let banned_keys = ["private_window", "etp_reload", "noopener", "await_uri"];
return Object.fromEntries(
Object.entries(x).filter(([k]) => !banned_keys.includes(k))
);
};
let result = await SpecialPowers.spawn(
tab.linkedBrowser,
[IFRAME_DOMAIN, CROSS_ORIGIN_DOMAIN, filterExtraData(extraData)],
async function (iframe_domain_, cross_origin_domain_, extraData_) {
return content.wrappedJSObject.runTheTest(
iframe_domain_,
cross_origin_domain_,
extraData_
);
}
);
if ("noopener" in extraData) {
await popupTabPromise;
if (Services.appinfo.OS === "WINNT") {
await new Promise(r => setTimeout(r, 1000));
}
let popup_tab = browserWin.tabs[browserWin.tabs.length - 1];
result = await SpecialPowers.spawn(
popup_tab.linkedBrowser,
[],
async function () {
let r = content.wrappedJSObject.give_result();
return r;
}
);
BrowserTestUtils.removeTab(popup_tab);
}
testFunction(result, expectedResults, extraData);
if ("etp_reload" in extraData) {
ContentBlockingAllowList.remove(tab.linkedBrowser);
}
BrowserTestUtils.removeTab(tab);
if (pbmWindow) {
await BrowserTestUtils.closeWindow(openedWin);
}
}
async function defaultsTest(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "default";
expectedResults.shouldRFPApply = false;
if (extraPrefs != undefined) {
await SpecialPowers.pushPrefEnv({
set: extraPrefs,
});
}
await runActualTest(uri, testFunction, expectedResults, extraData);
if (extraPrefs != undefined) {
await SpecialPowers.popPrefEnv();
}
}
async function simpleRFPTest(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "simple RFP enabled";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [["privacy.resistFingerprinting", true]].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
async function simplePBMRFPTest(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.private_window = true;
extraData.testDesc = extraData.testDesc || "simple RFP in PBM enabled";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [["privacy.resistFingerprinting.pbmode", true]].concat(
extraPrefs || []
),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
async function simpleFPPTest(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "simple FPP enabled";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.fingerprintingProtection", true],
["privacy.fingerprintingProtection.overrides", "+NavigatorHWConcurrency"],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
async function simplePBMFPPTest(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.private_window = true;
extraData.testDesc = extraData.testDesc || "simple FPP in PBM enabled";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.fingerprintingProtection.pbmode", true],
["privacy.fingerprintingProtection.overrides", "+HardwareConcurrency"],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
async function simpleRFPPBMFPPTest(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.private_window = false;
extraData.testDesc =
extraData.testDesc ||
"RFP Enabled in PBM and FPP enabled in Normal Browsing Mode";
expectedResults.shouldRFPApply = false;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", false],
["privacy.resistFingerprinting.pbmode", true],
["privacy.fingerprintingProtection", true],
["privacy.fingerprintingProtection.overrides", "-HardwareConcurrency"],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (A) RFP is exempted on the framer and framee and (if needed) on another cross-origin domain
async function testA(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (A)";
expectedResults.shouldRFPApply = false;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
[
"privacy.resistFingerprinting.exemptedDomains",
`${FRAMER_DOMAIN}, ${IFRAME_DOMAIN}, ${CROSS_ORIGIN_DOMAIN}`,
],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (B) RFP is exempted on the framer and framee but is not on another (if needed) cross-origin domain
async function testB(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (B)";
expectedResults.shouldRFPApply = false;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
[
"privacy.resistFingerprinting.exemptedDomains",
`${FRAMER_DOMAIN}, ${IFRAME_DOMAIN}`,
],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (C) RFP is exempted on the framer and (if needed) on another cross-origin domain, but not the framee
async function testC(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (C)";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
[
"privacy.resistFingerprinting.exemptedDomains",
`${FRAMER_DOMAIN}, ${CROSS_ORIGIN_DOMAIN}`,
],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (D) RFP is exempted on the framer but not the framee nor another (if needed) cross-origin domain
async function testD(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (D)";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
["privacy.resistFingerprinting.exemptedDomains", `${FRAMER_DOMAIN}`],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (E) RFP is not exempted on the framer nor the framee but (if needed) is exempted on another cross-origin domain
async function testE(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (E)";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
[
"privacy.resistFingerprinting.exemptedDomains",
`${CROSS_ORIGIN_DOMAIN}`,
],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (F) RFP is not exempted on the framer nor the framee nor another (if needed) cross-origin domain
async function testF(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (F)";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
["privacy.resistFingerprinting.exemptedDomains", ""],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (G) RFP is not exempted on the framer but is on the framee and (if needed) on another cross-origin domain
async function testG(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (G)";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
[
"privacy.resistFingerprinting.exemptedDomains",
`${IFRAME_DOMAIN}, ${CROSS_ORIGIN_DOMAIN}`,
],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}
// (H) RFP is not exempted on the framer nor another (if needed) cross-origin domain but is on the framee
async function testH(
uri,
testFunction,
expectedResults,
extraData,
extraPrefs
) {
if (extraData == undefined) {
extraData = {};
}
extraData.testDesc = extraData.testDesc || "test (H)";
expectedResults.shouldRFPApply = true;
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
["privacy.resistFingerprinting.exemptedDomains", `${IFRAME_DOMAIN}`],
].concat(extraPrefs || []),
});
await runActualTest(uri, testFunction, expectedResults, extraData);
await SpecialPowers.popPrefEnv();
}