Bug 781353 - Hook up "power" to Permission Manager. r=jlebar
authorKan-Ru Chen (陳侃如) <kanru@kanru.info>
Sat, 11 Aug 2012 19:40:43 +0800
changeset 102184 f111e43bc076331456c5aa3ae68b557d58c5afb1
parent 102183 4b7f0b17d69528e12bc7c73de101a42c85076ae2
child 102185 b753e1dce89f2d569bcd452285514729bbe401d2
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjlebar
bugs781353
milestone17.0a1
Bug 781353 - Hook up "power" to Permission Manager. r=jlebar
dom/base/Navigator.cpp
dom/power/PowerManager.cpp
dom/power/PowerManager.h
dom/power/test/browser_bug697132.js
dom/power/test/test_power_basics.html
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -49,16 +49,18 @@
 #include "nsIDOMBluetoothManager.h"
 #include "BluetoothManager.h"
 #endif
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraManager.h"
 
 #include "nsIDOMGlobalPropertyInitializer.h"
 
+using namespace mozilla::dom::power;
+
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
 
 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 
@@ -1024,21 +1026,21 @@ Navigator::GetBattery(nsIDOMBatteryManag
 }
 
 NS_IMETHODIMP
 Navigator::GetMozPower(nsIDOMMozPowerManager** aPower)
 {
   *aPower = nullptr;
 
   if (!mPowerManager) {
-    nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-    NS_ENSURE_TRUE(win, NS_OK);
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window, NS_OK);
 
-    mPowerManager = new power::PowerManager();
-    mPowerManager->Init(win);
+    mPowerManager = PowerManager::CheckPermissionAndCreateInstance(window);
+    NS_ENSURE_TRUE(mPowerManager, NS_OK);
   }
 
   nsCOMPtr<nsIDOMMozPowerManager> power(mPowerManager);
   power.forget(aPower);
 
   return NS_OK;
 }
 
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -1,19 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "mozilla/Hal.h"
 #include "PowerManager.h"
 #include "WakeLock.h"
-#include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMWakeLockListener.h"
+#include "nsIDocument.h"
+#include "nsIPermissionManager.h"
 #include "nsIPowerManagerService.h"
 #include "nsIPrincipal.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDOMError.h"
 
 DOMCI_DATA(MozPowerManager, mozilla::dom::power::PowerManager)
 
@@ -52,93 +53,61 @@ PowerManager::Shutdown()
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   // Remove ourself from the global notification list.
   pmService->RemoveWakeLockListener(this);
   return NS_OK;
 }
 
-bool
-PowerManager::CheckPermission()
-{
-  if (nsContentUtils::IsCallerChrome()) {
-    return true;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-  NS_ENSURE_TRUE(win, false);
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
-  NS_ENSURE_TRUE(doc, false);
-
-  nsCOMPtr<nsIURI> uri;
-  doc->NodePrincipal()->GetURI(getter_AddRefs(uri));
-
-  if (!nsContentUtils::URIIsChromeOrInPref(uri, "dom.power.whitelist")) {
-    return false;
-  }
-
-  return true;
-}
-
 NS_IMETHODIMP
 PowerManager::Reboot()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->Reboot();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::PowerOff()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->PowerOff();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   // already added? bail out.
   if (mListeners.Contains(aListener))
     return NS_OK;
 
   mListeners.AppendElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::RemoveWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   mListeners.RemoveElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetWakeLockState(const nsAString &aTopic, nsAString &aState)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   return pmService->GetWakeLockState(aTopic, aState);
 }
 
 NS_IMETHODIMP
@@ -158,74 +127,81 @@ PowerManager::Callback(const nsAString &
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenEnabled(bool *aEnabled)
 {
-  if (!CheckPermission()) {
-    *aEnabled = true;
-    return NS_OK;
-  }
-
   *aEnabled = hal::GetScreenEnabled();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenEnabled(bool aEnabled)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
-  // TODO bug 707589: When the screen's state changes, all visible windows
-  // should fire a visibility change event.
   hal::SetScreenEnabled(aEnabled);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenBrightness(double *aBrightness)
 {
-  if (!CheckPermission()) {
-    *aBrightness = 1;
-    return NS_OK;
-  }
-
   *aBrightness = hal::GetScreenBrightness();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenBrightness(double aBrightness)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   NS_ENSURE_TRUE(0 <= aBrightness && aBrightness <= 1, NS_ERROR_INVALID_ARG);
   hal::SetScreenBrightness(aBrightness);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetCpuSleepAllowed(bool *aAllowed)
 {
-  if (!CheckPermission()) {
-    *aAllowed = true;
-    return NS_OK;
-  }
-
   *aAllowed = hal::GetCpuSleepAllowed();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetCpuSleepAllowed(bool aAllowed)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   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);
+
+  PRUint32 permission = nsIPermissionManager::DENY_ACTION;
+  permMgr->TestPermissionFromPrincipal(principal, "power", &permission);
+
+  if (permission != nsIPermissionManager::ALLOW_ACTION) {
+    return nullptr;
+  }
+
+  nsRefPtr<PowerManager> powerManager = new PowerManager();
+  powerManager->Init(aWindow);
+
+  return powerManager.forget();
+}
+
 } // power
 } // dom
 } // mozilla
