Bug 1046245 - enumerateDevices returns label for pages w/active gUM or persistent permissions. r=jesup
authorJan-Ivar Bruaroey <jib@mozilla.com>
Tue, 03 Mar 2015 09:51:05 -0500
changeset 265271 c47fa3802a576b6f42232b8a9a3b86e9658e5e61
parent 265270 b9458ee8b29704620b7bac91d60bfb5f41efd6c1
child 265272 7b6b68c413ffeaf67458c040fbd7e651b086b7e7
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1046245
milestone39.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 1046245 - enumerateDevices returns label for pages w/active gUM or persistent permissions. r=jesup
dom/media/MediaDevices.cpp
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaDevices.cpp
+++ b/dom/media/MediaDevices.cpp
@@ -4,16 +4,17 @@
 
 #include "mozilla/dom/MediaDevices.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaDevicesBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/MediaManager.h"
 #include "nsIEventTarget.h"
 #include "nsIScriptGlobalObject.h"
+#include "nsIPermissionManager.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 class MediaDevices::GumResolver : public nsIDOMGetUserMediaSuccessCallback
 {
 public:
@@ -34,20 +35,53 @@ public:
 
 private:
   virtual ~GumResolver() {}
   nsRefPtr<Promise> mPromise;
 };
 
 class MediaDevices::EnumDevResolver : public nsIGetUserMediaDevicesSuccessCallback
 {
+  static bool HasAPersistentPermission(uint64_t aWindowId)
+  {
+    nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
+        (nsGlobalWindow::GetInnerWindowWithId(aWindowId));
+    if (NS_WARN_IF(!window)) {
+      return false;
+    }
+    // Check if this site has persistent permissions.
+    nsresult rv;
+    nsCOMPtr<nsIPermissionManager> mgr =
+      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return false; // no permission manager no permissions!
+    }
+
+    uint32_t audio = nsIPermissionManager::UNKNOWN_ACTION;
+    uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
+    {
+      auto* principal = window->GetExtantDoc()->NodePrincipal();
+      rv = mgr->TestExactPermissionFromPrincipal(principal, "microphone", &audio);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return false;
+      }
+      rv = mgr->TestExactPermissionFromPrincipal(principal, "camera", &video);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return false;
+      }
+    }
+    return audio == nsIPermissionManager::ALLOW_ACTION ||
+           video == nsIPermissionManager::ALLOW_ACTION;
+  }
+
 public:
   NS_DECL_ISUPPORTS
 
-  explicit EnumDevResolver(Promise* aPromise) : mPromise(aPromise) {}
+  EnumDevResolver(Promise* aPromise, uint64_t aWindowId)
+  : mPromise(aPromise), mWindowId(aWindowId) {}
 
   NS_IMETHOD
   OnSuccess(nsIVariant* aDevices) override
   {
     // Cribbed from MediaPermissionGonk.cpp
     nsIID elementIID;
     uint16_t elementType;
 
@@ -78,29 +112,40 @@ public:
     for (auto& device : devices) {
       nsString type;
       device->GetType(type);
       bool isVideo = type.EqualsLiteral("video");
       bool isAudio = type.EqualsLiteral("audio");
       if (isVideo || isAudio) {
         MediaDeviceKind kind = isVideo ?
             MediaDeviceKind::Videoinput : MediaDeviceKind::Audioinput;
-        // TODO: return anonymized id, +label (origins w/gUM permission) (1046245)
+        nsString id;
+        nsString name;
+        device->GetId(id);
+        // Include name only if page currently has a gUM stream active or
+        // persistent permissions (audio or video) have been granted
+        if (MediaManager::Get()->IsWindowActivelyCapturing(mWindowId) ||
+            HasAPersistentPermission(mWindowId) ||
+            Preferences::GetBool("media.navigator.permission.disabled", false)) {
+          device->GetName(name);
+        }
+        // TODO: return anonymized origin-persistent id (1046245)
         nsRefPtr<MediaDeviceInfo> info = new MediaDeviceInfo(nsString(), kind,
-                                                             nsString());
+                                                             name);
         infos.AppendElement(info);
       }
     }
     mPromise->MaybeResolve(infos);
     return NS_OK;
   }
 
 private:
   virtual ~EnumDevResolver() {}
   nsRefPtr<Promise> mPromise;
+  uint64_t mWindowId;
 };
 
 class MediaDevices::GumRejecter : public nsIDOMGetUserMediaErrorCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
   explicit GumRejecter(Promise* aPromise) : mPromise(aPromise) {}
@@ -145,17 +190,17 @@ MediaDevices::GetUserMedia(const MediaSt
 already_AddRefed<Promise>
 MediaDevices::EnumerateDevices(ErrorResult &aRv)
 {
   nsPIDOMWindow* window = GetOwner();
   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window);
   nsRefPtr<Promise> p = Promise::Create(go, aRv);
   NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
 
-  nsRefPtr<EnumDevResolver> resolver = new EnumDevResolver(p);
+  nsRefPtr<EnumDevResolver> resolver = new EnumDevResolver(p, window->WindowID());
   nsRefPtr<GumRejecter> rejecter = new GumRejecter(p);
 
   aRv = MediaManager::Get()->EnumerateDevices(window, resolver, rejecter);
   return p.forget();
 }
 
 NS_IMPL_ADDREF_INHERITED(MediaDevices, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MediaDevices, DOMEventTargetHelper)
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2363,16 +2363,34 @@ MediaManager::StopMediaStreams()
     array->GetElementAt(i, getter_AddRefs(window));
     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(window));
     if (win) {
       OnNavigation(win->WindowID());
     }
   }
 }
 
+bool
+MediaManager::IsWindowActivelyCapturing(uint64_t aWindowId)
+{
+  nsCOMPtr<nsISupportsArray> array;
+  GetActiveMediaCaptureWindows(getter_AddRefs(array));
+  uint32_t len;
+  array->Count(&len);
+  for (uint32_t i = 0; i < len; i++) {
+    nsCOMPtr<nsISupports> window;
+    array->GetElementAt(i, getter_AddRefs(window));
+    nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(window));
+    if (win && win->WindowID() == aWindowId) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void
 GetUserMediaCallbackMediaStreamListener::AudioConfig(bool aEchoOn,
               uint32_t aEcho,
               bool aAgcOn, uint32_t aAGC,
               bool aNoiseOn, uint32_t aNoise,
               int32_t aPlayoutDelay)
 {
   if (mAudioSource) {
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -598,16 +598,17 @@ public:
     uint64_t aInnerWindowID = 0);
 
   nsresult EnumerateDevices(nsPIDOMWindow* aWindow,
                             nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
                             nsIDOMGetUserMediaErrorCallback* aOnFailure);
 
   nsresult EnumerateDevices(nsPIDOMWindow* aWindow, dom::Promise& aPromise);
   void OnNavigation(uint64_t aWindowID);
+  bool IsWindowActivelyCapturing(uint64_t aWindowId);
 
   MediaEnginePrefs mPrefs;
 
 private:
   StreamListeners* AddWindowID(uint64_t aWindowId);
   WindowTable *GetActiveWindows() {
     NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
     return &mActiveWindows;