Bug 776934 - Add permissions check to camera API. r=jlebar
authorMike Habicher <mikeh@mozilla.com>
Fri, 21 Sep 2012 06:32:18 -0400
changeset 111314 da5b2bdfd1153b8edca68de4b9d48c11780ef523
parent 111313 31084b468d5ac65ce91710e491ae1f6c552e978a
child 111315 1d44fb1eef16c1faaafdfe0e5db2e9c52d6a040b
push id2248
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 19:23:44 +0000
treeherdermozilla-aurora@118a3b748323 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs776934
milestone18.0a1
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,