--- a/dom/power/PowerManager.h
+++ b/dom/power/PowerManager.h
@@ -7,16 +7,18 @@
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsIDOMPowerManager.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIDOMWindow.h"
 #include "nsWeakReference.h"
 
+class nsPIDOMWindow;
+
 namespace mozilla {
 namespace dom {
 namespace power {
 
 class PowerManager
   : public nsIDOMMozPowerManager
   , public nsIDOMMozWakeLockListener
 {
@@ -26,18 +28,20 @@ public:
   NS_DECL_NSIDOMMOZWAKELOCKLISTENER
 
   PowerManager() {};
   virtual ~PowerManager() {};
 
   nsresult Init(nsIDOMWindow *aWindow);
   nsresult Shutdown();
 
+  static already_AddRefed<PowerManager>
+  CheckPermissionAndCreateInstance(nsPIDOMWindow*);
+
 private:
-  bool CheckPermission();
 
   nsWeakPtr mWindow;
   nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
 };
 
 } // namespace power
 } // namespace dom
 } // namespace mozilla
--- a/dom/power/test/browser_bug697132.js
+++ b/dom/power/test/browser_bug697132.js
@@ -1,24 +1,27 @@
+/* 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/. */
+
 "use strict";
 
 waitForExplicitFinish();
 
-let kPrefNode = "dom.power.whitelist";
-let kPageSource1 = "data:text/html,1";
-let kPageSource2 = "data:text/html,2";
+let kUrlSource = "http://mochi.test:8888/";
+let kDataSource = "data:text/html,";
 
 let gOldPref;
 let gWin, gWin1, gWin2;
 let gTab, gTab1, gTab2;
 let gLock, gLock1, gLock2;
 let gCurStepIndex = -1;
 let gSteps = [
   function basicWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       gLock = nav.requestWakeLock("test");
@@ -46,17 +49,17 @@ let gSteps = [
       }
 
       gBrowser.removeTab(gTab);
 
       executeSoon(runNextStep);
     }, true);
   },
   function multiWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       let count = 0;
@@ -95,19 +98,19 @@ let gSteps = [
       gLock1.unlock();
       isnot(power.getWakeLockState("test"), "unlocked",
             "topic is locked");
 
       gLock2.unlock();
     }, true);
   },
   function crossTabWakeLock1() {
-    gTab1 = gBrowser.addTab(kPageSource1);
+    gTab1 = gBrowser.addTab(kUrlSource);
     gWin1 = gBrowser.getBrowserForTab(gTab1).contentWindow;
-    gTab2 = gBrowser.addTab(kPageSource1);
+    gTab2 = gBrowser.addTab(kUrlSource);
     gWin2 = gBrowser.getBrowserForTab(gTab2).contentWindow;
 
     gBrowser.selectedTab = gTab1;
     let browser = gBrowser.getBrowserForTab(gTab2);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       gLock2 = gWin2.navigator.requestWakeLock("test");
@@ -133,17 +136,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock3() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock4() {
@@ -161,17 +164,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock6() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock7() {
@@ -214,23 +217,17 @@ let gSteps = [
   },
 ];
 
 function runNextStep() {
   gCurStepIndex++;
   if (gCurStepIndex < gSteps.length) {
     gSteps[gCurStepIndex]();
   } else {
-    Services.prefs.setCharPref(kPrefNode, gOldPref);
+    SpecialPowers.removePermission("power", kUrlSource);
     finish();
   }
 }
 
 function test() {
-  try {
-    gOldPref = Services.prefs.getCharPref(kPrefNode);
-  } catch (e) {
-    gOldPref = "";
-  }
-  // data url inherits its parent's principal, which is |about:| here.
-  Services.prefs.setCharPref(kPrefNode, "about:");
+  SpecialPowers.addPermission("power", true, kUrlSource);
   runNextStep();
 }
--- a/dom/power/test/test_power_basics.html
+++ b/dom/power/test/test_power_basics.html
@@ -11,12 +11,24 @@
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Power API **/
 
 ok('mozPower' in navigator, "navigator.mozPower should exist");
 
+/** Test permission **/
+
+SpecialPowers.removePermission("power", document);
+
+power = navigator.mozPower;
+ok(!power, "Shouldn't be able to access power manager without permission.");
+
+SpecialPowers.addPermission("power", true, document);
+
+power = navigator.mozPower;
+ok(power, "Shouldn be able to access power manager with permission.");
+
 </script>
 </pre>
 </body>
 </html>