Bug 776934 - Add permissions check to camera API. r=jlebar
authorMike Habicher <mikeh@mozilla.com>
Fri, 21 Sep 2012 06:32:18 -0400
changeset 114586 da5b2bdfd1153b8edca68de4b9d48c11780ef523
parent 114585 31084b468d5ac65ce91710e491ae1f6c552e978a
child 114587 1d44fb1eef16c1faaafdfe0e5db2e9c52d6a040b
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs776934
milestone18.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 776934 - Add permissions check to camera API. r=jlebar
dom/base/Navigator.cpp
dom/bluetooth/BluetoothManager.cpp
dom/camera/DOMCameraControl.h
dom/camera/DOMCameraManager.cpp
dom/camera/DOMCameraManager.h
dom/camera/ICameraControl.h
dom/power/PowerManager.cpp
dom/sms/src/SmsManager.cpp
dom/telephony/Telephony.cpp
extensions/cookie/nsPermissionManager.cpp
netwerk/base/public/nsIPermissionManager.idl
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1157,25 +1157,22 @@ NS_IMETHODIMP
 Navigator::GetMozVoicemail(nsIDOMMozVoicemail** aVoicemail)
 {
   *aVoicemail = nullptr;
 
   if (!mVoicemail) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
     NS_ENSURE_TRUE(window, NS_OK);
 
-    nsCOMPtr<nsIDocument> document = do_QueryInterface(window->GetExtantDocument());
-    NS_ENSURE_TRUE(document, NS_OK);
-    nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
     nsCOMPtr<nsIPermissionManager> permMgr =
       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
     NS_ENSURE_TRUE(permMgr, NS_OK);
 
     uint32_t permission = nsIPermissionManager::DENY_ACTION;
-    permMgr->TestPermissionFromPrincipal(principal, "voicemail", &permission);
+    permMgr->TestPermissionFromWindow(window, "voicemail", &permission);
 
     if (permission != nsIPermissionManager::ALLOW_ACTION) {
       return NS_OK;
     }
 
     nsresult rv = NS_NewVoicemail(window, getter_AddRefs(mVoicemail));
     NS_ENSURE_SUCCESS(rv, rv);
   }
@@ -1215,25 +1212,22 @@ NS_IMETHODIMP
 Navigator::GetMozMobileConnection(nsIDOMMozMobileConnection** aMobileConnection)
 {
   *aMobileConnection = nullptr;
 
   if (!mMobileConnection) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
     NS_ENSURE_TRUE(window, NS_OK);
 
-    nsCOMPtr<nsIDocument> document = do_QueryInterface(window->GetExtantDocument());
-    NS_ENSURE_TRUE(document, NS_OK);
-    nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
     nsCOMPtr<nsIPermissionManager> permMgr =
       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
     NS_ENSURE_TRUE(permMgr, NS_OK);
 
     uint32_t permission = nsIPermissionManager::DENY_ACTION;
-    permMgr->TestPermissionFromPrincipal(principal, "mobileconnection", &permission);
+    permMgr->TestPermissionFromWindow(window, "mobileconnection", &permission);
 
     if (permission != nsIPermissionManager::ALLOW_ACTION) {
       return NS_OK;
     }
 
     mMobileConnection = new network::MobileConnection();
     mMobileConnection->Init(window);
   }
