Attachment #8616476: 0001-Bug-418986-Resist-fingerprinting-by-preventing-expos.patch for bug #418986

View | Details | Raw Unified | Return to bug 418986
Collapse All | Expand All

(-)a/dom/base/nsContentUtils.cpp (+14 lines)
Line     Link Here 
 Lines 252-257   bool nsContentUtils::sIsResourceTimingEnabled = false; Link Here 
252
bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
252
bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
253
bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
253
bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
254
bool nsContentUtils::sEncodeDecodeURLHash = false;
254
bool nsContentUtils::sEncodeDecodeURLHash = false;
255
bool nsContentUtils::sPrivacyResistFingerprinting = false;
255
256
256
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
257
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
257
258
 Lines 529-534   nsContentUtils::Init() Link Here 
529
  Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
530
  Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
530
                               "dom.url.encode_decode_hash", false);
531
                               "dom.url.encode_decode_hash", false);
531
532
533
  Preferences::AddBoolVarCache(&sPrivacyResistFingerprinting,
534
                               "privacy.resistFingerprinting", false);
535
532
  Preferences::AddUintVarCache(&sHandlingInputTimeout,
536
  Preferences::AddUintVarCache(&sHandlingInputTimeout,
533
                               "dom.event.handling-user-input-time-limit",
537
                               "dom.event.handling-user-input-time-limit",
534
                               1000);
538
                               1000);
 Lines 1985-1990   nsContentUtils::IsCallerChrome() Link Here 
1985
  return xpc::IsUniversalXPConnectEnabled(GetCurrentJSContext());
1989
  return xpc::IsUniversalXPConnectEnabled(GetCurrentJSContext());
