Bug 1382533 - Disable Presentation API when privacy.resistFingerprinting = true draft
authorChung-Sheng Fu <cfu@mozilla.com>
Wed, 09 Aug 2017 17:38:30 +0800
changeset 657234 bdfb69be0fce8fee1bc3b51918840f6454640c4e
parent 657025 14eea6bedcf3e2f46ea7c908e1ac9b7d256a42f0
child 657235 ed4ded0f49d68785a7b8e1649a6eb685abf437a6
push id77488
push userbmo:cfu@mozilla.com
push dateFri, 01 Sep 2017 08:33:09 +0000
bugs1382533
milestone57.0a1
Bug 1382533 - Disable Presentation API when privacy.resistFingerprinting = true 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;
   }