[tor-commits] [Git][tpo/applications/mullvad-browser][mullvad-browser-128.2.0esr-14.0-1] Bug 1885101: Match screen and window properties with top window for...
Pier Angelo Vendrame (@pierov)
git at gitlab.torproject.org
Mon Sep 2 08:35:40 UTC 2024
Pier Angelo Vendrame pushed to branch mullvad-browser-128.2.0esr-14.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
f5fe7501 by Fatih at 2024-09-02T10:35:23+02:00
Bug 1885101: Match screen and window properties with top window for ScreenRect, ScreenAvailRect and WindowOuterSize. r=timhuang,emilio
This patch removes test_iframe.html. We remove it because the newly introduced test covers the tests done in that test. The reason for removing it in the first place is now that screen properties are inherited/spoofed xorigin, we get a 4px difference. The reasosn for 4px difference is the test runner runs tests in an iframe with a 2px border on each side.
Differential Revision: https://phabricator.services.mozilla.com/D215509
- - - - -
12 changed files:
- browser/components/resistfingerprinting/test/mochitest/mochitest.toml
- + browser/components/resistfingerprinting/test/mochitest/test_bug1885101_screenwindow_sizes.html
- − browser/components/resistfingerprinting/test/mochitest/test_iframe.html
- docshell/base/BrowsingContext.h
- docshell/base/CanonicalBrowsingContext.cpp
- dom/base/nsGlobalWindowOuter.cpp
- dom/base/nsScreen.cpp
- dom/base/nsScreen.h
- dom/base/test/chrome/bug418986-1.js
- layout/base/nsPresContext.cpp
- layout/base/nsPresContext.h
- toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js
Changes:
=====================================
browser/components/resistfingerprinting/test/mochitest/mochitest.toml
=====================================
@@ -27,8 +27,6 @@ scheme = "https"
scheme = "https"
support-files = ["test_hide_gamepad_info_iframe.html"]
-["test_iframe.html"]
-
["test_keyboard_event.html"]
["test_pointer_event.html"]
@@ -36,3 +34,5 @@ support-files = ["../../../../../dom/events/test/pointerevents/mochitest_support
["test_speech_synthesis.html"]
skip-if = ["verify"]
+
+["test_bug1885101_screenwindow_sizes.html"]
=====================================
browser/components/resistfingerprinting/test/mochitest/test_bug1885101_screenwindow_sizes.html
=====================================
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Tests if +WindowOuterSizeExceptIFrame works properly</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ </head>
+
+ <body>
+ <iframe id="mainFrame"></iframe>
+
+ <template id="mainFrameContents">
+ <script>
+ window.parent.postMessage(
+ {
+ screen: {
+ height: window.screen.height,
+ width: window.screen.width,
+ availHeight: window.screen.availHeight,
+ availWidth: window.screen.availWidth,
+ },
+ outerHeight,
+ outerWidth,
+ },
+ "*"
+ );
+ </script>
+ </template>
+
+ <script>
+ document.addEventListener("DOMContentLoaded", function () {
+ SimpleTest.waitForExplicitFinish();
+
+ window.addEventListener("message", e => {
+ const data = e.data;
+
+ // Check for outer size
+ SimpleTest.is(
+ data.outerHeight,
+ window.outerHeight,
+ "iframe's window.outerHeight should be equal to window.top.outerHeight"
+ );
+
+ SimpleTest.is(
+ data.outerWidth,
+ window.outerWidth,
+ "iframe's window.outerWidth should be equal to window.top.outerWidth"
+ );
+
+ // Check for screen size
+ SimpleTest.is(
+ data.screen.height,
+ window.screen.height,
+ "iframe's window.screen.height should be equal to window.top.screen.height"
+ );
+
+ SimpleTest.is(
+ data.screen.width,
+ window.screen.width,
+ "iframe's window.screen.width should be equal to window.top.screen.width"
+ );
+
+ // Check for avail size
+ SimpleTest.is(
+ data.screen.availHeight,
+ window.screen.availHeight,
+ "iframe's window.screen.availHeight should be equal to window.top.screen.availHeight"
+ );
+
+ SimpleTest.is(
+ data.screen.availWidth,
+ window.screen.availWidth,
+ "iframe's window.screen.availWidth should be equal to window.top.screen.availWidth"
+ );
+
+ SimpleTest.finish();
+ });
+
+ function setFrameSource() {
+ const frame = document.getElementById("mainFrame");
+ const template = document.getElementById("mainFrameContents");
+ frame.srcdoc = template.innerHTML;
+ }
+
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [
+ ["privacy.fingerprintingProtection", true],
+ [
+ "privacy.fingerprintingProtection.overrides",
+ "+WindowOuterSize,+ScreenRect,+ScreenAvailRect",
+ ],
+ ],
+ },
+ () => setFrameSource()
+ );
+ });
+ </script>
+ </body>
+</html>
=====================================
browser/components/resistfingerprinting/test/mochitest/test_iframe.html deleted
=====================================
@@ -1,18 +0,0 @@
-<!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>
=====================================
docshell/base/BrowsingContext.h
=====================================
@@ -272,7 +272,10 @@ struct EmbedderColorSchemes {
/* If true, this browsing context is within a hidden embedded document. */ \
FIELD(IsUnderHiddenEmbedderElement, bool) \
/* If true, this browsing context is offline */ \
- FIELD(ForceOffline, bool)
+ FIELD(ForceOffline, bool) \
+ /* Used to propagate window.top's inner size for RFPTarget::Window* \
+ * protections */ \
+ FIELD(TopInnerSizeForRFP, CSSIntSize)
// BrowsingContext, in this context, is the cross process replicated
// environment in which information about documents is stored. In
@@ -1253,6 +1256,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
bool CanSet(FieldIndex<IDX_ForceOffline>, bool aNewValue,
ContentParent* aSource);
+ bool CanSet(FieldIndex<IDX_TopInnerSizeForRFP>, bool, ContentParent*) {
+ return IsTop();
+ }
+
bool CanSet(FieldIndex<IDX_EmbeddedInContentDocument>, bool,
ContentParent* aSource) {
return CheckOnlyEmbedderCanSet(aSource);
=====================================
docshell/base/CanonicalBrowsingContext.cpp
=====================================
@@ -324,6 +324,7 @@ void CanonicalBrowsingContext::ReplacedBy(
txn.SetHasRestoreData(GetHasRestoreData());
txn.SetShouldDelayMediaFromStart(GetShouldDelayMediaFromStart());
txn.SetForceOffline(GetForceOffline());
+ txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP());
// Propagate some settings on BrowsingContext replacement so they're not lost
// on bfcached navigations. These are important for GeckoView (see bug
=====================================
dom/base/nsGlobalWindowOuter.cpp
=====================================
@@ -3513,9 +3513,10 @@ CSSIntSize nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType,
ErrorResult& aError) {
if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
RFPTarget::WindowOuterSize)) {
- CSSSize size;
- aError = GetInnerSize(size);
- return RoundedToInt(size);
+ if (BrowsingContext* bc = GetBrowsingContext()) {
+ return bc->Top()->GetTopInnerSizeForRFP();
+ }
+ return {};
}
// Windows showing documents in RDM panes and any subframes within them
=====================================
dom/base/nsScreen.cpp
=====================================
@@ -62,7 +62,7 @@ nsDeviceContext* nsScreen::GetDeviceContext() const {
CSSIntRect nsScreen::GetRect() {
// Return window inner rect to prevent fingerprinting.
if (ShouldResistFingerprinting(RFPTarget::ScreenRect)) {
- return GetWindowInnerRect();
+ return GetTopWindowInnerRectForRFP();
}
// Here we manipulate the value of aRect to represent the screen size,
@@ -91,7 +91,7 @@ CSSIntRect nsScreen::GetRect() {
CSSIntRect nsScreen::GetAvailRect() {
// Return window inner rect to prevent fingerprinting.
if (ShouldResistFingerprinting(RFPTarget::ScreenAvailRect)) {
- return GetWindowInnerRect();
+ return GetTopWindowInnerRectForRFP();
}
// Here we manipulate the value of aRect to represent the screen size,
@@ -165,18 +165,14 @@ JSObject* nsScreen::WrapObject(JSContext* aCx,
return Screen_Binding::Wrap(aCx, this, aGivenProto);
}
-CSSIntRect nsScreen::GetWindowInnerRect() {
- nsCOMPtr<nsPIDOMWindowInner> win = GetOwner();
- if (!win) {
- return {};
- }
- double width;
- double height;
- if (NS_FAILED(win->GetInnerWidth(&width)) ||
- NS_FAILED(win->GetInnerHeight(&height))) {
- return {};
+CSSIntRect nsScreen::GetTopWindowInnerRectForRFP() {
+ if (nsPIDOMWindowInner* inner = GetOwner()) {
+ if (BrowsingContext* bc = inner->GetBrowsingContext()) {
+ CSSIntSize size = bc->Top()->GetTopInnerSizeForRFP();
+ return {0, 0, size.width, size.height};
+ }
}
- return {0, 0, int32_t(std::round(width)), int32_t(std::round(height))};
+ return {};
}
bool nsScreen::ShouldResistFingerprinting(RFPTarget aTarget) const {
=====================================
dom/base/nsScreen.h
=====================================
@@ -88,7 +88,7 @@ class nsScreen : public mozilla::DOMEventTargetHelper {
nsDeviceContext* GetDeviceContext() const;
mozilla::CSSIntRect GetRect();
mozilla::CSSIntRect GetAvailRect();
- mozilla::CSSIntRect GetWindowInnerRect();
+ mozilla::CSSIntRect GetTopWindowInnerRectForRFP();
private:
virtual ~nsScreen();
=====================================
dom/base/test/chrome/bug418986-1.js
=====================================
@@ -24,14 +24,14 @@ var test = function (isContent) {
["mozInnerScreenY", 0],
["screen.pixelDepth", 24],
["screen.colorDepth", 24],
- ["screen.availWidth", "innerWidth"],
- ["screen.availHeight", "innerHeight"],
+ ["screen.availWidth", "outerWidth"],
+ ["screen.availHeight", "outerHeight"],
["screen.left", 0],
["screen.top", 0],
["screen.availLeft", 0],
["screen.availTop", 0],
- ["screen.width", "innerWidth"],
- ["screen.height", "innerHeight"],
+ ["screen.width", "outerWidth"],
+ ["screen.height", "outerHeight"],
["screen.orientation.type", "'landscape-primary'"],
["screen.orientation.angle", 0],
["screen.mozOrientation", "'landscape-primary'"],
=====================================
layout/base/nsPresContext.cpp
=====================================
@@ -1459,6 +1459,32 @@ void nsPresContext::SetOverrideDPPX(float aDPPX) {
MediaFeatureChangePropagation::JustThisDocument);
}
+void nsPresContext::UpdateTopInnerSizeForRFP() {
+ if (!mDocument->ShouldResistFingerprinting(RFPTarget::WindowOuterSize) ||
+ !mDocument->GetBrowsingContext() ||
+ !mDocument->GetBrowsingContext()->IsTop()) {
+ return;
+ }
+
+ CSSSize size = CSSPixel::FromAppUnits(GetVisibleArea().Size());
+
+ switch (StaticPrefs::dom_innerSize_rounding()) {
+ case 1:
+ size.width = std::roundf(size.width);
+ size.height = std::roundf(size.height);
+ break;
+ case 2:
+ size.width = std::truncf(size.width);
+ size.height = std::truncf(size.height);
+ break;
+ default:
+ break;
+ }
+
+ Unused << mDocument->GetBrowsingContext()->SetTopInnerSizeForRFP(
+ CSSIntSize{(int)size.width, (int)size.height});
+}
+
gfxSize nsPresContext::ScreenSizeInchesForFontInflation(bool* aChanged) {
if (aChanged) {
*aChanged = false;
@@ -2972,6 +2998,8 @@ void nsPresContext::SetVisibleArea(const nsRect& r) {
{mozilla::MediaFeatureChangeReason::ViewportChange},
MediaFeatureChangePropagation::JustThisDocument);
}
+
+ UpdateTopInnerSizeForRFP();
}
}
=====================================
layout/base/nsPresContext.h
=====================================
@@ -540,6 +540,7 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
void SetFullZoom(float aZoom);
void SetOverrideDPPX(float);
void SetInRDMPane(bool aInRDMPane);
+ void UpdateTopInnerSizeForRFP();
public:
float GetFullZoom() { return mFullZoom; }
=====================================
toolkit/components/resistfingerprinting/tests/browser/browser_fingerprintingWebCompat.js
=====================================
@@ -34,12 +34,12 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "*",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: true,
firstParty: true,
thirdParty: true,
@@ -57,12 +57,12 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.com",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: true,
firstParty: true,
thirdParty: false,
@@ -80,13 +80,13 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.com",
thirdPartyDomain: "*",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: true,
firstParty: true,
thirdParty: true,
@@ -104,13 +104,13 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.com",
thirdPartyDomain: "example.org",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: false,
firstParty: false,
thirdParty: true,
@@ -128,13 +128,13 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "*",
thirdPartyDomain: "example.org",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: false,
firstParty: false,
thirdParty: true,
@@ -153,12 +153,12 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.net",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: false,
firstParty: false,
thirdParty: false,
@@ -177,13 +177,13 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.net",
thirdPartyDomain: "*",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: false,
firstParty: false,
thirdParty: false,
@@ -202,13 +202,13 @@ const TEST_CASES = [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.net",
thirdPartyDomain: "example.com",
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: false,
firstParty: false,
thirdParty: false,
@@ -221,13 +221,13 @@ const TEST_CASES = [
},
},
// Test multiple entries that enable HW concurrency in the first-party context
- // and WindowOuter in the third-party context.
+ // and ScreenAvailRect in the third-party context.
{
entires: [
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.com",
},
{
@@ -239,7 +239,7 @@ const TEST_CASES = [
},
],
expects: {
- windowOuter: {
+ screenAvailRect: {
top: true,
firstParty: true,
thirdParty: false,
@@ -335,22 +335,22 @@ async function openAndSetupTestPageForPopup() {
}
async function verifyResultInTab(tab, firstPartyBC, thirdPartyBC, expected) {
- let testWindowOuter = enabled => {
+ let testScreenAvailRect = enabled => {
if (enabled) {
ok(
- content.wrappedJSObject.outerHeight ==
- content.wrappedJSObject.innerHeight &&
- content.wrappedJSObject.outerWidth ==
- content.wrappedJSObject.innerWidth,
- "Fingerprinting target WindowOuterSize is enabled for WindowOuterSize."
+ content.wrappedJSObject.screen.availHeight ==
+ content.wrappedJSObject.screen.height &&
+ content.wrappedJSObject.screen.availWidth ==
+ content.wrappedJSObject.screen.width,
+ "Fingerprinting target ScreenAvailRect is enabled for ScreenAvailRect."
);
} else {
ok(
- content.wrappedJSObject.outerHeight !=
- content.wrappedJSObject.innerHeight ||
- content.wrappedJSObject.outerWidth !=
- content.wrappedJSObject.innerWidth,
- "Fingerprinting target WindowOuterSize is not enabled for WindowOuterSize."
+ content.wrappedJSObject.screen.availHeight !=
+ content.wrappedJSObject.screen.height ||
+ content.wrappedJSObject.screen.availWidth !=
+ content.wrappedJSObject.screen.width,
+ "Fingerprinting target ScreenAvailRect is not enabled for ScreenAvailRect."
);
}
};
@@ -370,8 +370,8 @@ async function verifyResultInTab(tab, firstPartyBC, thirdPartyBC, expected) {
);
await SpecialPowers.spawn(
tab.linkedBrowser,
- [expected.windowOuter.top],
- testWindowOuter
+ [expected.screenAvailRect.top],
+ testScreenAvailRect
);
let expectHWConcurrencyTop = expected.hwConcurrency.top
? SPOOFED_HW_CONCURRENCY
@@ -401,8 +401,8 @@ async function verifyResultInTab(tab, firstPartyBC, thirdPartyBC, expected) {
);
await SpecialPowers.spawn(
firstPartyBC,
- [expected.windowOuter.firstParty],
- testWindowOuter
+ [expected.screenAvailRect.firstParty],
+ testScreenAvailRect
);
let expectHWConcurrencyFirstParty = expected.hwConcurrency.firstParty
? SPOOFED_HW_CONCURRENCY
@@ -432,8 +432,8 @@ async function verifyResultInTab(tab, firstPartyBC, thirdPartyBC, expected) {
);
await SpecialPowers.spawn(
thirdPartyBC,
- [expected.windowOuter.thirdParty],
- testWindowOuter
+ [expected.screenAvailRect.thirdParty],
+ testScreenAvailRect
);
let expectHWConcurrencyThirdParty = expected.hwConcurrency.thirdParty
? SPOOFED_HW_CONCURRENCY
@@ -517,7 +517,7 @@ add_task(async function test_popup_inheritance() {
{
id: "1",
last_modified: 1000000000000001,
- overrides: "+WindowOuterSize",
+ overrides: "+ScreenRect,+ScreenAvailRect",
firstPartyDomain: "example.com",
thirdPartyDomain: "example.org",
},
@@ -532,22 +532,22 @@ add_task(async function test_popup_inheritance() {
// 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."
+ content.wrappedJSObject.screen.availHeight ==
+ content.wrappedJSObject.screen.height &&
+ content.wrappedJSObject.screen.availWidth ==
+ content.wrappedJSObject.screen.width,
+ "Fingerprinting target ScreenAvailRect 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.wrappedJSObject.screen.availHeight ==
+ content.wrappedJSObject.screen.height &&
+ content.wrappedJSObject.screen.availWidth ==
+ content.wrappedJSObject.screen.width,
+ "Fingerprinting target ScreenAvailRect is enabled for the pop-up."
);
content.close();
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/f5fe75011abe1a00f58cc723c6842c209a023218
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/f5fe75011abe1a00f58cc723c6842c209a023218
You're receiving this email because of your account on gitlab.torproject.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tor-commits/attachments/20240902/259fe556/attachment-0001.htm>
More information about the tor-commits
mailing list