1986
}
1990
}
1987
1991
1992
bool
1993
nsContentUtils::ShouldResistFingerprinting(nsIDocShell* aDocShell)
1994
{
1995
  if (!aDocShell) {
1996
    return false;
1997
  }
1998
  bool isChrome = nsContentUtils::IsChromeDoc(aDocShell->GetDocument());
1999
  return !isChrome && sPrivacyResistFingerprinting;
2000
}
2001
1988
namespace mozilla {
2002
namespace mozilla {
1989
namespace dom {
2003
namespace dom {
1990
namespace workers {
2004
namespace workers {
(-)a/dom/base/nsContentUtils.h (+14 lines)
Line     Link Here 
 Lines 198-203   public: Link Here 
198
                                  JS::Handle<jsid> aId,
198
                                  JS::Handle<jsid> aId,
199
                                  JS::MutableHandle<JSPropertyDescriptor> aDesc);
199
                                  JS::MutableHandle<JSPropertyDescriptor> aDesc);
200
200
201
  // Check whether we should avoid leaking distinguishing information to JS/CSS.
202
  static bool ShouldResistFingerprinting(nsIDocShell* aDocShell);
203
201
  /**
204
  /**
202
   * Returns the parent node of aChild crossing document boundaries.
205
   * Returns the parent node of aChild crossing document boundaries.
203
   * Uses the parent node in the composed document.
206
   * Uses the parent node in the composed document.
 Lines 1903-1908   public: Link Here 
1903
    return sEncodeDecodeURLHash;
1906
    return sEncodeDecodeURLHash;
1904
  }
1907
  }
1905
1908
1909
  /*
1910
   * Returns true if the browser should attempt to prevent content scripts
1911
   * from collecting distinctive information about the browser that could
1912
   * be used to "fingerprint" and track the user across websites.
1913
   */
1914
  static bool ResistFingerprinting()
1915
  {
1916
    return sPrivacyResistFingerprinting;
1917
  }
1918
1906
  /**
1919
  /**
1907
   * Returns true if the doc tree branch which contains aDoc contains any
1920
   * Returns true if the doc tree branch which contains aDoc contains any
1908
   * plugins which we don't control event dispatch for, i.e. do any plugins
1921
   * plugins which we don't control event dispatch for, i.e. do any plugins
 Lines 2440-2445   private: Link Here 
2440
  static bool sIsUserTimingLoggingEnabled;
2453
  static bool sIsUserTimingLoggingEnabled;
2441
  static bool sIsExperimentalAutocompleteEnabled;
2454
  static bool sIsExperimentalAutocompleteEnabled;
2442
  static bool sEncodeDecodeURLHash;
2455
  static bool sEncodeDecodeURLHash;
2456
  static bool sPrivacyResistFingerprinting;
2443
2457
2444
  static nsHtml5StringParser* sHTMLFragmentParser;
2458
  static nsHtml5StringParser* sHTMLFragmentParser;
2445
  static nsIParser* sXMLFragmentParser;
2459
  static nsIParser* sXMLFragmentParser;
(-)a/dom/base/nsGlobalWindow.cpp (+25 lines)
Line     Link Here 
 Lines 5003-5008   nsGlobalWindow::GetOuterSize(ErrorResult& aError) Link Here 
5003
{
5003
{
5004
  MOZ_ASSERT(IsOuterWindow());
5004
  MOZ_ASSERT(IsOuterWindow());
5005
5005
5006
  if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) {
5007
    CSSIntSize size;
5008
    aError = GetInnerSize(size);
5009
    return nsIntSize(size.width, size.height);
5010
  }
5011
5006
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5012
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5007
  if (!treeOwnerAsWin) {
5013
  if (!treeOwnerAsWin) {
5008
    aError.Throw(NS_ERROR_FAILURE);
5014
    aError.Throw(NS_ERROR_FAILURE);
 Lines 5167-5172   nsGlobalWindow::GetScreenXY(ErrorResult& aError) Link Here 
5167
{
5173
{
5168
  MOZ_ASSERT(IsOuterWindow());
5174
  MOZ_ASSERT(IsOuterWindow());
5169
5175
5176
  // When resisting fingerprinting, always return (0,0)
5177
  if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) {
5178
    return nsIntPoint(0, 0);
5179
  }
5180
5170
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5181
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5171
  if (!treeOwnerAsWin) {
5182
  if (!treeOwnerAsWin) {
5172
    aError.Throw(NS_ERROR_FAILURE);
5183
    aError.Throw(NS_ERROR_FAILURE);
 Lines 5240-5245   nsGlobalWindow::GetMozInnerScreenX(ErrorResult& aError) Link Here 
5240
{
5251
{
5241
  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenX, (aError), aError, 0);
5252
  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenX, (aError), aError, 0);
5242
5253
5254
  // When resisting fingerprinting, always return 0.
5255
  if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) {
5256
    return 0.0;
5257
  }
5258
5243
  nsRect r = GetInnerScreenRect();
5259
  nsRect r = GetInnerScreenRect();
5244
  return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
5260
  return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
5245
}
5261
}
 Lines 5258-5263   nsGlobalWindow::GetMozInnerScreenY(ErrorResult& aError) Link Here 
5258
{
5274
{
5259
  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenY, (aError), aError, 0);
5275
  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenY, (aError), aError, 0);
5260
5276
5277
  // Return 0 to prevent fingerprinting.
5278
  if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) {
5279
    return 0.0;
5280
  }
5281
5261
  nsRect r = GetInnerScreenRect();
5282
  nsRect r = GetInnerScreenRect();
5262
  return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
5283
  return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
5263
}
5284
}
 Lines 5286-5291   nsGlobalWindow::GetDevicePixelRatio(ErrorResult& aError) Link Here 
5286
    return 1.0;
5307
    return 1.0;
5287
  }
5308
  }
5288
5309
5310
  if (nsContentUtils::ShouldResistFingerprinting(mDocShell)) {
5311
    return 1.0;
5312
  }
5313
5289
  return float(nsPresContext::AppUnitsPerCSSPixel())/
5314
  return float(nsPresContext::AppUnitsPerCSSPixel())/
5290
      presContext->AppUnitsPerDevPixel();
5315
      presContext->AppUnitsPerDevPixel();
5291
}
5316
}
(-)a/dom/base/nsGlobalWindow.h (+2 lines)
Line     Link Here 
 Lines 1059-1064   public: Link Here 
1059
            bool aShowDialog, mozilla::ErrorResult& aError);
1059
            bool aShowDialog, mozilla::ErrorResult& aError);
1060
  uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);
1060
  uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);
1061
1061
1062
  bool ShouldResistFingerprinting();
1063
1062
  mozilla::dom::MozSelfSupport* GetMozSelfSupport(mozilla::ErrorResult& aError);
1064
  mozilla::dom::MozSelfSupport* GetMozSelfSupport(mozilla::ErrorResult& aError);
1063
1065
1064
  already_AddRefed<nsIDOMWindow> OpenDialog(JSContext* aCx,
1066
  already_AddRefed<nsIDOMWindow> OpenDialog(JSContext* aCx,
(-)a/dom/base/nsScreen.cpp (-15 / +58 lines)
Line     Link Here 
 Lines 68-73   NS_IMPL_RELEASE_INHERITED(nsScreen, DOMEventTargetHelper) Link Here 
68
int32_t
68
int32_t
69
nsScreen::GetPixelDepth(ErrorResult& aRv)
69
nsScreen::GetPixelDepth(ErrorResult& aRv)
70
{
70
{
71
  // Return 24 to prevent fingerprinting.
72
  if (ShouldResistFingerprinting()) {
73
    return 24;
74
  }
75
71
  nsDeviceContext* context = GetDeviceContext();
76
  nsDeviceContext* context = GetDeviceContext();
72
77
73
  if (!context) {
78
  if (!context) {
 Lines 111-116   nsScreen::GetDeviceContext() Link Here 
111
nsresult
116
nsresult
112
nsScreen::GetRect(nsRect& aRect)
117
nsScreen::GetRect(nsRect& aRect)
113
{
118
{
119
  // Return window inner rect to prevent fingerprinting.
120
  if (ShouldResistFingerprinting()) {
121
    return GetWindowInnerRect(aRect);
122
  }
123
114
  nsDeviceContext *context = GetDeviceContext();
124
  nsDeviceContext *context = GetDeviceContext();
115
125
116
  if (!context) {
126
  if (!context) {
 Lines 130-135   nsScreen::GetRect(nsRect& aRect) Link Here 
130
nsresult
140
nsresult
131
nsScreen::GetAvailRect(nsRect& aRect)
141
nsScreen::GetAvailRect(nsRect& aRect)
132
{
142
{
143
  // Return window inner rect to prevent fingerprinting.
144
  if (ShouldResistFingerprinting()) {
145
    return GetWindowInnerRect(aRect);
146
  }
147
133
  nsDeviceContext *context = GetDeviceContext();
148
  nsDeviceContext *context = GetDeviceContext();
134
149
135
  if (!context) {
150
  if (!context) {
 Lines 166-187   nsScreen::Notify(const hal::ScreenConfiguration& aConfiguration) Link Here 
166
void
181
void
167
nsScreen::GetMozOrientation(nsString& aOrientation)
182
nsScreen::GetMozOrientation(nsString& aOrientation)
168
{
183
{
169
  switch (mOrientation) {
184
  if (ShouldResistFingerprinting()) {
170
  case eScreenOrientation_PortraitPrimary:
171
    aOrientation.AssignLiteral("portrait-primary");
172
    break;
173
  case eScreenOrientation_PortraitSecondary:
174
    aOrientation.AssignLiteral("portrait-secondary");
175
    break;
176
  case eScreenOrientation_LandscapePrimary:
177
    aOrientation.AssignLiteral("landscape-primary");
185
    aOrientation.AssignLiteral("landscape-primary");
178
    break;
186
  } else {
179
  case eScreenOrientation_LandscapeSecondary:
187
    switch (mOrientation) {
180
    aOrientation.AssignLiteral("landscape-secondary");
188
    case eScreenOrientation_PortraitPrimary:
181
    break;
189
      aOrientation.AssignLiteral("portrait-primary");
182
  case eScreenOrientation_None:
190
      break;
183
  default:
191
    case eScreenOrientation_PortraitSecondary:
184
    MOZ_CRASH("Unacceptable mOrientation value");
192
      aOrientation.AssignLiteral("portrait-secondary");
193
      break;
194
    case eScreenOrientation_LandscapePrimary:
195
      aOrientation.AssignLiteral("landscape-primary");
196
      break;
197
    case eScreenOrientation_LandscapeSecondary:
198
      aOrientation.AssignLiteral("landscape-secondary");
199
      break;
200
    case eScreenOrientation_None:
201
    default:
202
      MOZ_CRASH("Unacceptable mOrientation value");
203
    }
185
  }
204
  }
186
}
205
}
187
206
 Lines 373-375   nsScreen::FullScreenEventListener::HandleEvent(nsIDOMEvent* aEvent) Link Here 
373
392
374
  return NS_OK;
393
  return NS_OK;
375
}
394
}
395
396
nsresult
397
nsScreen::GetWindowInnerRect(nsRect& aRect)
398
{
399
  aRect.x = 0;
400
  aRect.y = 0;
401
  nsCOMPtr<nsIDOMWindow> win = GetOwner();
402
  if (!win) {
403
    return NS_ERROR_FAILURE;
404
  }
405
  nsresult rv = win->GetInnerWidth(&aRect.width);
406
  NS_ENSURE_SUCCESS(rv, rv);
407
  return win->GetInnerHeight(&aRect.height);
408
}
409
410
bool nsScreen::ShouldResistFingerprinting() const
411
{
412
  bool resist = false;
413
  nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
414
  if (owner) {
415
    resist = nsContentUtils::ShouldResistFingerprinting(owner->GetDocShell());
416
  }
417
  return resist;
418
}
(-)a/dom/base/nsScreen.h (+3 lines)
Line     Link Here 
 Lines 131-136   protected: Link Here 
131
  nsDeviceContext* GetDeviceContext();
131
  nsDeviceContext* GetDeviceContext();
132
  nsresult GetRect(nsRect& aRect);
132
  nsresult GetRect(nsRect& aRect);
133
  nsresult GetAvailRect(nsRect& aRect);
133
  nsresult GetAvailRect(nsRect& aRect);
134
  nsresult GetWindowInnerRect(nsRect& aRect);
134
135
135
  mozilla::dom::ScreenOrientation mOrientation;
136
  mozilla::dom::ScreenOrientation mOrientation;
136
137
 Lines 158-163   private: Link Here 
158
159
159
  bool IsDeviceSizePageSize();
160
  bool IsDeviceSizePageSize();
160
161
162
  bool ShouldResistFingerprinting() const;
163
161
  nsRefPtr<FullScreenEventListener> mEventListener;
164
  nsRefPtr<FullScreenEventListener> mEventListener;
162
};
165
};
163
166
(-)a/dom/base/test/chrome/bug418986-1.js (+71 lines)
Line     Link Here 
Line 0    Link Here 
1
// The main test function.
2
let test = function (isContent) {
3
  SimpleTest.waitForExplicitFinish();
4
5
  let { ww } = SpecialPowers.Services;
6
  window.chromeWindow = ww.activeWindow;
7
8
  // The pairs of values expected to be the same when
9
  // fingerprinting resistance is enabled.
10
  let pairs = [
11
    ["screenX", 0],
12
    ["screenY", 0],
13
    ["mozInnerScreenX", 0],
14
    ["mozInnerScreenY", 0],
15
    ["screen.pixelDepth", 24],
16
    ["screen.colorDepth", 24],
17
    ["screen.availWidth", "innerWidth"],
18
    ["screen.availHeight", "innerHeight"],
19
    ["screen.left", 0],
20
    ["screen.top", 0],
21
    ["screen.availLeft", 0],
22
    ["screen.availTop", 0],
23
    ["screen.width", "innerWidth"],
24
    ["screen.height", "innerHeight"],
25
    ["screen.mozOrientation", "'landscape-primary'"],
26
    ["devicePixelRatio", 1]
27
  ];
28
29
  // checkPair: tests if members of pair [a, b] are equal when evaluated.
30
  let checkPair = function (a, b) {
31
    is(eval(a), eval(b), a + " should be equal to " + b);
32
  };
33
34
  // Returns generator object that iterates through pref values.
35
  let prefVals = (for (prefVal of [false, true]) prefVal);
36
37
  // The main test function, runs until all pref values are exhausted.
38
  let nextTest = function () {
39
    let {value : prefValue, done} = prefVals.next();
40
    if (done) {
41
      SimpleTest.finish();
42
      return;
43
    }
44
    SpecialPowers.pushPrefEnv({set : [["privacy.resistFingerprinting", prefValue]]},
45
      function () {
46
        // We will be resisting fingerprinting if the pref is enabled,
47
        // and we are in a content script (not chrome).
48
        let resisting = prefValue && isContent;
49
        // Check each of the pairs.
50
        pairs.map(function ([item, onVal]) {
51
          if (resisting) {
52
            checkPair("window." + item, onVal);
53
          } else {
54
            if (!item.startsWith("moz")) {
55
              checkPair("window." + item, "chromeWindow." + item);
56
            }
57
          }
58
        });
59
        if (!resisting) {
60
          // Hard to predict these values, but we can enforce constraints:
61
          ok(window.mozInnerScreenX >= chromeWindow.mozInnerScreenX,
62
             "mozInnerScreenX");
63
          ok(window.mozInnerScreenY >= chromeWindow.mozInnerScreenY,
64
             "mozInnerScreenY");
65
        }
66
      nextTest();
67
    });
68
  }
69
70
  nextTest();
71
}
(-)a/dom/base/test/chrome/chrome.ini (+2 lines)
Line     Link Here 
 Lines 3-8   skip-if = buildapp == 'b2g' Link Here 
3
support-files =
3
support-files =
4
  blockNoPlugins.xml
4
  blockNoPlugins.xml
5
  blockPluginHard.xml
5
  blockPluginHard.xml
6
  bug418986-1.js
6
  cpows_child.js
7
  cpows_child.js
7
  cpows_parent.xul
8
  cpows_parent.xul
8
  file_bug391728.html
9
  file_bug391728.html
 Lines 31-36   support-files = Link Here 
31
[test_bug380418.html^headers^]
32
[test_bug380418.html^headers^]
32
[test_bug383430.html]
33
[test_bug383430.html]
33
[test_bug391728.html]
34
[test_bug391728.html]
35
[test_bug418986-1.xul]
34
[test_bug421622.xul]
36
[test_bug421622.xul]
35
[test_bug429785.xul]
37
[test_bug429785.xul]
36
[test_bug430050.xul]
38
[test_bug430050.xul]
(-)a/dom/base/test/chrome/test_bug418986-1.xul (+26 lines)
Line     Link Here 
Line 0    Link Here 
1
<?xml version="1.0"?>
2
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
3
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
4
                 type="text/css"?>
5
<!--
6
https://bugzilla.mozilla.org/show_bug.cgi?id=418986-1
7
-->
8
<window title="Mozilla Bug 418986 (Part 1)"
9
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
10
  <script type="application/javascript"
11
          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
12
13
  <!-- test results are displayed in the html:body -->
14
  <body xmlns="http://www.w3.org/1999/xhtml">
15
  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986-1"
16
     target="_blank">Mozilla Bug 418986 (Part 1)</a>
17
18
  <script type="application/javascript;version=1.7" src="bug418986-1.js"></script>
19
  <!-- test code goes here -->
20
  <script type="application/javascript"><![CDATA[
21
    window.onload = function() {
22
      test(false);
23
    };
24
  ]]></script>
25
  </body>
26
</window>
(-)a/dom/base/test/mochitest.ini (+2 lines)
Line     Link Here 
 Lines 56-61   support-files = Link Here 
56
  bug704320.sjs
56
  bug704320.sjs
57
  bug704320_counter.sjs
57
  bug704320_counter.sjs
58
  bug819051.sjs
58
  bug819051.sjs
59
  chrome/bug418986-1.js
59
  copypaste.js
60
  copypaste.js
60
  delayedServerEvents.sjs
61
  delayedServerEvents.sjs
61
  echo.sjs
62
  echo.sjs
 Lines 453-458   support-files = test_bug402150.html^headers^ Link Here 
453
[test_bug417255.html]
454
[test_bug417255.html]
454
[test_bug417384.html]
455
[test_bug417384.html]
455
[test_bug418214.html]
456
[test_bug418214.html]
457
[test_bug418986-1.html]
456
[test_bug419132.html]
458
[test_bug419132.html]
457
[test_bug419527.xhtml]
459
[test_bug419527.xhtml]
458
[test_bug420609.xhtml]
460
[test_bug420609.xhtml]
(-)a/dom/base/test/test_bug418986-1.html (+24 lines)
Line     Link Here 
Line 0    Link Here 
1
<!DOCTYPE HTML>
2
<html>
3
<!--
4
https://bugzilla.mozilla.org/show_bug.cgi?id=418986
5
-->
6
<head>
7
  <meta charset="utf-8">
8
  <title>Test 1/3 for Bug 418986 - Resist fingerprinting by preventing exposure of screen and system info</title>
9
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
10
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
11
  <script type="application/javascript;version=1.7" src="chrome/bug418986-1.js"></script>
12
</head>
13
<body>
14
  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a>
15
  <p id="display"></p>
16
  <div id="content" style="display: none"></div>
17
  <pre id="test"></pre>
18
  <script>
19
    window.onload = function() {
20
      test(true);
21
    };
22
  </script>
23
</body>
24
</html>
(-)a/dom/events/Event.cpp (+7 lines)
Line     Link Here 
 Lines 890-895   Event::GetScreenCoords(nsPresContext* aPresContext, Link Here 
890
                       WidgetEvent* aEvent,
890
                       WidgetEvent* aEvent,
891
                       LayoutDeviceIntPoint aPoint)
891
                       LayoutDeviceIntPoint aPoint)
892
{
892
{
893
  if (!nsContentUtils::IsCallerChrome() &&
894
      nsContentUtils::ResistFingerprinting()) {
895
    // When resisting fingerprinting, return client coordinates instead.
896
    CSSIntPoint clientCoords = GetClientCoords(aPresContext, aEvent, aPoint, CSSIntPoint(0, 0));
897
    return LayoutDeviceIntPoint(clientCoords.x, clientCoords.y);
898
  }
899
893
  if (EventStateManager::sIsPointerLocked) {
900
  if (EventStateManager::sIsPointerLocked) {
894
    return EventStateManager::sLastScreenPoint;
901
    return EventStateManager::sLastScreenPoint;
895
  }
902
  }
(-)a/dom/events/test/bug418986-3.js (+69 lines)
Line     Link Here 
Line 0    Link Here 
1
SimpleTest.waitForExplicitFinish();
2
3
// The main testing function.
4
let test = function (isContent) {
5
  // Each definition is [eventType, prefSetting]
6
  // Where we are setting the "privacy.resistFingerprinting" pref.
7
  let eventDefs = [["mousedown", true],
8
                   ["mouseup", true],
9
                   ["mousedown", false],
10
                   ["mouseup", false]];
11
12
  let testCounter = 0;
13
14
  // Declare ahead of time.
15
  let setup;
16
17
  // This function is called when the event handler fires.
18
  let handleEvent = function (event, prefVal) {
19
    let resisting = prefVal && isContent;
20
    if (resisting) {
21
      is(event.screenX, event.clientX, "event.screenX and event.clientX should be the same");
22
      is(event.screenY, event.clientY, "event.screenY and event.clientY should be the same");
23
    } else {
24
      // We can't be sure about X coordinates not being equal, but we can test Y.
25
      isnot(event.screenY, event.clientY, "event.screenY !== event.clientY");
26
    }
27
    ++testCounter;
28
    if (testCounter < eventDefs.length) {
29
      nextTest();
30
    } else {
31
      SimpleTest.finish();
32
    }
33
  };
34
35
  // In this function, we set up the nth div and event handler,
36
  // and then synthesize a mouse event in the div, to test
37
  // whether the resulting events resist fingerprinting by
38
  // suppressing absolute screen coordinates.
39
  nextTest = function () {
40
    let [eventType, prefVal] = eventDefs[testCounter];
41
    SpecialPowers.pushPrefEnv({set:[["privacy.resistFingerprinting", prefVal]]},
42
      function () {
43
        // The following code creates a new div for each event in eventDefs,
44
        // attaches a listener to listen for the event, and then generates
45
        // a fake event at the center of the div.
46
        let div = document.createElement("div");
47
        div.style.width = "10px";
48
        div.style.height = "10px";
49
        div.style.backgroundColor = "red";
50
        // Name the div after the event we're listening for.
51
        div.id = eventType;
52
        document.getElementById("body").appendChild(div);
53
        // Seems we can't add an event listener in chrome unless we run
54
        // it in a later task.
55
        window.setTimeout(function() {
56
          div.addEventListener(eventType, event => handleEvent(event, prefVal), false);
57
          // For some reason, the following synthesizeMouseAtCenter call only seems to run if we
58
          // wrap it in a window.setTimeout(..., 0).
59
          window.setTimeout(function () {
60
            synthesizeMouseAtCenter(div, {type : eventType});
61
          }, 0);
62
        }, 0);
63
      });
64
  };
65
66
  // Now run by starting with the 0th event.
67
  nextTest();
68
69
};
(-)a/dom/events/test/chrome.ini (+2 lines)
Line     Link Here 
 Lines 3-8   skip-if = buildapp == 'b2g' Link Here 
3
support-files =
3
support-files =
4
  bug415498-doc1.html
4
  bug415498-doc1.html
5
  bug415498-doc2.html
5
  bug415498-doc2.html
6
  bug418986-3.js
6
  bug591249_iframe.xul
7
  bug591249_iframe.xul
7
  bug602962.xul
8
  bug602962.xul
8
  file_bug679494.html
9
  file_bug679494.html
 Lines 12-17   support-files = Link Here 
12
[test_bug336682_2.xul]
13
[test_bug336682_2.xul]
13
[test_bug368835.html]
14
[test_bug368835.html]
14
[test_bug415498.xul]
15
[test_bug415498.xul]
16
[test_bug418986-3.xul]
15
[test_bug524674.xul]
17
[test_bug524674.xul]
16
[test_bug586961.xul]
18
[test_bug586961.xul]
17
[test_bug591249.xul]
19
[test_bug591249.xul]
(-)a/dom/events/test/mochitest.ini (+4 lines)
Line     Link Here 
 Lines 7-12   support-files = Link Here 
7
  bug426082.html
7
  bug426082.html
8
  bug648573.html
8
  bug648573.html
9
  bug656379-1.html
9
  bug656379-1.html
10
  bug418986-3.js
10
  error_event_worker.js
11
  error_event_worker.js
11
  empty.js
12
  empty.js
12
  window_bug493251.html
13
  window_bug493251.html
 Lines 38-43   support-files = test_bug336682.js Link Here 
38
[test_bug409604.html]
39
[test_bug409604.html]
39
skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
40
skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
40
[test_bug412567.html]
41
[test_bug412567.html]
42
[test_bug418986-3.html]
43
# Sometimes fails to finish after tests pass on 'B2G ICS Emulator'.
44
skip-if = (os == 'b2g')
41
[test_bug422132.html]
45
[test_bug422132.html]
42
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)
46
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)
43
[test_bug426082.html]
47
[test_bug426082.html]
(-)a/dom/events/test/test_bug418986-3.html (+25 lines)
Line     Link Here 
Line 0    Link Here 
1
<!DOCTYPE HTML>
2
<html>
3
<!--
4
https://bugzilla.mozilla.org/show_bug.cgi?id=418986
5
-->
6
<head>
7
  <meta charset="utf-8">
8
  <title>Test 3/3 for Bug 418986 - Resist fingerprinting by preventing exposure of screen and system info</title>
9
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
10
  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
11
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
12
</head>
13
<body id="body">
14
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a>
15
<p id="display"></p>
16
<pre id="test"></pre>
17
<script type="application/javascript;version=1.7" src="bug418986-3.js"></script>
18
<script type="application/javascript;version=1.7">
19
  // This test produces fake mouse events and checks that the screenX and screenY
20
  // properties of the received event objects provide client window coordinates.
21
  // Run the test once the window has loaded.
22
  window.onload = () => test(true);
23
</script>
24
</body>
25
</html>
(-)a/dom/events/test/test_bug418986-3.xul (+27 lines)
Line     Link Here 
Line 0    Link Here 
1
<?xml version="1.0"?>
2
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
3
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
4
<!--
5
Bug 418986
6
-->
7
<window title="Mozilla Bug 418986"
8
  xmlns:html="http://www.w3.org/1999/xhtml"
9
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
10
11
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
12
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
13
14
<body id="body" xmlns="http://www.w3.org/1999/xhtml">
15
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">
16
Mozilla Bug 418986</a>
17
</body>
18
19
<script type="application/javascript;version=1.7" src="bug418986-3.js"></script>
20
<script type="application/javascript;version=1.7"><![CDATA[
21
  // This test produces fake mouse events and checks that the screenX and screenY
22
  // properties of the received event objects provide client window coordinates.
23
  // Run the test once the window has loaded.
24
  test(false);
25
]]></script>  
26
27
</window>
(-)a/layout/style/nsComputedDOMStyle.cpp (+4 lines)
Line     Link Here 
 Lines 1450-1455   nsComputedDOMStyle::DoGetFontSizeAdjust() Link Here 
1450
CSSValue*
1450
CSSValue*
1451
nsComputedDOMStyle::DoGetOsxFontSmoothing()
1451
nsComputedDOMStyle::DoGetOsxFontSmoothing()
1452
{
1452
{
1453
  if (nsContentUtils::ShouldResistFingerprinting(
1454
        mPresShell->GetPresContext()->GetDocShell()))
1455
    return nullptr;
1456
1453
  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1457
  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1454
  val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
1458
  val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
1455
                                               nsCSSProps::kFontSmoothingKTable));
1459
                                               nsCSSProps::kFontSmoothingKTable));
(-)a/layout/style/nsMediaFeatures.cpp (-15 / +49 lines)
Line     Link Here 
 Lines 109-121   GetDeviceContextFor(nsPresContext* aPresContext) Link Here 
109
  return aPresContext->DeviceContext();
109
  return aPresContext->DeviceContext();
110
}
110
}
111
111
112
static bool
113
ShouldResistFingerprinting(nsPresContext* aPresContext)
114
{
115
    return nsContentUtils::ShouldResistFingerprinting(aPresContext->GetDocShell());
116
}
117
112
// A helper for three features below.
118
// A helper for three features below.
113
static nsSize
119
static nsSize
114
GetDeviceSize(nsPresContext* aPresContext)
120
GetDeviceSize(nsPresContext* aPresContext)
115
{
121
{
116
    nsSize size;
122
    nsSize size;
117
123
118
    if (aPresContext->IsDeviceSizePageSize()) {
124
    if (ShouldResistFingerprinting(aPresContext) || aPresContext->IsDeviceSizePageSize()) {
119
        size = GetSize(aPresContext);
125
        size = GetSize(aPresContext);
120
    } else if (aPresContext->IsRootPaginatedDocument()) {
126
    } else if (aPresContext->IsRootPaginatedDocument()) {
121
        // We want the page size, including unprintable areas and margins.
127
        // We want the page size, including unprintable areas and margins.
 Lines 223-235   static nsresult Link Here 
223
GetColor(nsPresContext* aPresContext, const nsMediaFeature*,
229
GetColor(nsPresContext* aPresContext, const nsMediaFeature*,
224
         nsCSSValue& aResult)
230
         nsCSSValue& aResult)
225
{
231
{
226
    // FIXME:  This implementation is bogus.  nsDeviceContext
232
    uint32_t depth = 24; // Use depth of 24 when resisting fingerprinting.
227
    // doesn't provide reliable information (should be fixed in bug
233
228
    // 424386).
234
    if (!ShouldResistFingerprinting(aPresContext)) {
229
    // FIXME: On a monochrome device, return 0!
235
        // FIXME:  This implementation is bogus.  nsDeviceContext
230
    nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
236
        // doesn't provide reliable information (should be fixed in bug
231
    uint32_t depth;
237
        // 424386).
232
    dx->GetDepth(depth);
238
        // FIXME: On a monochrome device, return 0!
239
        nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
240
        dx->GetDepth(depth);
241
    }
242
233
    // The spec says to use bits *per color component*, so divide by 3,
243
    // The spec says to use bits *per color component*, so divide by 3,
234
    // and round down, since the spec says to use the smallest when the
244
    // and round down, since the spec says to use the smallest when the
235
    // color components differ.
245
    // color components differ.
 Lines 267-276   static nsresult Link Here 
267
GetResolution(nsPresContext* aPresContext, const nsMediaFeature*,
277
GetResolution(nsPresContext* aPresContext, const nsMediaFeature*,
268
              nsCSSValue& aResult)
278
              nsCSSValue& aResult)
269
{
279
{
270
    // Resolution measures device pixels per CSS (inch/cm/pixel).  We
280
    float dpi = 96; // Use 96 when resisting fingerprinting.
271
    // return it in device pixels per CSS inches.
281
272
    float dpi = float(nsPresContext::AppUnitsPerCSSInch()) /
282
    if (!ShouldResistFingerprinting(aPresContext)) {
273
                float(aPresContext->AppUnitsPerDevPixel());
283
      // Resolution measures device pixels per CSS (inch/cm/pixel).  We
284
      // return it in device pixels per CSS inches.
285
      dpi = float(nsPresContext::AppUnitsPerCSSInch()) /
286
            float(aPresContext->AppUnitsPerDevPixel());
287
    }
288
274
    aResult.SetFloatValue(dpi, eCSSUnit_Inch);
289
    aResult.SetFloatValue(dpi, eCSSUnit_Inch);
275
    return NS_OK;
290
    return NS_OK;
276
}
291
}
 Lines 299-313   static nsresult Link Here 
299
GetDevicePixelRatio(nsPresContext* aPresContext, const nsMediaFeature*,
314
GetDevicePixelRatio(nsPresContext* aPresContext, const nsMediaFeature*,
300
                    nsCSSValue& aResult)
315
                    nsCSSValue& aResult)
301
{
316
{
302
  float ratio = aPresContext->CSSPixelsToDevPixels(1.0f);
317
    if (!ShouldResistFingerprinting(aPresContext)) {
303
  aResult.SetFloatValue(ratio, eCSSUnit_Number);
318
        float ratio = aPresContext->CSSPixelsToDevPixels(1.0f);
304
  return NS_OK;
319
        aResult.SetFloatValue(ratio, eCSSUnit_Number);
320
    } else {
321
        aResult.SetFloatValue(1.0, eCSSUnit_Number);
322
    }
323
    return NS_OK;
305
}
324
}
306
325
307
static nsresult
326
static nsresult
308
GetSystemMetric(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
327
GetSystemMetric(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
309
                nsCSSValue& aResult)
328
                nsCSSValue& aResult)
310
{
329
{
330
    aResult.Reset();
331
    if (ShouldResistFingerprinting(aPresContext)) {
332
        // If "privacy.resistFingerprinting" is enabled, then we simply don't
333
        // return any system-backed media feature values. (No spoofed values returned.)
334
        return NS_OK;
335
    }
336
311
    MOZ_ASSERT(aFeature->mValueType == nsMediaFeature::eBoolInteger,
337
    MOZ_ASSERT(aFeature->mValueType == nsMediaFeature::eBoolInteger,
312
               "unexpected type");
338
               "unexpected type");
313
    nsIAtom *metricAtom = *aFeature->mData.mMetric;
339
    nsIAtom *metricAtom = *aFeature->mData.mMetric;
 Lines 321-326   GetWindowsTheme(nsPresContext* aPresContext, const nsMediaFeature* aFeature, Link Here 
321
                nsCSSValue& aResult)
347
                nsCSSValue& aResult)
322
{
348
{
323
    aResult.Reset();
349
    aResult.Reset();
350
    if (ShouldResistFingerprinting(aPresContext)) {
351
        return NS_OK;
352
    }
353
324
#ifdef XP_WIN
354
#ifdef XP_WIN
325
    uint8_t windowsThemeId =
355
    uint8_t windowsThemeId =
326
        nsCSSRuleProcessor::GetWindowsThemeIdentifier();
356
        nsCSSRuleProcessor::GetWindowsThemeIdentifier();
 Lines 346-351   GetOperatinSystemVersion(nsPresContext* aPresContext, const nsMediaFeature* aFea Link Here 
346
                         nsCSSValue& aResult)
376
                         nsCSSValue& aResult)
347
{
377
{
348
    aResult.Reset();
378
    aResult.Reset();
379
    if (ShouldResistFingerprinting(aPresContext)) {
380
        return NS_OK;
381
    }
382
349
#ifdef XP_WIN
383
#ifdef XP_WIN
350
    int32_t metricResult;
384
    int32_t metricResult;
351
    if (NS_SUCCEEDED(
385
    if (NS_SUCCEEDED(
(-)a/layout/style/test/chrome/bug418986-2.js (+274 lines)
Line     Link Here 
Line 0    Link Here 
1
// # Bug 418986, part 2.
2
3
/* jshint esnext:true */
4
/* jshint loopfunc:true */
5
/* global window, screen, ok, SpecialPowers, matchMedia */
6
7
SimpleTest.waitForExplicitFinish();
8
9
// Expected values. Format: [name, pref_off_value, pref_on_value]
10
// If pref_*_value is an array with two values, then we will match
11
// any value in between those two values. If a value is null, then
12
// we skip the media query.
13
let expected_values = [
14
  ["color", null, 8],
15
  ["color-index", null, 0],
16
  ["aspect-ratio", null, window.innerWidth + "/" + window.innerHeight],
17
  ["device-aspect-ratio", screen.width + "/" + screen.height,
18
                          window.innerWidth + "/" + window.innerHeight],
19
  ["device-height", screen.height + "px", window.innerHeight + "px"],
20
  ["device-width", screen.width + "px", window.innerWidth + "px"],
21
  ["grid", null, 0],
22
  ["height", window.innerHeight + "px", window.innerHeight + "px"],
23
  ["monochrome", null, 0],
24
  // Square is defined as portrait:
25
  ["orientation", null,
26
                  window.innerWidth > window.innerHeight ?
27
                    "landscape" : "portrait"],
28
  ["resolution", null, "96dpi"],
29
  ["resolution", [0.999 * window.devicePixelRatio + "dppx",
30
                  1.001 * window.devicePixelRatio + "dppx"], "1dppx"],
31
  ["width", window.innerWidth + "px", window.innerWidth + "px"],
32
  ["-moz-device-pixel-ratio", window.devicePixelRatio, 1],
33
  ["-moz-device-orientation", screen.width > screen.height ?
34
                                "landscape" : "portrait",
35
                              window.innerWidth > window.innerHeight ?
36
                                "landscape" : "portrait"]
37
];
38
39
// These media queries return value 0 or 1 when the pref is off.
40
// When the pref is on, they should not match.
41
let suppressed_toggles = [
42
  "-moz-images-in-menus",
43
  "-moz-mac-graphite-theme",
44
  // Not available on most OSs.
45
//  "-moz-maemo-classic",
46
  "-moz-scrollbar-end-backward",
47
  "-moz-scrollbar-end-forward",
48
  "-moz-scrollbar-start-backward",
49
  "-moz-scrollbar-start-forward",
50
  "-moz-scrollbar-thumb-proportional",
51
  "-moz-touch-enabled",
52
  "-moz-windows-compositor",
53
  "-moz-windows-default-theme",
54
  "-moz-windows-glass",
55
];
56
57
// Possible values for '-moz-os-version'
58
let windows_versions = [
59
  "windows-xp",
60
  "windows-vista",
61
  "windows-win7",
62
  "windows-win8"];
63
64
// Possible values for '-moz-windows-theme'
65
let windows_themes = [
66
  "aero",
67
  "luna-blue",
68
  "luna-olive",
69
  "luna-silver",
70
  "royale",
71
  "generic",
72
  "zune"
73
];
74
75
// Read the current OS.
76
let OS = SpecialPowers.Services.appinfo.OS;
77
78
// If we are using Windows, add an extra toggle only
79
// available on that OS.
80
if (OS === "WINNT") {
81
  suppressed_toggles.push("-moz-windows-classic");
82
}
83
84
// __keyValMatches(key, val)__.
85
// Runs a media query and returns true if key matches to val.
86
let keyValMatches = (key, val) => matchMedia("(" + key + ":" + val +")").matches;
87
88
// __testMatch(key, val)__.
89
// Attempts to run a media query match for the given key and value.
90
// If value is an array of two elements [min max], then matches any
91
// value in-between.
92
let testMatch = function (key, val) {
93
  if (val === null) {
94
    return;
95
  } else if (Array.isArray(val)) {
96
    ok(keyValMatches("min-" + key, val[0]) && keyValMatches("max-" + key, val[1]),
97
       "Expected " + key + " between " + val[0] + " and " + val[1]);
98
  } else {
99
    ok(keyValMatches(key, val), "Expected " + key + ":" + val);
100
  }
101
};
102
103
// __testToggles(resisting)__.
104
// Test whether we are able to match the "toggle" media queries.
105
let testToggles = function (resisting) {
106
  suppressed_toggles.forEach(
107
    function (key) {
108
      var exists = keyValMatches(key, 0) || keyValMatches(key, 1);
109
      if (resisting) {
110
         ok(!exists, key + " should not exist.");
111
      } else {
112
         ok(exists, key + " should exist.");
113
      }
114
    });
115
};
116
117
// __testWindowsSpecific__.
118
// Runs a media query on the queryName with the given possible matching values.
119
let testWindowsSpecific = function (resisting, queryName, possibleValues) {
120
  let found = false;
121
  possibleValues.forEach(function (val) {
122
    found = found || keyValMatches(queryName, val);
123
  });
124
  if (resisting) {
125
    ok(!found, queryName + " should have no match");
126
  } else {
127
    ok(found, queryName + " should match");
128
  }
129
};
130
131
// __generateHtmlLines(resisting)__.
132
// Create a series of div elements that look like:
133
// `<div class='spoof' id='resolution'>resolution</div>`,
134
// where each line corresponds to a different media query.
135
let generateHtmlLines = function (resisting) {
136
  let lines = "";
137
  expected_values.forEach(
138
    function ([key, offVal, onVal]) {
139
      let val = resisting ? onVal : offVal;
140
      if (val) {
141
        lines += "<div class='spoof' id='" + key + "'>" + key + "</div>\n";
142
      }
143
    });
144
  suppressed_toggles.forEach(
145
    function (key) {
146
      lines += "<div class='suppress' id='" + key + "'>" + key + "</div>\n";
147
    });
148
  if (OS === "WINNT") {
149
    lines += "<div class='windows' id='-moz-os-version'>-moz-os-version</div>";
150
    lines += "<div class='windows' id='-moz-windows-theme'>-moz-windows-theme</div>";
151
  }
152
  return lines;
153
};
154
155
// __cssLine__.
156
// Creates a line of css that looks something like
157
// `@media (resolution: 1ppx) { .spoof#resolution { background-color: green; } }`.
158
let cssLine = function (query, clazz, id, color) {
159
  return "@media " + query + " { ." + clazz +  "#" + id +
160
         " { background-color: " + color + "; } }\n";
161
};
162
163
// __mediaQueryCSSLine(key, val, color)__.
164
// Creates a line containing a CSS media query and a CSS expression.
165
let mediaQueryCSSLine = function (key, val, color) {
166
  if (val === null) {
167
    return "";
168
  }
169
  let query;
170
  if (Array.isArray(val)) {
171
    query = "(min-" + key + ": " + val[0] + ") and (max-" +  key + ": " + val[1] + ")";
172
  } else {
173
    query = "(" + key + ": " + val + ")";
174
  }
175
  return cssLine(query, "spoof", key, color);
176
};
177
178
// __suppressedMediaQueryCSSLine(key, color)__.
179
// Creates a CSS line that matches the existence of a
180
// media query that is supposed to be suppressed.
181
let suppressedMediaQueryCSSLine = function (key, color, suppressed) {
182
  let query = "(" + key + ": 0), (" + key + ": 1)";
183
  return cssLine(query, "suppress", key, color);
184
};
185
186
// __generateCSSLines(resisting)__.
187
// Creates a series of lines of CSS, each of which corresponds to
188
// a different media query. If the query produces a match to the
189
// expected value, then the element will be colored green.
190
let generateCSSLines = function (resisting) {
191
  let lines = ".spoof { background-color: red;}\n";
192
  expected_values.forEach(
193
    function ([key, offVal, onVal]) {
194
      lines += mediaQueryCSSLine(key, resisting ? onVal : offVal, "green");
195
    });
196
  lines += ".suppress { background-color: " + (resisting ? "green" : "red") + ";}\n";
197
  suppressed_toggles.forEach(
198
    function (key) {
199
      lines += suppressedMediaQueryCSSLine(key, resisting ? "red" : "green");
200
    });
201
  if (OS === "WINNT") {
202
    lines += ".windows { background-color: " + (resisting ? "green" : "red") + ";}\n";
203
    lines += windows_versions.map(val => "(-moz-os-version: " + val + ")").join(", ") +
204
             " { #-moz-os-version { background-color: " + (resisting ? "red" : "green") + ";} }\n";
205
    lines += windows_themes.map(val => "(-moz-windows-theme: " + val + ")").join(",") +
206
             " { #-moz-windows-theme { background-color: " + (resisting ? "red" : "green") + ";} }\n";
207
  }
208
  return lines;
209
};
210
211
// __green__.
212
// Returns the computed color style corresponding to green.
213
let green = (function () {
214
  let temp = document.createElement("span");
215
  temp.style.backgroundColor = "green";
216
  return getComputedStyle(temp).backgroundColor;
217
})();
218
219
// __testCSS(resisting)__.
220
// Creates a series of divs and CSS using media queries to set their
221
// background color. If all media queries match as expected, then
222
// all divs should have a green background color.
223
let testCSS = function (resisting) {
224
  document.getElementById("display").innerHTML = generateHtmlLines(resisting);
225
  document.getElementById("test-css").innerHTML = generateCSSLines(resisting);
226
  let cssTestDivs = document.querySelectorAll(".spoof,.suppress");
227
  for (let div of cssTestDivs) {
228
    let color = window.getComputedStyle(div).backgroundColor;
229
    ok(color === green, "CSS for '" + div.id + "'");
230
  }
231
};
232
233
// __testOSXFontSmoothing(resisting)__.
234
// When fingerprinting resistance is enabled, the `getComputedStyle`
235
// should always return `undefined` for `MozOSXFontSmoothing`.
236
let testOSXFontSmoothing = function (resisting) {
237
  let div = document.createElement("div");
238
  div.style.MozOsxFontSmoothing = "unset";
239
  let readBack = window.getComputedStyle(div).MozOsxFontSmoothing;
240
  let smoothingPref = SpecialPowers.getBoolPref("layout.css.osx-font-smoothing.enabled", false);
241
  is(readBack, resisting ? "" : (smoothingPref ? "auto" : ""),
242
               "-moz-osx-font-smoothing");
243
};
244
245
// An iterator yielding pref values for two consecutive tests.
246
let prefVals = (for (prefVal of [false, true]) prefVal);
247
248
// __test(isContent)__.
249
// Run all tests.
250
let test = function(isContent) {
251
  let {value: prefValue, done} = prefVals.next();
252
  if (done) {
253
    SimpleTest.finish();
254
    return;
255
  }
256
  SpecialPowers.pushPrefEnv({set: [["privacy.resistFingerprinting", prefValue]]},
257
    function () {
258
      let resisting = prefValue && isContent;
259
      expected_values.forEach(
260
        function ([key, offVal, onVal]) {
261
          testMatch(key, resisting ? onVal : offVal);
262
        });
263
      testToggles(resisting);
264
      if (OS === "WINNT") {
265
        testWindowsSpecific(resisting, "-moz-os-version", windows_versions);
266
        testWindowsSpecific(resisting, "-moz-windows-theme", windows_themes);
267
      }
268
      testCSS(resisting);
269
      if (OS === "Darwin") {
270
        testOSXFontSmoothing(resisting);
271
      }
272
      test(isContent);
273
    });
274
};
(-)a/layout/style/test/chrome/chrome.ini (+2 lines)
Line     Link Here 
 Lines 1-6    Link Here 
1
[DEFAULT]
1
[DEFAULT]
2
skip-if = buildapp == 'b2g'
2
skip-if = buildapp == 'b2g'
3
support-files =
3
support-files =
4
  bug418986-2.js
4
  bug535806-css.css
5
  bug535806-css.css
5
  bug535806-html.html
6
  bug535806-html.html
6
  bug535806-xul.xul
7
  bug535806-xul.xul
 Lines 9-14   support-files = Link Here 
9
[test_addSheet.html]
10
[test_addSheet.html]
10
[test_additional_sheets.html]
11
[test_additional_sheets.html]
11
[test_author_specified_style.html]
12
[test_author_specified_style.html]
13
[test_bug418986-2.xul]
12
[test_bug1157097.html]
14
[test_bug1157097.html]
13
[test_bug1160724.xul]
15
[test_bug1160724.xul]
14
[test_bug535806.xul]
16
[test_bug535806.xul]
(-)a/layout/style/test/chrome/test_bug418986-2.xul (+27 lines)
Line     Link Here 
Line 0    Link Here 
1
<?xml version="1.0"?>
2
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
3
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
4
<!--
5
https://bugzilla.mozilla.org/show_bug.cgi?id=418986
6
-->
7
<window title="Mozilla Bug 418986"
8
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
9
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
10
  <!-- test results are displayed in the html:body -->
11
  <body xmlns="http://www.w3.org/1999/xhtml">
12
  <style id="test-css" scoped="true"></style>
13
  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986"
14
     target="_blank">Mozilla Bug 418986</a>
15
  <p id="display"></p>
16
17
  </body>
18
19
  <script type="text/javascript;version=1.7" src="bug418986-2.js"></script>
20
  <!-- test code goes here -->
21
  <script type="text/javascript;version=1.7">
22
    // Run all tests now.
23
    window.onload = function () {
24
      test(false);
25
    };
26
  </script>
27
</window>
(-)a/layout/style/test/mochitest.ini (+2 lines)
Line     Link Here 
 Lines 5-10   support-files = Link Here 
5
  ccd.sjs
5
  ccd.sjs
6
  ccd-standards.html
6
  ccd-standards.html
7
  css_properties.js
7
  css_properties.js
8
  chrome/bug418986-2.js
8
  descriptor_database.js
9
  descriptor_database.js
9
  empty.html
10
  empty.html
10
  media_queries_dynamic_xbl_binding.xml
11
  media_queries_dynamic_xbl_binding.xml
 Lines 75-80   skip-if = true # Bug 701060 Link Here 
75
[test_bug412901.html]
76
[test_bug412901.html]
76
skip-if = android_version == '18' # bug 1147986
77
skip-if = android_version == '18' # bug 1147986
77
[test_bug413958.html]
78
[test_bug413958.html]
79
[test_bug418986-2.html]
78
[test_bug437915.html]
80
[test_bug437915.html]
79
[test_bug450191.html]
81
[test_bug450191.html]
80
[test_bug453896_deck.html]
82
[test_bug453896_deck.html]
(-)a/layout/style/test/test_bug418986-2.html (-1 / +29 lines)
Line     Link Here 
Line 0    Link Here 
0
- 
1
<!DOCTYPE HTML>
2
<html>
3
<!--
4
https://bugzilla.mozilla.org/show_bug.cgi?id=418986
5
-->
6
<head>
7
  <meta charset="utf-8">
8
  <title>Test 2/3 for Bug #418986: Resist fingerprinting by preventing exposure of screen and system info</title>
9
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
10
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
11
  <style id="test-css"></style>
12
  <script type="text/javascript;version=1.7" src="chrome/bug418986-2.js"></script>
13
  <script type="text/javascript;version=1.7">
14
    // Run all tests now.
15
    window.onload = function () {
16
      test(true);
17
    };
18
  </script>
19
</head>
20
<body>
21
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a>
22
<p id="display">TEST</p>
23
<div id="content" style="display: none">
24
25
</div>
26
<pre id="test">
27
</pre>
28
</body>
29
</html>

Return to bug 418986