@@ -1371,17 +1365,18 @@ Navigator::GetMozCameras(nsIDOMCameraMan
   if (!mCameraManager) {
     nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
     NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
 
     if (!win->GetOuterWindow() || win->GetOuterWindow()->GetCurrentInnerWindow() != win) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
-    mCameraManager = nsDOMCameraManager::Create(win->WindowID());
+    mCameraManager = nsDOMCameraManager::CheckPermissionAndCreateInstance(win);
+    NS_ENSURE_TRUE(mCameraManager, NS_OK);
   }
 
   nsRefPtr<nsDOMCameraManager> cameraManager = mCameraManager;
   cameraManager.forget(aCameraManager);
 
   return NS_OK;
 }
 
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -244,35 +244,24 @@ BluetoothManager::Create(nsPIDOMWindow* 
 }
 
 nsresult
 NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
                        nsIDOMBluetoothManager** aBluetoothManager)
 {
   NS_ASSERTION(aWindow, "Null pointer!");
 
-  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
-    aWindow :
-    aWindow->GetCurrentInnerWindow();
-
-  // Need the document for security check.
-  nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
-  NS_ENSURE_TRUE(document, NS_NOINTERFACE);
-
-  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
-  NS_ENSURE_TRUE(principal, NS_ERROR_UNEXPECTED);
-
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, NS_ERROR_UNEXPECTED);
 
   uint32_t permission;
   nsresult rv =
-    permMgr->TestPermissionFromPrincipal(principal, "mozBluetooth",
-                                         &permission);
+    permMgr->TestPermissionFromWindow(aWindow, "mozBluetooth",
+                                      &permission);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<BluetoothManager> bluetoothManager;
 
   if (permission == nsIPermissionManager::ALLOW_ACTION) {
     bluetoothManager = BluetoothManager::Create(aWindow);
   }
 
--- a/dom/camera/DOMCameraControl.h
+++ b/dom/camera/DOMCameraControl.h
@@ -1,17 +1,15 @@
 /* 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/. */
 
 #ifndef DOM_CAMERA_DOMCAMERACONTROL_H
 #define DOM_CAMERA_DOMCAMERACONTROL_H
 
-#include "base/basictypes.h"
-#include "prtypes.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "DictionaryHelpers.h"
 #include "ICameraControl.h"
 #include "DOMCameraPreview.h"
 #include "nsIDOMCameraManager.h"
 #include "CameraCommon.h"
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -1,12 +1,15 @@
 /* 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 "nsDebug.h"
+#include "nsIDocument.h"
+#include "nsIPermissionManager.h"
 #include "DOMCameraControl.h"
 #include "DOMCameraManager.h"
 #include "nsDOMClassInfo.h"
 #include "DictionaryHelpers.h"
 #include "CameraCommon.h"
 
 using namespace mozilla;
 
@@ -22,19 +25,17 @@ NS_IMPL_ADDREF(nsDOMCameraManager)
 NS_IMPL_RELEASE(nsDOMCameraManager)
 
 /**
  * Global camera logging object
  *
  * Set the NSPR_LOG_MODULES environment variable to enable logging
  * in a debug build, e.g. NSPR_LOG_MODULES=Camera:5
  */
-#ifdef PR_LOGGING
-PRLogModuleInfo* gCameraLog;
-#endif
+PRLogModuleInfo* gCameraLog = PR_LOG_DEFINE("Camera");
 
 /**
  * nsDOMCameraManager::GetListOfCameras
  * is implementation-specific, and can be found in (e.g.)
  * GonkCameraManager.cpp and FallbackCameraManager.cpp.
  */
 
 nsDOMCameraManager::nsDOMCameraManager(uint64_t aWindowId)
