Bug 1382533 - Disable Presentation API when privacy.resistFingerprinting = true r=arthuredelstein,smaug
authorChung-Sheng Fu <cfu@mozilla.com>
Wed, 09 Aug 2017 17:38:30 +0800
changeset 428943 aad2ab1d510cf39ebb0684aa9e9b15572c6cd73c
parent 428942 3c5539322b579b27c178fde7af6c3f20c42224ec
child 428944 92659c8ed9f20e968f6cc764328cc002da831471
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarthuredelstein, smaug
bugs1382533
milestone57.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
Bug 1382533 - Disable Presentation API when privacy.resistFingerprinting = true r=arthuredelstein,smaug MozReview-Commit-ID: IDKEqSqm9Ug
dom/presentation/Presentation.cpp
dom/presentation/PresentationAvailability.cpp
dom/presentation/PresentationConnection.cpp
dom/presentation/PresentationConnectionList.cpp
dom/presentation/PresentationReceiver.cpp
dom/presentation/PresentationRequest.cpp
dom/presentation/PresentationSessionInfo.cpp
--- a/dom/presentation/Presentation.cpp
+++ b/dom/presentation/Presentation.cpp
@@ -58,38 +58,50 @@ Presentation::WrapObject(JSContext* aCx,
                          JS::Handle<JSObject*> aGivenProto)
 {
   return PresentationBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 Presentation::SetDefaultRequest(PresentationRequest* aRequest)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   nsCOMPtr<nsIDocument> doc = mWindow ? mWindow->GetExtantDoc() : nullptr;
   if (NS_WARN_IF(!doc)) {
     return;
   }
 
   if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
     return;
   }
 
   mDefaultRequest = aRequest;
 }
 
 already_AddRefed<PresentationRequest>
 Presentation::GetDefaultRequest() const
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return nullptr;
+  }
+
   RefPtr<PresentationRequest> request = mDefaultRequest;
   return request.forget();
 }
 
 already_AddRefed<PresentationReceiver>
 Presentation::GetReceiver()
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return nullptr;
+  }
+
   // return the same receiver if already created
   if (mReceiver) {
     RefPtr<PresentationReceiver> receiver = mReceiver;
     return receiver.forget();
   }
 
   if (!HasReceiverSupport() || !IsInPresentedContent()) {
     return nullptr;
--- a/dom/presentation/PresentationAvailability.cpp
+++ b/dom/presentation/PresentationAvailability.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PresentationAvailability.h"
 
 #include "mozilla/dom/PresentationAvailabilityBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/Unused.h"
+#include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIPresentationDeviceManager.h"
 #include "nsIPresentationService.h"
 #include "nsServiceManagerUtils.h"
 #include "PresentationLog.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -152,16 +153,20 @@ void
 PresentationAvailability::EnqueuePromise(RefPtr<Promise>& aPromise)
 {
   mPromises.AppendElement(aPromise);
 }
 
 bool
 PresentationAvailability::Value() const
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return false;
+  }
+
   return mIsAvailable;
 }
 
 NS_IMETHODIMP
 PresentationAvailability::NotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
                                                 bool aIsAvailable)
 {
   bool available = false;
@@ -186,22 +191,31 @@ PresentationAvailability::UpdateAvailabi
   bool isChanged = (aIsAvailable != mIsAvailable);
 
   mIsAvailable = aIsAvailable;
 
   if (!mPromises.IsEmpty()) {
     // Use the first availability change notification to resolve promise.
     do {
       nsTArray<RefPtr<Promise>> promises = Move(mPromises);
+
+      if (nsContentUtils::ShouldResistFingerprinting()) {
+        continue;
+      }
+
       for (auto& promise : promises) {
         promise->MaybeResolve(this);
       }
       // more promises may have been added to mPromises, at least in theory
     } while (!mPromises.IsEmpty());
 
     return;
   }
 
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   if (isChanged) {
     Unused <<
       NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change"))));
   }
 }
--- a/dom/presentation/PresentationConnection.cpp
+++ b/dom/presentation/PresentationConnection.cpp
@@ -152,47 +152,73 @@ PresentationConnection::WrapObject(JSCon
                                    JS::Handle<JSObject*> aGivenProto)
 {
   return PresentationConnectionBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 PresentationConnection::GetId(nsAString& aId) const
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    aId = EmptyString();
+    return;
+  }
+
   aId = mId;
 }
 
 void
 PresentationConnection::GetUrl(nsAString& aUrl) const
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    aUrl = EmptyString();
+    return;
+  }
+
   aUrl = mUrl;
 }
 
 PresentationConnectionState
 PresentationConnection::State() const
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return PresentationConnectionState::Terminated;
+  }
+
   return mState;
 }
 
 PresentationConnectionBinaryType
 PresentationConnection::BinaryType() const
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return PresentationConnectionBinaryType::Blob;
+  }
+
   return mBinaryType;
 }
 
 void
 PresentationConnection::SetBinaryType(PresentationConnectionBinaryType aType)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   mBinaryType = aType;
 }
 
 void
 PresentationConnection::Send(const nsAString& aData,
                              ErrorResult& aRv)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   // Sending is not allowed if the session is not connected.
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
@@ -212,16 +238,20 @@ PresentationConnection::Send(const nsASt
       NS_LITERAL_STRING("\""));
   }
 }
 
 void
 PresentationConnection::Send(Blob& aData,
                              ErrorResult& aRv)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
