Bug 1037424 - Part 1: Implement prefs-based screenshare domain whitelist in MediaManager. r=mt,ehugg a=sylvestre
authorPaul Kerr [:pkerr] <pkerr@mozilla.com>
Wed, 30 Jul 2014 17:03:20 -0400
changeset 209292 79626072eee791fda8e9b994f7b862ffc32db9ea
parent 209291 126d41d598be3b3f5b0c0080d8ebb885f89e5d69
child 209293 4f0cef5f09b49eb2fde529b1e2d0f89654990960
push id6623
push userrjesup@wgate.com
push dateThu, 07 Aug 2014 22:43:24 +0000
treeherdermozilla-aurora@793c7a968030 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmt, ehugg, sylvestre
bugs1037424
milestone33.0a2
Bug 1037424 - Part 1: Implement prefs-based screenshare domain whitelist in MediaManager. r=mt,ehugg a=sylvestre
dom/media/MediaManager.cpp
modules/libpref/src/init/all.js
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -18,16 +18,17 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsIPermissionManager.h"
 #include "nsIPopupWindowManager.h"
 #include "nsISupportsArray.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIInterfaceRequestorUtils.h"
+#include "nsIIDNService.h"
 #include "nsNetUtil.h"
 #include "mozilla/Types.h"
 #include "mozilla/PeerIdentity.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/GetUserMediaRequestBinding.h"
 #include "mozilla/Preferences.h"
@@ -95,16 +96,69 @@ using dom::MediaStreamConstraints;      
 using dom::MediaTrackConstraintSet;        // Mandatory or optional constraints
 using dom::MediaTrackConstraints;          // Raw mMandatory (as JSObject)
 using dom::GetUserMediaRequest;
 using dom::Sequence;
 using dom::OwningBooleanOrMediaTrackConstraints;
 using dom::SupportedAudioConstraints;
 using dom::SupportedVideoConstraints;
 
+
+static bool
+HostHasPermission(nsIURI &docURI)
+{
+  nsAdoptingCString hostName;
+  docURI.GetAsciiHost(hostName); //normalize UTF8 to ASCII equivalent
+  nsAdoptingCString domainWhiteList =
+    Preferences::GetCString("media.getusermedia.screensharing.allowed_domains");
+  domainWhiteList.StripWhitespace();
+
+  if (domainWhiteList.IsEmpty() || hostName.IsEmpty()) {
+    return false;
+  }
+
+  nsresult rv;
+  // Get UTF8 to ASCII domain name normalization service
+  nsCOMPtr<nsIIDNService> idnService
+    = do_GetService("@mozilla.org/network/idn-service;1", &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  PRUint32 begin = 0;
+  PRUint32 end = 0;
+  nsCString domainName;
+  /* 
+     Test each domain name in the comma separated list
+     after converting from UTF8 to ASCII. Each domain
+     must match exactly: no wildcards are used.
+  */
+  do {
+    end = domainWhiteList.FindChar(',', begin);
+    if (end == (PRUint32)-1) {
+      // Last or only domain name in the comma separated list
+      end = domainWhiteList.Length();
+    }
+
+    rv = idnService->ConvertUTF8toACE(Substring(domainWhiteList, begin, end - begin),
+                                      domainName);
+    if (NS_SUCCEEDED(rv)) {
+      if (hostName.EqualsIgnoreCase(domainName.Data(), domainName.Length())) {
+        return true;
+      }
+    } else {
+      NS_WARNING("Failed to convert UTF-8 host to ASCII");
+    }
+
+    begin = end + 1;
+  } while (end < domainWhiteList.Length());
+
+  return false;
+}
+
 ErrorCallbackRunnable::ErrorCallbackRunnable(
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
   const nsAString& aErrorMsg, uint64_t aWindowID)
   : mErrorMsg(aErrorMsg)
   , mWindowID(aWindowID)
   , mManager(MediaManager::GetInstance())
 {
@@ -1483,39 +1537,46 @@ MediaManager::GetUserMedia(bool aPrivile
     runnable = new GetUserMediaRunnable(c, onSuccess.forget(),
       onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault());
   } else {
     // Stream from default device from WebRTC backend.
     runnable = new GetUserMediaRunnable(c, onSuccess.forget(),
       onError.forget(), windowID, listener, mPrefs);
   }
 
-  // deny screensharing request if support is disabled
-  if (c.mVideo.IsMediaTrackConstraints() &&
-      !Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
+  nsIURI* docURI = aWindow->GetDocumentURI();
+
+  if (c.mVideo.IsMediaTrackConstraints()) {
     auto& tc = c.mVideo.GetAsMediaTrackConstraints();
+    // deny screensharing request if support is disabled
     if (tc.mMediaSource != dom::MediaSourceEnum::Camera) {
-      return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+      if (!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
+        return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+      }
+      /* Deny screensharing if the requesting document is not from a host
+       on the whitelist. */
+      if (!HostHasPermission(*docURI)) {
+        return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+      }
     }
   }
 
 #ifdef MOZ_B2G_CAMERA
   if (mCameraManager == nullptr) {
     mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
   }
 #endif
 
 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
   if (c.mPicture) {
     // ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
     NS_DispatchToMainThread(runnable);
     return NS_OK;
   }
 #endif
-  nsIURI* docURI = aWindow->GetDocumentURI();
 
   bool isLoop = false;
   nsCOMPtr<nsIURI> loopURI;
   nsresult rv = NS_NewURI(getter_AddRefs(loopURI), "about:loopconversation");
   NS_ENSURE_SUCCESS(rv, rv);
   rv = docURI->EqualsExceptRef(loopURI, &isLoop);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -361,16 +361,17 @@ pref("media.navigator.enabled", true);
 #endif
 #endif
 
 // do not enable screensharing before addressing security concerns: Bug 1035577
 // do not enable screensharing before implementing app/window sharing: Bug 1036653
 // do not enable screensharing before source constraints are finalized: Bug 1033885
 // do not enable screensharing before UX is ready: Bug 1035577
 pref("media.getusermedia.screensharing.enabled", false);
+pref("media.getusermedia.screensharing.allowed_domains", "");
 
 // TextTrack support
 pref("media.webvtt.enabled", true);
 pref("media.webvtt.regions.enabled", false);
 
 // AudioTrack and VideoTrack support
 pref("media.track.enabled", false);