@@ -53,26 +54,31 @@ nsDOMCameraManager::~nsDOMCameraManager(
 void
 nsDOMCameraManager::OnNavigation(uint64_t aWindowId)
 {
   // TODO: see bug 779145.
 }
 
 // static creator
 already_AddRefed<nsDOMCameraManager>
-nsDOMCameraManager::Create(uint64_t aWindowId)
+nsDOMCameraManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
 {
-  // TODO: see bug 776934.
+  nsCOMPtr<nsIPermissionManager> permMgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(permMgr, nullptr);
 
-#ifdef PR_LOGGING
-  if (!gCameraLog) {
-    gCameraLog = PR_LOG_DEFINE("Camera");
+  uint32_t permission = nsIPermissionManager::DENY_ACTION;
+  permMgr->TestPermissionFromWindow(aWindow, "camera", &permission);
+  if (permission != nsIPermissionManager::ALLOW_ACTION) {
+    NS_WARNING("No permission to access camera");
+    return nullptr;
   }
-#endif
-  nsRefPtr<nsDOMCameraManager> cameraManager = new nsDOMCameraManager(aWindowId);
+
+  nsRefPtr<nsDOMCameraManager> cameraManager =
+    new nsDOMCameraManager(aWindow->WindowID());
   return cameraManager.forget();
 }
 
 /* [implicit_jscontext] void getCamera ([optional] in jsval aOptions, in nsICameraGetCameraCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
 NS_IMETHODIMP
 nsDOMCameraManager::GetCamera(const JS::Value& aOptions, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
 {
   NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -9,23 +9,26 @@
 
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMCameraManager.h"
 #include "mozilla/Attributes.h"
 
+class nsPIDOMWindow;
+
 class nsDOMCameraManager MOZ_FINAL : public nsIDOMCameraManager
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMCAMERAMANAGER
 
-  static already_AddRefed<nsDOMCameraManager> Create(uint64_t aWindowId);
+  static already_AddRefed<nsDOMCameraManager>
+    CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow);
 
   void OnNavigation(uint64_t aWindowId);
 
 private:
   nsDOMCameraManager();
   nsDOMCameraManager(uint64_t aWindowId);
   nsDOMCameraManager(const nsDOMCameraManager&) MOZ_DELETE;
   nsDOMCameraManager& operator=(const nsDOMCameraManager&) MOZ_DELETE;
--- a/dom/camera/ICameraControl.h
+++ b/dom/camera/ICameraControl.h
@@ -1,17 +1,15 @@
 /* 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/. */
 
 #ifndef DOM_CAMERA_ICAMERACONTROL_H
 #define DOM_CAMERA_ICAMERACONTROL_H
 
-#include "base/basictypes.h"
-#include "prtypes.h"
 #include "jsapi.h"
 #include "nsIDOMCameraManager.h"
 #include "DictionaryHelpers.h"
 #include "CameraCommon.h"
 
 namespace mozilla {
 
 using namespace dom;
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -170,32 +170,22 @@ PowerManager::SetCpuSleepAllowed(bool aA
 {
   hal::SetCpuSleepAllowed(aAllowed);
   return NS_OK;
 }
 
 already_AddRefed<PowerManager>
 PowerManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
 {
-  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
-    aWindow :
-    aWindow->GetCurrentInnerWindow();
-
-  // Need the document for security check.
-  nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
-  NS_ENSURE_TRUE(document, nullptr);
-
-  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
-
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, nullptr);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
-  permMgr->TestPermissionFromPrincipal(principal, "power", &permission);
+  permMgr->TestPermissionFromWindow(aWindow, "power", &permission);
 
   if (permission != nsIPermissionManager::ALLOW_ACTION) {
     return nullptr;
   }
 
   nsRefPtr<PowerManager> powerManager = new PowerManager();
   powerManager->Init(aWindow);
 
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -64,34 +64,22 @@ SmsManager::CheckPermissionAndCreateInst
 {
   NS_ASSERTION(aWindow, "Null pointer!");
 
   // First of all, the general pref has to be turned on.
   bool enabled = false;
   Preferences::GetBool("dom.sms.enabled", &enabled);
   NS_ENSURE_TRUE(enabled, nullptr);
 
-  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
-    aWindow :
-    aWindow->GetCurrentInnerWindow();
-
-  // Need the document for security check.
-  nsCOMPtr<nsIDocument> document =
-    do_QueryInterface(innerWindow->GetExtantDocument());
-  NS_ENSURE_TRUE(document, nullptr);
-
-  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
-  NS_ENSURE_TRUE(principal, nullptr);
-
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, nullptr);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
-  permMgr->TestPermissionFromPrincipal(principal, "sms", &permission);
+  permMgr->TestPermissionFromWindow(aWindow, "sms", &permission);
 
   if (permission != nsIPermissionManager::ALLOW_ACTION) {
     return nullptr;
   }
 
   nsRefPtr<SmsManager> smsMgr = new SmsManager();
   smsMgr->Init(aWindow);
 
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -531,31 +531,23 @@ nsresult
 NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony)
 {
   NS_ASSERTION(aWindow, "Null pointer!");
 
   nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
     aWindow :
     aWindow->GetCurrentInnerWindow();
 
-  // Need the document for security check.
-  nsCOMPtr<nsIDocument> document =
-    do_QueryInterface(innerWindow->GetExtantDocument());
-  NS_ENSURE_TRUE(document, NS_NOINTERFACE);
-
-  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
-  NS_ENSURE_TRUE(principal, NS_ERROR_UNEXPECTED);
-
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, NS_ERROR_UNEXPECTED);
 
   uint32_t permission;
   nsresult rv =
-    permMgr->TestPermissionFromPrincipal(principal, "telephony", &permission);
+    permMgr->TestPermissionFromWindow(aWindow, "telephony", &permission);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (permission != nsIPermissionManager::ALLOW_ACTION) {
     *aTelephony = nullptr;
     return NS_OK;
   }
 
   nsCOMPtr<nsIRILContentHelper> ril =
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -905,16 +905,36 @@ nsPermissionManager::TestPermission(nsIU
   nsCOMPtr<nsIPrincipal> principal;
   nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return TestPermissionFromPrincipal(principal, aType, aPermission);
 }
 
 NS_IMETHODIMP
+nsPermissionManager::TestPermissionFromWindow(nsIDOMWindow* aWindow,
+                                              const char* aType,
+                                              uint32_t* aPermission)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
+  NS_ENSURE_TRUE(window, NS_NOINTERFACE);
+
+  nsPIDOMWindow* innerWindow = window->IsInnerWindow() ?
+    window.get() :
+    window->GetCurrentInnerWindow();
+
+  // Get the document for security check
+  nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
+  NS_ENSURE_TRUE(document, NS_NOINTERFACE);
+
+  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
+  return TestPermissionFromPrincipal(principal, aType, aPermission);
+}
+
+NS_IMETHODIMP
 nsPermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal,
                                                  const char* aType,
                                                  uint32_t* aPermission)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
   // System principals do not have URI so we can't try to get
   // retro-compatibility here.
--- a/netwerk/base/public/nsIPermissionManager.idl
+++ b/netwerk/base/public/nsIPermissionManager.idl
@@ -29,18 +29,19 @@
  */
 
 #include "nsISupports.idl"
 #include "nsISimpleEnumerator.idl"
 
 interface nsIURI;
 interface nsIObserver;
 interface nsIPrincipal;
+interface nsIDOMWindow;
 
-[scriptable, uuid(da33450a-f3cb-4fdb-93ee-219644e450c2)]
+[scriptable, uuid(ad79e135-6904-4734-8137-a511016d2723)]
 interface nsIPermissionManager : nsISupports
 {
   /**
    * Predefined return values for the testPermission method and for
    * the permission param of the add method
    * NOTE: UNKNOWN_ACTION (0) is reserved to represent the
    * default permission when no entry is found for a host, and
    * should not be used by consumers to indicate otherwise.
@@ -142,16 +143,24 @@ interface nsIPermissionManager : nsISupp
   /**
    * Test whether the principal has the permission to perform a given action.
    * System principals will always have permissions granted.
    */
   uint32_t testPermissionFromPrincipal(in nsIPrincipal principal,
                                        in string type);
 
   /**
+   * Test whether the principal associated with the window's document has the
+   * permission to perform a given action.  System principals will always
+   * have permissions granted.
+   */
+  uint32_t testPermissionFromWindow(in nsIDOMWindow window,
+                                    in string type);
+
+  /**
    * Test whether a website has permission to perform the given action.
    * This requires an exact hostname match, subdomains are not a match.
    * @param uri     the uri to be tested
    * @param type    a case-sensitive ASCII string, identifying the consumer
    * @param return  see add(), param permission. returns UNKNOWN_ACTION when
    *                there is no stored permission for this uri and / or type.
    */
   uint32_t testExactPermission(in nsIURI uri,