@@ -236,16 +266,20 @@ PresentationConnection::Send(Blob& aData
       NS_LITERAL_STRING("Unable to send binary message for Blob message."));
   }
 }
 
 void
 PresentationConnection::Send(const ArrayBuffer& aData,
                              ErrorResult& aRv)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
@@ -268,16 +302,20 @@ PresentationConnection::Send(const Array
       NS_LITERAL_STRING("Unable to send binary message for ArrayBuffer message."));
   }
 }
 
 void
 PresentationConnection::Send(const ArrayBufferView& aData,
                              ErrorResult& aRv)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
@@ -299,16 +337,20 @@ PresentationConnection::Send(const Array
     AsyncCloseConnectionWithErrorMsg(
       NS_LITERAL_STRING("Unable to send binary message for ArrayBufferView message."));
   }
 }
 
 void
 PresentationConnection::Close(ErrorResult& aRv)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   // It only works when the state is CONNECTED or CONNECTING.
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
                  mState != PresentationConnectionState::Connecting)) {
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
@@ -321,16 +363,20 @@ PresentationConnection::Close(ErrorResul
     service->CloseSession(mId,
                           mRole,
                           nsIPresentationService::CLOSED_REASON_CLOSED)));
 }
 
 void
 PresentationConnection::Terminate(ErrorResult& aRv)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return;
+  }
+
   // It only works when the state is CONNECTED.
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
@@ -407,16 +453,20 @@ PresentationConnection::NotifyStateChang
 
 nsresult
 PresentationConnection::ProcessStateChanged(nsresult aReason)
 {
   switch (mState) {
     case PresentationConnectionState::Connecting:
       return NS_OK;
     case PresentationConnectionState::Connected: {
+      if (nsContentUtils::ShouldResistFingerprinting()) {
+        return NS_OK;
+      }
+
       RefPtr<AsyncEventDispatcher> asyncDispatcher =
         new AsyncEventDispatcher(this, NS_LITERAL_STRING("connect"), false);
       return asyncDispatcher->PostDOMEvent();
     }
     case PresentationConnectionState::Closed: {
       PresentationConnectionClosedReason reason =
         PresentationConnectionClosedReason::Closed;
 
@@ -436,20 +486,22 @@ PresentationConnection::ProcessStateChan
       }
 
       Unused <<
         NS_WARN_IF(NS_FAILED(DispatchConnectionCloseEvent(reason, errorMsg)));
 
       return RemoveFromLoadGroup();
     }
     case PresentationConnectionState::Terminated: {
-      // Ensure onterminate event is fired.
-      RefPtr<AsyncEventDispatcher> asyncDispatcher =
-        new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false);
-      Unused << NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
+      if (!nsContentUtils::ShouldResistFingerprinting()) {
+        // Ensure onterminate event is fired.
+        RefPtr<AsyncEventDispatcher> asyncDispatcher =
+          new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false);
+        Unused << NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
+      }
 
       nsCOMPtr<nsIPresentationService> service =
         do_GetService(PRESENTATION_SERVICE_CONTRACTID);
       if (NS_WARN_IF(!service)) {
         return NS_ERROR_NOT_AVAILABLE;
       }
 
       nsresult rv = service->UnregisterSessionListener(mId, mRole);
@@ -490,16 +542,20 @@ PresentationConnection::NotifyMessage(co
   }
 
   return NS_OK;
 }
 
 nsresult
 PresentationConnection::DoReceiveMessage(const nsACString& aData, bool aIsBinary)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return NS_OK;
+  }
+
   // Transform the data.
   AutoJSAPI jsapi;
   if (!jsapi.Init(GetOwner())) {
     return NS_ERROR_FAILURE;
   }
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsData(cx);
 
@@ -535,16 +591,20 @@ PresentationConnection::DoReceiveMessage
 }
 
 nsresult
 PresentationConnection::DispatchConnectionCloseEvent(
   PresentationConnectionClosedReason aReason,
   const nsAString& aMessage,
   bool aDispatchNow)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return NS_OK;
+  }
+
   if (mState != PresentationConnectionState::Closed) {
     MOZ_ASSERT(false, "The connection state should be closed.");
     return NS_ERROR_FAILURE;
   }
 
   PresentationConnectionCloseEventInit init;
   init.mReason = aReason;
   init.mMessage = aMessage;
--- a/dom/presentation/PresentationConnectionList.cpp
+++ b/dom/presentation/PresentationConnectionList.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PresentationConnectionList.h"
 
