| author | Kathy Brade <brade@pearlcrescent.com> |
| Sun, 07 Jun 2015 09:02:00 -0400 | |
| changeset 247632 | 3abb08512b2435c53e63dcba2843d0df66391a55 |
| parent 247631 | a9cff1d9e7c6a9a698522ee4cd9ddbac39cb0b07 |
| child 247633 | 98ada2157a8e70798186e3a9bf15b3a9832fab0c |
| push id | 28874 |
| push user | ryanvm@gmail.com |
| push date | Tue, 09 Jun 2015 16:52:27 +0000 |
| treeherder | mozilla-central@76ae244b637a [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | mrbkap, heycam |
| bugs | 418986 |
| milestone | 41.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -248,16 +248,17 @@ bool nsContentUtils::sInitialized = fals bool nsContentUtils::sIsFullScreenApiEnabled = false; bool nsContentUtils::sTrustedFullScreenOnly = true; bool nsContentUtils::sIsCutCopyAllowed = true; bool nsContentUtils::sIsPerformanceTimingEnabled = false; bool nsContentUtils::sIsResourceTimingEnabled = false; bool nsContentUtils::sIsUserTimingLoggingEnabled = false; bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false; bool nsContentUtils::sEncodeDecodeURLHash = false; +bool nsContentUtils::sPrivacyResistFingerprinting = false; uint32_t nsContentUtils::sHandlingInputTimeout = 1000; nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; nsIParser* nsContentUtils::sXMLFragmentParser = nullptr; nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; bool nsContentUtils::sFragmentParsingActive = false; @@ -528,16 +529,19 @@ nsContentUtils::Init() "dom.performance.enable_user_timing_logging", false); Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled, "dom.forms.autocomplete.experimental", false); Preferences::AddBoolVarCache(&sEncodeDecodeURLHash, "dom.url.encode_decode_hash", false); + Preferences::AddBoolVarCache(&sPrivacyResistFingerprinting, + "privacy.resistFingerprinting", false); + Preferences::AddUintVarCache(&sHandlingInputTimeout, "dom.event.handling-user-input-time-limit", 1000); #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled, "browser.dom.window.dump.enabled"); #endif @@ -1984,16 +1988,26 @@ nsContentUtils::IsCallerChrome() if (SubjectPrincipal() == sSystemPrincipal) { return true; } // If the check failed, look for UniversalXPConnect on the cx compartment. return xpc::IsUniversalXPConnectEnabled(GetCurrentJSContext()); } +bool +nsContentUtils::ShouldResistFingerprinting(nsIDocShell* aDocShell) +{ + if (!aDocShell) { + return false; + } + bool isChrome = nsContentUtils::IsChromeDoc(aDocShell->GetDocument()); + return !isChrome && sPrivacyResistFingerprinting; +} + namespace mozilla { namespace dom { namespace workers { extern bool IsCurrentThreadRunningChromeWorker(); extern JSContext* GetCurrentThreadJSContext(); } } }
--- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -194,16 +194,19 @@ public: static bool IsCallerContentXBL(); static bool IsImageSrcSetDisabled(); static bool LookupBindingMember(JSContext* aCx, nsIContent *aContent, JS::Handle<jsid> aId, JS::MutableHandle<JSPropertyDescriptor> aDesc); + // Check whether we should avoid leaking distinguishing information to JS/CSS. + static bool ShouldResistFingerprinting(nsIDocShell* aDocShell); + /** * Returns the parent node of aChild crossing document boundaries. * Uses the parent node in the composed document. */ static nsINode* GetCrossDocParentNode(nsINode* aChild); /** * Do not ever pass null pointers to this method. If one of your @@ -1908,16 +1911,26 @@ public: * Returns true if URL setters should percent encode the Hash/Ref segment * and getters should return the percent decoded value of the segment */ static bool EncodeDecodeURLHash() { return sEncodeDecodeURLHash; } + /* + * Returns true if the browser should attempt to prevent content scripts + * from collecting distinctive information about the browser that could + * be used to "fingerprint" and track the user across websites. + */ + static bool ResistFingerprinting() + { + return sPrivacyResistFingerprinting; + } + /** * Returns true if the doc tree branch which contains aDoc contains any * plugins which we don't control event dispatch for, i.e. do any plugins * in the same tab as this document receive key events outside of our * control? This always returns false on MacOSX. */ static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc); @@ -2448,16 +2461,17 @@ private: static bool sTrustedFullScreenOnly; static bool sIsCutCopyAllowed; static uint32_t sHandlingInputTimeout; static bool sIsPerformanceTimingEnabled; static bool sIsResourceTimingEnabled; static bool sIsUserTimingLoggingEnabled; static bool sIsExperimentalAutocompleteEnabled; static bool sEncodeDecodeURLHash; + static bool sPrivacyResistFingerprinting; static nsHtml5StringParser* sHTMLFragmentParser; static nsIParser* sXMLFragmentParser; static nsIFragmentContentSink* sXMLFragmentSink; /** * True if there's a fragment parser activation on the stack. */
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -4998,16 +4998,22 @@ nsGlobalWindow::SetInnerHeight(int32_t a return rv.StealNSResult(); } nsIntSize nsGlobalWindow::GetOuterSize(ErrorResult& aError) { MOZ_ASSERT(IsOuterWindow()); + if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) { + CSSIntSize size; + aError = GetInnerSize(size); + return nsIntSize(size.width, size.height); + } + nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow(); if (!treeOwnerAsWin) { aError.Throw(NS_ERROR_FAILURE); return nsIntSize(0, 0); } nsGlobalWindow* rootWindow = static_cast<nsGlobalWindow *>(GetPrivateRoot()); @@ -5162,16 +5168,21 @@ nsGlobalWindow::SetOuterHeight(int32_t a return rv.StealNSResult(); } nsIntPoint nsGlobalWindow::GetScreenXY(ErrorResult& aError) { MOZ_ASSERT(IsOuterWindow()); + // When resisting fingerprinting, always return (0,0) + if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) { + return nsIntPoint(0, 0); + } + nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow(); if (!treeOwnerAsWin) { aError.Throw(NS_ERROR_FAILURE); return nsIntPoint(0, 0); } int32_t x = 0, y = 0; aError = treeOwnerAsWin->GetPosition(&x, &y); @@ -5235,16 +5246,21 @@ nsGlobalWindow::GetInnerScreenRect() return rootFrame->GetScreenRectInAppUnits(); } float nsGlobalWindow::GetMozInnerScreenX(ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenX, (aError), aError, 0); + // When resisting fingerprinting, always return 0. + if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) { + return 0.0; + } + nsRect r = GetInnerScreenRect(); return nsPresContext::AppUnitsToFloatCSSPixels(r.x); } NS_IMETHODIMP nsGlobalWindow::GetMozInnerScreenX(float* aScreenX) { ErrorResult rv; @@ -5253,16 +5269,21 @@ nsGlobalWindow::GetMozInnerScreenX(float return rv.StealNSResult(); } float nsGlobalWindow::GetMozInnerScreenY(ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenY, (aError), aError, 0); + // Return 0 to prevent fingerprinting. + if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) { + return 0.0; + } + nsRect r = GetInnerScreenRect(); return nsPresContext::AppUnitsToFloatCSSPixels(r.y); } NS_IMETHODIMP nsGlobalWindow::GetMozInnerScreenY(float* aScreenY) { ErrorResult rv; @@ -5281,16 +5302,20 @@ nsGlobalWindow::GetDevicePixelRatio(Erro } nsRefPtr<nsPresContext> presContext; mDocShell->GetPresContext(getter_AddRefs(presContext)); if (!presContext) { return 1.0; } + if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) { + return 1.0; + } + return float(nsPresContext::AppUnitsPerCSSPixel())/ presContext->AppUnitsPerDevPixel(); } NS_IMETHODIMP nsGlobalWindow::GetDevicePixelRatio(float* aRatio) { ErrorResult rv;
--- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -1054,16 +1054,18 @@ public: void Back(mozilla::ErrorResult& aError); void Forward(mozilla::ErrorResult& aError); void Home(mozilla::ErrorResult& aError); bool Find(const nsAString& aString, bool aCaseSensitive, bool aBackwards, bool aWrapAround, bool aWholeWord, bool aSearchInFrames, bool aShowDialog, mozilla::ErrorResult& aError); uint64_t GetMozPaintCount(mozilla::ErrorResult& aError); + bool ShouldResistFingerprinting(); + mozilla::dom::MozSelfSupport* GetMozSelfSupport(mozilla::ErrorResult& aError); already_AddRefed<nsIDOMWindow> OpenDialog(JSContext* aCx, const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions, const mozilla::dom::Sequence<JS::Value>& aExtraArgument, mozilla::ErrorResult& aError);
--- a/dom/base/nsScreen.cpp +++ b/dom/base/nsScreen.cpp @@ -63,16 +63,21 @@ NS_INTERFACE_MAP_BEGIN(nsScreen) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(nsScreen, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(nsScreen, DOMEventTargetHelper) int32_t nsScreen::GetPixelDepth(ErrorResult& aRv) { + // Return 24 to prevent fingerprinting. + if (ShouldResistFingerprinting()) { + return 24; + } + nsDeviceContext* context = GetDeviceContext(); if (!context) { aRv.Throw(NS_ERROR_FAILURE); return -1; } uint32_t depth; @@ -106,16 +111,21 @@ nsDeviceContext* nsScreen::GetDeviceContext() { return nsLayoutUtils::GetDeviceContextForScreenInfo(GetOwner()); } nsresult nsScreen::GetRect(nsRect& aRect) { + // Return window inner rect to prevent fingerprinting. + if (ShouldResistFingerprinting()) { + return GetWindowInnerRect(aRect); + } + nsDeviceContext *context = GetDeviceContext(); if (!context) { return NS_ERROR_FAILURE; } context->GetRect(aRect); @@ -125,16 +135,21 @@ nsScreen::GetRect(nsRect& aRect) aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width); return NS_OK; } nsresult nsScreen::GetAvailRect(nsRect& aRect) { + // Return window inner rect to prevent fingerprinting. + if (ShouldResistFingerprinting()) { + return GetWindowInnerRect(aRect); + } + nsDeviceContext *context = GetDeviceContext(); if (!context) { return NS_ERROR_FAILURE; } context->GetClientRect(aRect); @@ -161,32 +176,36 @@ nsScreen::Notify(const hal::ScreenConfig if (mOrientation != previousOrientation) { DispatchTrustedEvent(NS_LITERAL_STRING("mozorientationchange")); } } void nsScreen::GetMozOrientation(nsString& aOrientation) { - switch (mOrientation) { - case eScreenOrientation_PortraitPrimary: - aOrientation.AssignLiteral("portrait-primary"); - break; - case eScreenOrientation_PortraitSecondary: - aOrientation.AssignLiteral("portrait-secondary"); - break; - case eScreenOrientation_LandscapePrimary: + if (ShouldResistFingerprinting()) { aOrientation.AssignLiteral("landscape-primary"); - break; - case eScreenOrientation_LandscapeSecondary: - aOrientation.AssignLiteral("landscape-secondary"); - break; - case eScreenOrientation_None: - default: - MOZ_CRASH("Unacceptable mOrientation value"); + } else { + switch (mOrientation) { + case eScreenOrientation_PortraitPrimary: + aOrientation.AssignLiteral("portrait-primary"); + break; + case eScreenOrientation_PortraitSecondary: + aOrientation.AssignLiteral("portrait-secondary"); + break; + case eScreenOrientation_LandscapePrimary: + aOrientation.AssignLiteral("landscape-primary"); + break; + case eScreenOrientation_LandscapeSecondary: + aOrientation.AssignLiteral("landscape-secondary"); + break; + case eScreenOrientation_None: + default: + MOZ_CRASH("Unacceptable mOrientation value"); + } } } NS_IMETHODIMP nsScreen::GetSlowMozOrientation(nsAString& aOrientation) { nsString orientation; GetMozOrientation(orientation); @@ -368,8 +387,32 @@ nsScreen::FullScreenEventListener::Handl target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"), this, true); hal::UnlockScreenOrientation(); return NS_OK; } + +nsresult +nsScreen::GetWindowInnerRect(nsRect& aRect) +{ + aRect.x = 0; + aRect.y = 0; + nsCOMPtr<nsIDOMWindow> win = GetOwner(); + if (!win) { + return NS_ERROR_FAILURE; + } + nsresult rv = win->GetInnerWidth(&aRect.width); + NS_ENSURE_SUCCESS(rv, rv); + return win->GetInnerHeight(&aRect.height); +} + +bool nsScreen::ShouldResistFingerprinting() const +{ + bool resist = false; + nsCOMPtr<nsPIDOMWindow> owner = GetOwner(); + if (owner) { + resist = nsContentUtils::ShouldResistFingerprinting(owner->GetDocShell()); + } + return resist; +}
--- a/dom/base/nsScreen.h +++ b/dom/base/nsScreen.h @@ -126,16 +126,17 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration) override; protected: nsDeviceContext* GetDeviceContext(); nsresult GetRect(nsRect& aRect); nsresult GetAvailRect(nsRect& aRect); + nsresult GetWindowInnerRect(nsRect& aRect); mozilla::dom::ScreenOrientation mOrientation; private: class FullScreenEventListener final : public nsIDOMEventListener { ~FullScreenEventListener() {} public: @@ -153,12 +154,14 @@ private: FULLSCREEN_LOCK_ALLOWED, LOCK_ALLOWED }; LockPermission GetLockOrientationPermission() const; bool IsDeviceSizePageSize(); + bool ShouldResistFingerprinting() const; + nsRefPtr<FullScreenEventListener> mEventListener; }; #endif /* nsScreen_h___ */
new file mode 100644 --- /dev/null +++ b/dom/base/test/chrome/bug418986-1.js @@ -0,0 +1,71 @@ +// The main test function. +let test = function (isContent) { + SimpleTest.waitForExplicitFinish(); + + let { ww } = SpecialPowers.Services; + window.chromeWindow = ww.activeWindow; + + // The pairs of values expected to be the same when + // fingerprinting resistance is enabled. + let pairs = [ + ["screenX", 0], + ["screenY", 0], + ["mozInnerScreenX", 0], + ["mozInnerScreenY", 0], + ["screen.pixelDepth", 24], + ["screen.colorDepth", 24], + ["screen.availWidth", "innerWidth"], + ["screen.availHeight", "innerHeight"], + ["screen.left", 0], + ["screen.top", 0], + ["screen.availLeft", 0], + ["screen.availTop", 0], + ["screen.width", "innerWidth"], + ["screen.height", "innerHeight"], + ["screen.mozOrientation", "'landscape-primary'"], + ["devicePixelRatio", 1] + ]; + + // checkPair: tests if members of pair [a, b] are equal when evaluated. + let checkPair = function (a, b) { + is(eval(a), eval(b), a + " should be equal to " + b); + }; + + // Returns generator object that iterates through pref values. + let prefVals = (for (prefVal of [false, true]) prefVal); + + // The main test function, runs until all pref values are exhausted. + let nextTest = function () { + let {value : prefValue, done} = prefVals.next(); + if (done) { + SimpleTest.finish(); + return; + } + SpecialPowers.pushPrefEnv({set : [["privacy.resistFingerprinting", prefValue]]}, + function () { + // We will be resisting fingerprinting if the pref is enabled, + // and we are in a content script (not chrome). + let resisting = prefValue && isContent; + // Check each of the pairs. + pairs.map(function ([item, onVal]) { + if (resisting) { + checkPair("window." + item, onVal); + } else { + if (!item.startsWith("moz")) { + checkPair("window." + item, "chromeWindow." + item); + } + } + }); + if (!resisting) { + // Hard to predict these values, but we can enforce constraints: + ok(window.mozInnerScreenX >= chromeWindow.mozInnerScreenX, + "mozInnerScreenX"); + ok(window.mozInnerScreenY >= chromeWindow.mozInnerScreenY, + "mozInnerScreenY"); + } + nextTest(); + }); + } + + nextTest(); +}
--- a/dom/base/test/chrome/chrome.ini +++ b/dom/base/test/chrome/chrome.ini @@ -1,13 +1,14 @@ [DEFAULT] skip-if = buildapp == 'b2g' support-files = blockNoPlugins.xml blockPluginHard.xml + bug418986-1.js cpows_child.js cpows_parent.xul file_bug391728.html file_bug391728_2.html file_bug549682.xul file_bug616841.xul file_bug816340.xul file_bug990812-1.xul @@ -26,16 +27,17 @@ support-files = [test_bug206691.xul] [test_bug339494.xul] [test_bug357450.xul] [test_bug380418.html] [test_bug380418.html^headers^] [test_bug383430.html] [test_bug391728.html] +[test_bug418986-1.xul] [test_bug421622.xul] [test_bug429785.xul] [test_bug430050.xul] [test_bug467123.xul] [test_bug549682.xul] [test_bug571390.xul] [test_bug574596.html] [test_bug1098074_throw_from_ReceiveMessage.xul]
new file mode 100644 --- /dev/null +++ b/dom/base/test/chrome/test_bug418986-1.xul @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" + type="text/css"?> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=418986-1 +--> +<window title="Mozilla Bug 418986 (Part 1)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <!-- test results are displayed in the html:body --> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986-1" + target="_blank">Mozilla Bug 418986 (Part 1)</a> + + <script type="application/javascript;version=1.7" src="bug418986-1.js"></script> + <!-- test code goes here --> + <script type="application/javascript"><![CDATA[ + window.onload = function() { + test(false); + }; + ]]></script> + </body> +</window>
--- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -51,16 +51,17 @@ support-files = bug682592-subframe-ref.html bug682592-subframe.html bug696301-script-1.js bug696301-script-1.js^headers^ bug696301-script-2.js bug704320.sjs bug704320_counter.sjs bug819051.sjs + chrome/bug418986-1.js copypaste.js delayedServerEvents.sjs echo.sjs eventsource.resource eventsource.resource^headers^ eventsource_redirect.resource eventsource_redirect.resource^headers^ eventsource_redirect_to.resource @@ -448,16 +449,17 @@ support-files = test_bug402150.html^head [test_bug414190.html] [test_bug415860.html] [test_bug416317-1.html] [test_bug416317-2.html] [test_bug416383.html] [test_bug417255.html] [test_bug417384.html] [test_bug418214.html] +[test_bug418986-1.html] [test_bug419132.html] [test_bug419527.xhtml] [test_bug420609.xhtml] [test_bug420700.html] [test_bug421602.html] [test_bug422403-1.html] skip-if = buildapp == 'b2g' # b2g(bug 901343, specialpowers.wrap issue [nsIChannel.open]) b2g-debug(bug 901343, specialpowers.wrap issue [nsIChannel.open]) b2g-desktop(bug 901343, specialpowers.wrap issue [nsIChannel.open]) [test_bug422403-2.xhtml]
new file mode 100644 --- /dev/null +++ b/dom/base/test/test_bug418986-1.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=418986 +--> +<head> + <meta charset="utf-8"> + <title>Test 1/3 for Bug 418986 - Resist fingerprinting by preventing exposure of screen and system info</title> + <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;version=1.7" src="chrome/bug418986-1.js"></script> +</head> +<body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> + <script> + window.onload = function() { + test(true); + }; + </script> +</body> +</html>
--- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -885,16 +885,23 @@ Event::Shutdown() } } LayoutDeviceIntPoint Event::GetScreenCoords(nsPresContext* aPresContext, WidgetEvent* aEvent, LayoutDeviceIntPoint aPoint) { + if (!nsContentUtils::IsCallerChrome() && + nsContentUtils::ResistFingerprinting()) { + // When resisting fingerprinting, return client coordinates instead. + CSSIntPoint clientCoords = GetClientCoords(aPresContext, aEvent, aPoint, CSSIntPoint(0, 0)); + return LayoutDeviceIntPoint(clientCoords.x, clientCoords.y); + } + if (EventStateManager::sIsPointerLocked) { return EventStateManager::sLastScreenPoint; } if (!aEvent || (aEvent->mClass != eMouseEventClass && aEvent->mClass != eMouseScrollEventClass && aEvent->mClass != eWheelEventClass &&
new file mode 100644 --- /dev/null +++ b/dom/events/test/bug418986-3.js @@ -0,0 +1,69 @@ +SimpleTest.waitForExplicitFinish(); + +// The main testing function. +let test = function (isContent) { + // Each definition is [eventType, prefSetting] + // Where we are setting the "privacy.resistFingerprinting" pref. + let eventDefs = [["mousedown", true], + ["mouseup", true], + ["mousedown", false], + ["mouseup", false]]; + + let testCounter = 0; + + // Declare ahead of time. + let setup; + + // This function is called when the event handler fires. + let handleEvent = function (event, prefVal) { + let resisting = prefVal && isContent; + if (resisting) { + is(event.screenX, event.clientX, "event.screenX and event.clientX should be the same"); + is(event.screenY, event.clientY, "event.screenY and event.clientY should be the same"); + } else { + // We can't be sure about X coordinates not being equal, but we can test Y. + isnot(event.screenY, event.clientY, "event.screenY !== event.clientY"); + } + ++testCounter; + if (testCounter < eventDefs.length) { + nextTest(); + } else { + SimpleTest.finish(); + } + }; + + // In this function, we set up the nth div and event handler, + // and then synthesize a mouse event in the div, to test + // whether the resulting events resist fingerprinting by + // suppressing absolute screen coordinates. + nextTest = function () { + let [eventType, prefVal] = eventDefs[testCounter]; + SpecialPowers.pushPrefEnv({set:[["privacy.resistFingerprinting", prefVal]]}, + function () { + // The following code creates a new div for each event in eventDefs, + // attaches a listener to listen for the event, and then generates + // a fake event at the center of the div. + let div = document.createElement("div"); + div.style.width = "10px"; + div.style.height = "10px"; + div.style.backgroundColor = "red"; + // Name the div after the event we're listening for. + div.id = eventType; + document.getElementById("body").appendChild(div); + // Seems we can't add an event listener in chrome unless we run + // it in a later task. + window.setTimeout(function() { + div.addEventListener(eventType, event => handleEvent(event, prefVal), false); + // For some reason, the following synthesizeMouseAtCenter call only seems to run if we + // wrap it in a window.setTimeout(..., 0). + window.setTimeout(function () { + synthesizeMouseAtCenter(div, {type : eventType}); + }, 0); + }, 0); + }); + }; + + // Now run by starting with the 0th event. + nextTest(); + +};
--- a/dom/events/test/chrome.ini +++ b/dom/events/test/chrome.ini @@ -1,22 +1,24 @@ [DEFAULT] skip-if = buildapp == 'b2g' support-files = bug415498-doc1.html bug415498-doc2.html + bug418986-3.js bug591249_iframe.xul bug602962.xul file_bug679494.html window_bug617528.xul test_bug336682.js [test_bug336682_2.xul] [test_bug368835.html] [test_bug415498.xul] +[test_bug418986-3.xul] [test_bug524674.xul] [test_bug586961.xul] [test_bug591249.xul] [test_bug602962.xul] [test_bug617528.xul] [test_bug679494.xul] [test_bug930374-chrome.html] [test_bug1128787-1.html]
--- a/dom/events/test/mochitest.ini +++ b/dom/events/test/mochitest.ini @@ -2,16 +2,17 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM support-files = bug226361_iframe.xhtml bug299673.js bug322588-popup.html bug426082.html bug648573.html bug656379-1.html + bug418986-3.js error_event_worker.js empty.js window_bug493251.html window_bug659071.html window_wheel_default_action.html [test_accel_virtual_modifier.html] [test_addEventListenerExtraArg.html] @@ -33,16 +34,19 @@ support-files = test_bug336682.js [test_bug368835.html] [test_bug379120.html] [test_bug391568.xhtml] [test_bug402089.html] [test_bug405632.html] [test_bug409604.html] skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT [test_bug412567.html] +[test_bug418986-3.html] +# Sometimes fails to finish after tests pass on 'B2G ICS Emulator'. +skip-if = (os == 'b2g') [test_bug422132.html] skip-if = buildapp == 'b2g' || e10s # b2g(2 failures out of 8, mousewheel test) b2g-debug(2 failures out of 8, mousewheel test) b2g-desktop(2 failures out of 8, mousewheel test) [test_bug426082.html] skip-if = buildapp == 'mulet' || buildapp == 'b2g' || os == "win" || toolkit == 'android' || e10s # Intermittent failures, bug 921693 # b2g(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-debug(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-desktop(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) [test_bug427537.html] [test_bug428988.html] [test_bug432698.html] skip-if = buildapp == 'mulet'
new file mode 100644 --- /dev/null +++ b/dom/events/test/test_bug418986-3.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=418986 +--> +<head> + <meta charset="utf-8"> + <title>Test 3/3 for Bug 418986 - Resist fingerprinting by preventing exposure of screen and system info</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body id="body"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a> +<p id="display"></p> +<pre id="test"></pre> +<script type="application/javascript;version=1.7" src="bug418986-3.js"></script> +<script type="application/javascript;version=1.7"> + // This test produces fake mouse events and checks that the screenX and screenY + // properties of the received event objects provide client window coordinates. + // Run the test once the window has loaded. + window.onload = () => test(true); +</script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/events/test/test_bug418986-3.xul @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> +<!-- +Bug 418986 +--> +<window title="Mozilla Bug 418986" + xmlns:html="http://www.w3.org/1999/xhtml" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + +<body id="body" xmlns="http://www.w3.org/1999/xhtml"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986"> +Mozilla Bug 418986</a> +</body> + +<script type="application/javascript;version=1.7" src="bug418986-3.js"></script> +<script type="application/javascript;version=1.7"><![CDATA[ + // This test produces fake mouse events and checks that the screenX and screenY + // properties of the received event objects provide client window coordinates. + // Run the test once the window has loaded. + test(false); +]]></script> + +</window>
--- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -1445,16 +1445,20 @@ nsComputedDOMStyle::DoGetFontSizeAdjust( } return val; } CSSValue* nsComputedDOMStyle::DoGetOsxFontSmoothing() { + if (nsContentUtils::ShouldResistFingerprinting( + mPresShell->GetPresContext()->GetDocShell())) + return nullptr; + nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing, nsCSSProps::kFontSmoothingKTable)); return val; } CSSValue* nsComputedDOMStyle::DoGetFontStretch()
--- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -104,23 +104,29 @@ GetDeviceContextFor(nsPresContext* aPres // It would be nice to call // nsLayoutUtils::GetDeviceContextForScreenInfo here, except for two // things: (1) it can flush, and flushing is bad here, and (2) it // doesn't really get us consistency in multi-monitor situations // *anyway*. return aPresContext->DeviceContext(); } +static bool +ShouldResistFingerprinting(nsPresContext* aPresContext) +{ + return nsContentUtils::ShouldResistFingerprinting(aPresContext->GetDocShell()); +} + // A helper for three features below. static nsSize GetDeviceSize(nsPresContext* aPresContext) { nsSize size; - if (aPresContext->IsDeviceSizePageSize()) { + if (ShouldResistFingerprinting(aPresContext) || aPresContext->IsDeviceSizePageSize()) { size = GetSize(aPresContext); } else if (aPresContext->IsRootPaginatedDocument()) { // We want the page size, including unprintable areas and margins. // XXX The spec actually says we want the "page sheet size", but // how is that different? size = aPresContext->GetPageSize(); } else { GetDeviceContextFor(aPresContext)-> @@ -218,23 +224,27 @@ GetDeviceAspectRatio(nsPresContext* aPre { return MakeArray(GetDeviceSize(aPresContext), aResult); } static nsresult GetColor(nsPresContext* aPresContext, const nsMediaFeature*, nsCSSValue& aResult) { - // FIXME: This implementation is bogus. nsDeviceContext - // doesn't provide reliable information (should be fixed in bug - // 424386). - // FIXME: On a monochrome device, return 0! - nsDeviceContext *dx = GetDeviceContextFor(aPresContext); - uint32_t depth; - dx->GetDepth(depth); + uint32_t depth = 24; // Use depth of 24 when resisting fingerprinting. + + if (!ShouldResistFingerprinting(aPresContext)) { + // FIXME: This implementation is bogus. nsDeviceContext + // doesn't provide reliable information (should be fixed in bug + // 424386). + // FIXME: On a monochrome device, return 0! + nsDeviceContext *dx = GetDeviceContextFor(aPresContext); + dx->GetDepth(depth); + } + // The spec says to use bits *per color component*, so divide by 3, // and round down, since the spec says to use the smallest when the // color components differ. depth /= 3; aResult.SetIntValue(int32_t(depth), eCSSUnit_Integer); return NS_OK; } @@ -262,20 +272,25 @@ GetMonochrome(nsPresContext* aPresContex aResult.SetIntValue(0, eCSSUnit_Integer); return NS_OK; } static nsresult GetResolution(nsPresContext* aPresContext, const nsMediaFeature*, nsCSSValue& aResult) { - // Resolution measures device pixels per CSS (inch/cm/pixel). We - // return it in device pixels per CSS inches. - float dpi = float(nsPresContext::AppUnitsPerCSSInch()) / - float(aPresContext->AppUnitsPerDevPixel()); + float dpi = 96; // Use 96 when resisting fingerprinting. + + if (!ShouldResistFingerprinting(aPresContext)) { + // Resolution measures device pixels per CSS (inch/cm/pixel). We + // return it in device pixels per CSS inches. + dpi = float(nsPresContext::AppUnitsPerCSSInch()) / + float(aPresContext->AppUnitsPerDevPixel()); + } + aResult.SetFloatValue(dpi, eCSSUnit_Inch); return NS_OK; } static nsresult GetScan(nsPresContext* aPresContext, const nsMediaFeature*, nsCSSValue& aResult) { @@ -294,38 +309,53 @@ GetGrid(nsPresContext* aPresContext, con aResult.SetIntValue(0, eCSSUnit_Integer); return NS_OK; } static nsresult GetDevicePixelRatio(nsPresContext* aPresContext, const nsMediaFeature*, nsCSSValue& aResult) { - float ratio = aPresContext->CSSPixelsToDevPixels(1.0f); - aResult.SetFloatValue(ratio, eCSSUnit_Number); - return NS_OK; + if (!ShouldResistFingerprinting(aPresContext)) { + float ratio = aPresContext->CSSPixelsToDevPixels(1.0f); + aResult.SetFloatValue(ratio, eCSSUnit_Number); + } else { + aResult.SetFloatValue(1.0, eCSSUnit_Number); + } + return NS_OK; } static nsresult GetSystemMetric(nsPresContext* aPresContext, const nsMediaFeature* aFeature, nsCSSValue& aResult) { + aResult.Reset(); + if (ShouldResistFingerprinting(aPresContext)) { + // If "privacy.resistFingerprinting" is enabled, then we simply don't + // return any system-backed media feature values. (No spoofed values returned.) + return NS_OK; + } + MOZ_ASSERT(aFeature->mValueType == nsMediaFeature::eBoolInteger, "unexpected type"); nsIAtom *metricAtom = *aFeature->mData.mMetric; bool hasMetric = nsCSSRuleProcessor::HasSystemMetric(metricAtom); aResult.SetIntValue(hasMetric ? 1 : 0, eCSSUnit_Integer); return NS_OK; } static nsresult GetWindowsTheme(nsPresContext* aPresContext, const nsMediaFeature* aFeature, nsCSSValue& aResult) { aResult.Reset(); + if (ShouldResistFingerprinting(aPresContext)) { + return NS_OK; + } + #ifdef XP_WIN uint8_t windowsThemeId = nsCSSRuleProcessor::GetWindowsThemeIdentifier(); // Classic mode should fail to match. if (windowsThemeId == LookAndFeel::eWindowsTheme_Classic) return NS_OK; @@ -341,16 +371,20 @@ GetWindowsTheme(nsPresContext* aPresCont return NS_OK; } static nsresult GetOperatinSystemVersion(nsPresContext* aPresContext, const nsMediaFeature* aFeature, nsCSSValue& aResult) { aResult.Reset(); + if (ShouldResistFingerprinting(aPresContext)) { + return NS_OK; + } + #ifdef XP_WIN int32_t metricResult; if (NS_SUCCEEDED( LookAndFeel::GetInt(LookAndFeel::eIntID_OperatingSystemVersionIdentifier, &metricResult))) { for (size_t i = 0; i < ArrayLength(osVersionStrings); ++i) { if (metricResult == osVersionStrings[i].id) { aResult.SetStringValue(nsDependentString(osVersionStrings[i].name),
new file mode 100644 --- /dev/null +++ b/layout/style/test/chrome/bug418986-2.js @@ -0,0 +1,274 @@ +// # Bug 418986, part 2. + +/* jshint esnext:true */ +/* jshint loopfunc:true */ +/* global window, screen, ok, SpecialPowers, matchMedia */ + +SimpleTest.waitForExplicitFinish(); + +// Expected values. Format: [name, pref_off_value, pref_on_value] +// If pref_*_value is an array with two values, then we will match +// any value in between those two values. If a value is null, then +// we skip the media query. +let expected_values = [ + ["color", null, 8], + ["color-index", null, 0], + ["aspect-ratio", null, window.innerWidth + "/" + window.innerHeight], + ["device-aspect-ratio", screen.width + "/" + screen.height, + window.innerWidth + "/" + window.innerHeight], + ["device-height", screen.height + "px", window.innerHeight + "px"], + ["device-width", screen.width + "px", window.innerWidth + "px"], + ["grid", null, 0], + ["height", window.innerHeight + "px", window.innerHeight + "px"], + ["monochrome", null, 0], + // Square is defined as portrait: + ["orientation", null, + window.innerWidth > window.innerHeight ? + "landscape" : "portrait"], + ["resolution", null, "96dpi"], + ["resolution", [0.999 * window.devicePixelRatio + "dppx", + 1.001 * window.devicePixelRatio + "dppx"], "1dppx"], + ["width", window.innerWidth + "px", window.innerWidth + "px"], + ["-moz-device-pixel-ratio", window.devicePixelRatio, 1], + ["-moz-device-orientation", screen.width > screen.height ? + "landscape" : "portrait", + window.innerWidth > window.innerHeight ? + "landscape" : "portrait"] +]; + +// These media queries return value 0 or 1 when the pref is off. +// When the pref is on, they should not match. +let suppressed_toggles = [ + "-moz-images-in-menus", + "-moz-mac-graphite-theme", + // Not available on most OSs. +// "-moz-maemo-classic", + "-moz-scrollbar-end-backward", + "-moz-scrollbar-end-forward", + "-moz-scrollbar-start-backward", + "-moz-scrollbar-start-forward", + "-moz-scrollbar-thumb-proportional", + "-moz-touch-enabled", + "-moz-windows-compositor", + "-moz-windows-default-theme", + "-moz-windows-glass", +]; + +// Possible values for '-moz-os-version' +let windows_versions = [ + "windows-xp", + "windows-vista", + "windows-win7", + "windows-win8"]; + +// Possible values for '-moz-windows-theme' +let windows_themes = [ + "aero", + "luna-blue", + "luna-olive", + "luna-silver", + "royale", + "generic", + "zune" +]; + +// Read the current OS. +let OS = SpecialPowers.Services.appinfo.OS; + +// If we are using Windows, add an extra toggle only +// available on that OS. +if (OS === "WINNT") { + suppressed_toggles.push("-moz-windows-classic"); +} + +// __keyValMatches(key, val)__. +// Runs a media query and returns true if key matches to val. +let keyValMatches = (key, val) => matchMedia("(" + key + ":" + val +")").matches; + +// __testMatch(key, val)__. +// Attempts to run a media query match for the given key and value. +// If value is an array of two elements [min max], then matches any +// value in-between. +let testMatch = function (key, val) { + if (val === null) { + return; + } else if (Array.isArray(val)) { + ok(keyValMatches("min-" + key, val[0]) && keyValMatches("max-" + key, val[1]), + "Expected " + key + " between " + val[0] + " and " + val[1]); + } else { + ok(keyValMatches(key, val), "Expected " + key + ":" + val); + } +}; + +// __testToggles(resisting)__. +// Test whether we are able to match the "toggle" media queries. +let testToggles = function (resisting) { + suppressed_toggles.forEach( + function (key) { + var exists = keyValMatches(key, 0) || keyValMatches(key, 1); + if (resisting) { + ok(!exists, key + " should not exist."); + } else { + ok(exists, key + " should exist."); + } + }); +}; + +// __testWindowsSpecific__. +// Runs a media query on the queryName with the given possible matching values. +let testWindowsSpecific = function (resisting, queryName, possibleValues) { + let found = false; + possibleValues.forEach(function (val) { + found = found || keyValMatches(queryName, val); + }); + if (resisting) { + ok(!found, queryName + " should have no match"); + } else { + ok(found, queryName + " should match"); + } +}; + +// __generateHtmlLines(resisting)__. +// Create a series of div elements that look like: +// `<div class='spoof' id='resolution'>resolution</div>`, +// where each line corresponds to a different media query. +let generateHtmlLines = function (resisting) { + let lines = ""; + expected_values.forEach( + function ([key, offVal, onVal]) { + let val = resisting ? onVal : offVal; + if (val) { + lines += "<div class='spoof' id='" + key + "'>" + key + "</div>\n"; + } + }); + suppressed_toggles.forEach( + function (key) { + lines += "<div class='suppress' id='" + key + "'>" + key + "</div>\n"; + }); + if (OS === "WINNT") { + lines += "<div class='windows' id='-moz-os-version'>-moz-os-version</div>"; + lines += "<div class='windows' id='-moz-windows-theme'>-moz-windows-theme</div>"; + } + return lines; +}; + +// __cssLine__. +// Creates a line of css that looks something like +// `@media (resolution: 1ppx) { .spoof#resolution { background-color: green; } }`. +let cssLine = function (query, clazz, id, color) { + return "@media " + query + " { ." + clazz + "#" + id + + " { background-color: " + color + "; } }\n"; +}; + +// __mediaQueryCSSLine(key, val, color)__. +// Creates a line containing a CSS media query and a CSS expression. +let mediaQueryCSSLine = function (key, val, color) { + if (val === null) { + return ""; + } + let query; + if (Array.isArray(val)) { + query = "(min-" + key + ": " + val[0] + ") and (max-" + key + ": " + val[1] + ")"; + } else { + query = "(" + key + ": " + val + ")"; + } + return cssLine(query, "spoof", key, color); +}; + +// __suppressedMediaQueryCSSLine(key, color)__. +// Creates a CSS line that matches the existence of a +// media query that is supposed to be suppressed. +let suppressedMediaQueryCSSLine = function (key, color, suppressed) { + let query = "(" + key + ": 0), (" + key + ": 1)"; + return cssLine(query, "suppress", key, color); +}; + +// __generateCSSLines(resisting)__. +// Creates a series of lines of CSS, each of which corresponds to +// a different media query. If the query produces a match to the +// expected value, then the element will be colored green. +let generateCSSLines = function (resisting) { + let lines = ".spoof { background-color: red;}\n"; + expected_values.forEach( + function ([key, offVal, onVal]) { + lines += mediaQueryCSSLine(key, resisting ? onVal : offVal, "green"); + }); + lines += ".suppress { background-color: " + (resisting ? "green" : "red") + ";}\n"; + suppressed_toggles.forEach( + function (key) { + lines += suppressedMediaQueryCSSLine(key, resisting ? "red" : "green"); + }); + if (OS === "WINNT") { + lines += ".windows { background-color: " + (resisting ? "green" : "red") + ";}\n"; + lines += windows_versions.map(val => "(-moz-os-version: " + val + ")").join(", ") + + " { #-moz-os-version { background-color: " + (resisting ? "red" : "green") + ";} }\n"; + lines += windows_themes.map(val => "(-moz-windows-theme: " + val + ")").join(",") + + " { #-moz-windows-theme { background-color: " + (resisting ? "red" : "green") + ";} }\n"; + } + return lines; +}; + +// __green__. +// Returns the computed color style corresponding to green. +let green = (function () { + let temp = document.createElement("span"); + temp.style.backgroundColor = "green"; + return getComputedStyle(temp).backgroundColor; +})(); + +// __testCSS(resisting)__. +// Creates a series of divs and CSS using media queries to set their +// background color. If all media queries match as expected, then +// all divs should have a green background color. +let testCSS = function (resisting) { + document.getElementById("display").innerHTML = generateHtmlLines(resisting); + document.getElementById("test-css").innerHTML = generateCSSLines(resisting); + let cssTestDivs = document.querySelectorAll(".spoof,.suppress"); + for (let div of cssTestDivs) { + let color = window.getComputedStyle(div).backgroundColor; + ok(color === green, "CSS for '" + div.id + "'"); + } +}; + +// __testOSXFontSmoothing(resisting)__. +// When fingerprinting resistance is enabled, the `getComputedStyle` +// should always return `undefined` for `MozOSXFontSmoothing`. +let testOSXFontSmoothing = function (resisting) { + let div = document.createElement("div"); + div.style.MozOsxFontSmoothing = "unset"; + let readBack = window.getComputedStyle(div).MozOsxFontSmoothing; + let smoothingPref = SpecialPowers.getBoolPref("layout.css.osx-font-smoothing.enabled", false); + is(readBack, resisting ? "" : (smoothingPref ? "auto" : ""), + "-moz-osx-font-smoothing"); +}; + +// An iterator yielding pref values for two consecutive tests. +let prefVals = (for (prefVal of [false, true]) prefVal); + +// __test(isContent)__. +// Run all tests. +let test = function(isContent) { + let {value: prefValue, done} = prefVals.next(); + if (done) { + SimpleTest.finish(); + return; + } + SpecialPowers.pushPrefEnv({set: [["privacy.resistFingerprinting", prefValue]]}, + function () { + let resisting = prefValue && isContent; + expected_values.forEach( + function ([key, offVal, onVal]) { + testMatch(key, resisting ? onVal : offVal); + }); + testToggles(resisting); + if (OS === "WINNT") { + testWindowsSpecific(resisting, "-moz-os-version", windows_versions); + testWindowsSpecific(resisting, "-moz-windows-theme", windows_themes); + } + testCSS(resisting); + if (OS === "Darwin") { + testOSXFontSmoothing(resisting); + } + test(isContent); + }); +};
--- a/layout/style/test/chrome/chrome.ini +++ b/layout/style/test/chrome/chrome.ini @@ -1,17 +1,19 @@ [DEFAULT] skip-if = buildapp == 'b2g' support-files = + bug418986-2.js bug535806-css.css bug535806-html.html bug535806-xul.xul hover_helper.html [test_addSheet.html] [test_additional_sheets.html] [test_author_specified_style.html] +[test_bug418986-2.xul] [test_bug1157097.html] [test_bug1160724.xul] [test_bug535806.xul] [test_hover.html] skip-if = buildapp == 'mulet' [test_moz_document_rules.html]
new file mode 100644 --- /dev/null +++ b/layout/style/test/chrome/test_bug418986-2.xul @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=418986 +--> +<window title="Mozilla Bug 418986" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + <!-- test results are displayed in the html:body --> + <body xmlns="http://www.w3.org/1999/xhtml"> + <style id="test-css" scoped="true"></style> + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986" + target="_blank">Mozilla Bug 418986</a> + <p id="display"></p> + + </body> + + <script type="text/javascript;version=1.7" src="bug418986-2.js"></script> + <!-- test code goes here --> + <script type="text/javascript;version=1.7"> + // Run all tests now. + window.onload = function () { + test(false); + }; + </script> +</window>
--- a/layout/style/test/mochitest.ini +++ b/layout/style/test/mochitest.ini @@ -1,15 +1,16 @@ [DEFAULT] support-files = animation_utils.js ccd-quirks.html ccd.sjs ccd-standards.html css_properties.js + chrome/bug418986-2.js descriptor_database.js empty.html media_queries_dynamic_xbl_binding.xml media_queries_dynamic_xbl_iframe.html media_queries_dynamic_xbl_style.css media_queries_iframe.html neverending_font_load.sjs neverending_stylesheet_load.sjs @@ -70,16 +71,17 @@ skip-if = toolkit == 'android' [test_bug397427.html] [test_bug399349.html] [test_bug401046.html] skip-if = true # Bug 701060 [test_bug405818.html] [test_bug412901.html] skip-if = android_version == '18' # bug 1147986 [test_bug413958.html] +[test_bug418986-2.html] [test_bug437915.html] [test_bug450191.html] [test_bug453896_deck.html] support-files = bug453896_iframe.html [test_bug470769.html] [test_bug499655.html] [test_bug499655.xhtml] [test_bug511909.html]
new file mode 100644 --- /dev/null +++ b/layout/style/test/test_bug418986-2.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=418986 +--> +<head> + <meta charset="utf-8"> + <title>Test 2/3 for Bug #418986: Resist fingerprinting by preventing exposure of screen and system info</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style id="test-css"></style> + <script type="text/javascript;version=1.7" src="chrome/bug418986-2.js"></script> + <script type="text/javascript;version=1.7"> + // Run all tests now. + window.onload = function () { + test(true); + }; + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a> +<p id="display">TEST</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html>