Bug 1281963 - Hide mime types and plugins when resisting fingerprinting. r=blassey
authorArthur Edelstein <arthuredelstein@gmail.com>
Thu, 30 Jun 2016 08:40:00 +0200
changeset 383198 dd2cdd2663620b0ee532786e5609bdddce6aa847
parent 383197 eb6de343924f07e384be029a11c2404b7ac5e3df
child 383199 15e7cce04da4e4267ae9e92b328296c9ca9f08e3
push id21963
push userdmitchell@mozilla.com
push dateFri, 01 Jul 2016 19:54:18 +0000
reviewersblassey
bugs1281963
milestone50.0a1
Bug 1281963 - Hide mime types and plugins when resisting fingerprinting. r=blassey
dom/base/nsMimeTypeArray.cpp
dom/base/nsPluginArray.cpp
dom/base/test/mochitest.ini
dom/base/test/test_bug1281963.html
--- a/dom/base/nsMimeTypeArray.cpp
+++ b/dom/base/nsMimeTypeArray.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/dom/MimeTypeBinding.h"
 #include "nsIDOMNavigator.h"
 #include "nsPIDOMWindow.h"
 #include "nsPluginArray.h"
 #include "nsIMIMEService.h"
 #include "nsIMIMEInfo.h"
 #include "Navigator.h"
 #include "nsServiceManagerUtils.h"
+#include "nsContentUtils.h"
 #include "nsPluginTags.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMimeTypeArray)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMimeTypeArray)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMimeTypeArray)
@@ -35,16 +36,22 @@ nsMimeTypeArray::nsMimeTypeArray(nsPIDOM
   : mWindow(aWindow)
 {
 }
 
 nsMimeTypeArray::~nsMimeTypeArray()
 {
 }
 
+static bool
+ResistFingerprinting() {
+  return !nsContentUtils::ThreadsafeIsCallerChrome() &&
+         nsContentUtils::ResistFingerprinting();
+}
+
 JSObject*
 nsMimeTypeArray::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MimeTypeArrayBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 nsMimeTypeArray::Refresh()
@@ -73,16 +80,20 @@ nsMimeTypeArray::NamedItem(const nsAStri
   return NamedGetter(aName, unused);
 }
 
 nsMimeType*
 nsMimeTypeArray::IndexedGetter(uint32_t aIndex, bool &aFound)
 {
   aFound = false;
 
+  if (ResistFingerprinting()) {
+    return nullptr;
+  }
+
   EnsurePluginMimeTypes();
 
   if (aIndex >= mMimeTypes.Length()) {
     return nullptr;
   }
 
   aFound = true;
 
@@ -103,16 +114,20 @@ FindMimeType(const nsTArray<RefPtr<nsMim
   return nullptr;
 }
 
 nsMimeType*
 nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
 {
   aFound = false;
 
+  if (ResistFingerprinting()) {
+    return nullptr;
+  }
+
   EnsurePluginMimeTypes();
 
   nsString lowerName(aName);
   ToLowerCase(lowerName);
 
   nsMimeType* mimeType = FindMimeType(mMimeTypes, lowerName);
   if (mimeType) {
     aFound = true;
@@ -120,16 +135,20 @@ nsMimeTypeArray::NamedGetter(const nsASt
   }
 
   return nullptr;
 }
 
 uint32_t
 nsMimeTypeArray::Length()
 {
+  if (ResistFingerprinting()) {
+    return 0;
+  }
+
   EnsurePluginMimeTypes();
 
   return mMimeTypes.Length();
 }
 
 void
 nsMimeTypeArray::GetSupportedNames(nsTArray<nsString>& aRetval)
 {
--- a/dom/base/nsPluginArray.cpp
+++ b/dom/base/nsPluginArray.cpp
@@ -16,16 +16,17 @@
 #include "nsPluginHost.h"
 #include "nsPluginTags.h"
 #include "nsIObserverService.h"
 #include "nsIWeakReference.h"
 #include "mozilla/Services.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPermissionManager.h"
 #include "nsIDocument.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsPluginArray::nsPluginArray(nsPIDOMWindowInner* aWindow)
   : mWindow(aWindow)
 {
 }
@@ -39,16 +40,22 @@ nsPluginArray::Init()
     obsService->AddObserver(this, "plugin-info-updated", true);
   }
 }
 
 nsPluginArray::~nsPluginArray()
 {
 }
 
+static bool
+ResistFingerprinting() {
+  return !nsContentUtils::ThreadsafeIsCallerChrome() &&
+         nsContentUtils::ResistFingerprinting();
+}
+
 nsPIDOMWindowInner*
 nsPluginArray::GetParentObject() const
 {
   MOZ_ASSERT(mWindow);
   return mWindow;
 }
 
 JSObject*
@@ -165,17 +172,17 @@ nsPluginArray::Refresh(bool aReloadDocum
   }
 }
 
 nsPluginElement*
 nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
 {
   aFound = false;
 
-  if (!AllowPlugins()) {
+  if (!AllowPlugins() || ResistFingerprinting()) {
     return nullptr;
   }
 
   EnsurePlugins();
 
   aFound = aIndex < mPlugins.Length();
 
   if (!aFound) {
@@ -212,17 +219,17 @@ FindPlugin(const nsTArray<RefPtr<nsPlugi
   return nullptr;
 }
 
 nsPluginElement*
 nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
 {
   aFound = false;
 
-  if (!AllowPlugins()) {
+  if (!AllowPlugins() || ResistFingerprinting()) {
     return nullptr;
   }
 
   EnsurePlugins();
 
   nsPluginElement* plugin = FindPlugin(mPlugins, aName);
   aFound = (plugin != nullptr);
   if (!aFound) {
@@ -233,17 +240,17 @@ nsPluginArray::NamedGetter(const nsAStri
     }
   }
   return plugin;
 }
 
 uint32_t
 nsPluginArray::Length()
 {
-  if (!AllowPlugins()) {
+  if (!AllowPlugins() || ResistFingerprinting()) {
     return 0;
   }
 
   EnsurePlugins();
 
   return mPlugins.Length();
 }
 
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -625,16 +625,17 @@ skip-if = buildapp == 'b2g'
 [test_bug1165501.html]
 [test_bug1187157.html]
 [test_bug1198095.html]
 [test_bug1238440.html]
 [test_bug1250148.html]
 [test_bug1259588.html]
 [test_bug1263696.html]
 [test_bug1274806.html]
+[test_bug1281963.html]
 [test_caretPositionFromPoint.html]
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_classList.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_copyimage.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1281963.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/1281963
+-->
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=utf-8">
+  <title>Test for Bug 1281963</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content"></div>
+
+<script class="testbody" type="application/javascript;version=1.7">
+
+// __setPref(key, value)__.
+// Set a pref value asynchronously, returning a promise that resolves
+// when it succeeds.
+let setPref = function* (key, value) {
+  return new Promise(function(resolve, reject) {
+    SpecialPowers.pushPrefEnv({"set": [[key, value]]}, resolve);
+  });
+};
+
+// Run a test to see that we don't expose the supported mimeTypes
+// or installed plugins when "privacy.resistFingerprinting" is active.
+add_task(function* () {
+  let exampleMimeType = undefined,
+      examplePlugin = undefined;
+  // Disable fingerprinting resistance.
+  yield setPref("privacy.resistFingerprinting", false);
+  // Depending on the testing platform, we may have at least
+  // one mimeType and plugin available.
+  exampleMimeType = navigator.mimeTypes[0];
+  examplePlugin = navigator.plugins[0];
+
+  // First check that we can retrieve mimeType or plugin by name and that
+  // the array length is nonzero.
+  if (exampleMimeType) {
+    isnot(navigator.mimeTypes[exampleMimeType.type], undefined, "Should reveal mime type");
+    isnot(navigator.mimeTypes.length, 0, "navigator.mimeTypes.length should be nonzero");
+  }
+  if (examplePlugin) {
+    isnot(navigator.plugins[examplePlugin.name], undefined, "Should reveal plugin");
+    isnot(navigator.plugins.length, 0, "navigator.plugins.length should be nonzero");
+  }
+
+  // Now test with fingerprinting resistance enabled
+  yield setPref("privacy.resistFingerprinting", true);
+  if (exampleMimeType) {
+    is(navigator.mimeTypes[exampleMimeType.type], undefined, "Don't reveal mime type");
+  }
+  is(navigator.mimeTypes[0], undefined, "Don't reveal mime type");
+  is(navigator.mimeTypes.length, 0, "navigator.mimeTypes.length should be 0");
+  if (examplePlugin) {
+    is(navigator.plugins[examplePlugin.name], undefined, "Don't reveal plugin");
+  }
+  is(navigator.plugins[0], undefined, "Don't reveal plugin");
+  is(navigator.plugins.length, 0, "navigator.plugins.length should be 0");
+});
+
+</script>
+
+</body>
+</html>