+#include "nsContentUtils.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/PresentationConnectionAvailableEvent.h"
 #include "mozilla/dom/PresentationConnectionListBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "PresentationConnection.h"
 
 namespace mozilla {
 namespace dom {
@@ -40,23 +41,32 @@ PresentationConnectionList::WrapObject(J
 {
   return PresentationConnectionListBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 PresentationConnectionList::GetConnections(
   nsTArray<RefPtr<PresentationConnection>>& aConnections) const
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    aConnections.Clear();
+    return;
+  }
+
   aConnections = mConnections;
 }
 
 nsresult
 PresentationConnectionList::DispatchConnectionAvailableEvent(
   PresentationConnection* aConnection)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return NS_OK;
+  }
+
   PresentationConnectionAvailableEventInit init;
   init.mConnection = aConnection;
 
   RefPtr<PresentationConnectionAvailableEvent> event =
     PresentationConnectionAvailableEvent::Constructor(
       this,
       NS_LITERAL_STRING("connectionavailable"),
       init);
@@ -99,17 +109,19 @@ PresentationConnectionList::NotifyStateC
     FindConnectionById(aSessionId) != mConnections.NoIndex ? true : false;
 
   PresentationConnectionListBinding::ClearCachedConnectionsValue(this);
   switch (aConnection->State()) {
     case PresentationConnectionState::Connected:
       if (!connectionFound) {
         mConnections.AppendElement(aConnection);
         if (mGetConnectionListPromise) {
-          mGetConnectionListPromise->MaybeResolve(this);
+          if (!nsContentUtils::ShouldResistFingerprinting()) {
+            mGetConnectionListPromise->MaybeResolve(this);
+          }
           mGetConnectionListPromise = nullptr;
           return;
         }
       }
       DispatchConnectionAvailableEvent(aConnection);
       break;
     case PresentationConnectionState::Terminated:
       if (connectionFound) {
--- a/dom/presentation/PresentationReceiver.cpp
+++ b/dom/presentation/PresentationReceiver.cpp
@@ -140,16 +140,19 @@ PresentationReceiver::GetConnectionList(
       [self]() -> void { self->CreateConnectionList(); }));
     if (NS_FAILED(rv)) {
       aRv.Throw(rv);
       return nullptr;
     }
   }
 
   RefPtr<Promise> promise = mGetConnectionListPromise;
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
+  }
   return promise.forget();
 }
 
 void
 PresentationReceiver::CreateConnectionList()
 {
   MOZ_ASSERT(mGetConnectionListPromise);
 
--- a/dom/presentation/PresentationRequest.cpp
+++ b/dom/presentation/PresentationRequest.cpp
@@ -167,16 +167,21 @@ PresentationRequest::StartWithDevice(con
     return nullptr;
   }
 
   RefPtr<Promise> promise = Promise::Create(global, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
+    return promise.forget();
+  }
+
   if (IsProhibitMixedSecurityContexts(doc) &&
       !IsAllURLAuthenticated()) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
   if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
@@ -266,16 +271,21 @@ PresentationRequest::Reconnect(const nsA
     return nullptr;
   }
 
   RefPtr<Promise> promise = Promise::Create(global, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
+    return promise.forget();
+  }
+
   if (IsProhibitMixedSecurityContexts(doc) &&
       !IsAllURLAuthenticated()) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
   if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
@@ -379,16 +389,21 @@ PresentationRequest::GetAvailability(Err
     return nullptr;
   }
 
   RefPtr<Promise> promise = Promise::Create(global, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
+    return promise.forget();
+  }
+
   if (IsProhibitMixedSecurityContexts(doc) &&
       !IsAllURLAuthenticated()) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
   if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
@@ -438,16 +453,20 @@ PresentationRequest::FindOrCreatePresent
     aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 }
 
 nsresult
 PresentationRequest::DispatchConnectionAvailableEvent(PresentationConnection* aConnection)
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return NS_OK;
+  }
+
   PresentationConnectionAvailableEventInit init;
   init.mConnection = aConnection;
 
   RefPtr<PresentationConnectionAvailableEvent> event =
     PresentationConnectionAvailableEvent::Constructor(this,
                                                       NS_LITERAL_STRING("connectionavailable"),
                                                       init);
   if (NS_WARN_IF(!event)) {
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -640,16 +640,20 @@ PresentationControllingInfo::Shutdown(ns
     Unused << NS_WARN_IF(NS_FAILED(mServerSocket->Close()));
     mServerSocket = nullptr;
   }
 }
 
 nsresult
 PresentationControllingInfo::GetAddress()
 {
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    return NS_ERROR_FAILURE;
+  }
+
 #if defined(MOZ_WIDGET_ANDROID)
   RefPtr<PresentationNetworkHelper> networkHelper =
     new PresentationNetworkHelper(this,
                                   &PresentationControllingInfo::OnGetAddress);
   nsresult rv = networkHelper->GetWifiIPAddress();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }