Bug 1429432 - Require Secure Context for Notifications. r=Ehsan
☠☠ backed out by b3e646df6c5e ☠ ☠
authorJohann Hofmann <jhofmann@mozilla.com>
Tue, 26 Feb 2019 22:37:22 +0000
changeset 519155 279a75b5a6d42a41176750f113594139060d8924
parent 519154 6cf5eb6b1a8c28d56b42aba2e8632643e6dc94dc
child 519156 17d59b664c0fca195a1169c7a62f995480617d0a
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1429432
milestone67.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 1429432 - Require Secure Context for Notifications. r=Ehsan Differential Revision: https://phabricator.services.mozilla.com/D21001
dom/locales/en-US/chrome/dom/dom.properties
dom/notification/Notification.cpp
dom/notification/test/browser/browser_permission_dismiss.js
dom/notification/test/mochitest/mochitest.ini
dom/notification/test/mochitest/test_notification_insecure_context.html
modules/libpref/init/StaticPrefList.h
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -311,16 +311,17 @@ GenericFileName=file
 LargeAllocationSuccess=This page was loaded in a new process due to a Large-Allocation header.
 # LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name. Do not translate GET.
 LargeAllocationNonGetRequest=A Large-Allocation header was ignored due to the load being triggered by a non-GET request.
 # LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name. Do not translate `window.opener`.
 LargeAllocationNotOnlyToplevelInTabGroup=A Large-Allocation header was ignored due to the presence of windows which have a reference to this browsing context through the frame hierarchy or window.opener.
 # LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name
 LargeAllocationNonE10S=A Large-Allocation header was ignored due to the document not being loaded out of process.
 GeolocationInsecureRequestIsForbidden=A Geolocation request can only be fulfilled in a secure context.
+NotificationsInsecureRequestIsForbidden=The Notification permission may only be requested in a secure context.
 # LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name.
 LargeAllocationNonWin32=This page would be loaded in a new process due to a Large-Allocation header, however Large-Allocation process creation is disabled on non-Win32 platforms.
 # LOCALIZATION NOTE: Do not translate "content", "Window", and "window.top"
 WindowContentUntrustedWarning=The ‘content’ attribute of Window objects is deprecated.  Please use ‘window.top’ instead.
 # LOCALIZATION NOTE: The first %S is the tag name of the element that starts the loop, the second %S is the element's ID.
 SVGRefLoopWarning=The SVG <%S> with ID “%S” has a reference loop.
 # LOCALIZATION NOTE: The first %S is the tag name of the element in the chain where the chain was broken, the second %S is the element's ID.
 SVGRefChainLengthExceededWarning=An SVG <%S> reference chain which is too long was abandoned at the element with ID “%S”.
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -41,16 +41,17 @@
 #include "nsIAlertsService.h"
 #include "nsIContentPermissionPrompt.h"
 #include "mozilla/dom/Document.h"
 #include "nsILoadContext.h"
 #include "nsINotificationStorage.h"
 #include "nsIPermissionManager.h"
 #include "nsIPermission.h"
 #include "nsIPushService.h"
+#include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIServiceWorkerManager.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIXPConnect.h"
 #include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 #include "nsServiceManagerUtils.h"
@@ -473,23 +474,35 @@ NS_IMETHODIMP
 NotificationPermissionRequest::Run() {
   if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
     mPermission = NotificationPermission::Granted;
   } else {
     // File are automatically granted permission.
     nsCOMPtr<nsIURI> uri;
     mPrincipal->GetURI(getter_AddRefs(uri));
 
+    bool isFile = false;
     if (uri) {
-      bool isFile;
       uri->SchemeIs("file", &isFile);
       if (isFile) {
         mPermission = NotificationPermission::Granted;
       }
     }
+
+    if (!isFile && !StaticPrefs::dom_webnotifications_allowinsecure() &&
+        !mWindow->IsSecureContext()) {
+      mPermission = NotificationPermission::Denied;
+      nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
+      if (doc) {
+        nsContentUtils::ReportToConsole(
+            nsIScriptError::errorFlag, NS_LITERAL_CSTRING("DOM"), doc,
+            nsContentUtils::eDOM_PROPERTIES,
+            "NotificationsInsecureRequestIsForbidden");
+      }
+    }
   }
 
   // We can't call ShowPrompt() directly here since our logic for determining
   // whether to display a prompt depends on the checks above as well as the
   // result of CheckPromptPrefs().  So we have to manually check the prompt
   // prefs and decide what to do based on that.
   PromptResult pr = CheckPromptPrefs();
   switch (pr) {
--- a/dom/notification/test/browser/browser_permission_dismiss.js
+++ b/dom/notification/test/browser/browser_permission_dismiss.js
@@ -1,16 +1,16 @@
 "use strict";
 
-const ORIGIN_URI = Services.io.newURI("http://mochi.test:8888");
+const ORIGIN_URI = Services.io.newURI("https://example.com");
 const PERMISSION_NAME = "desktop-notification";
 const PROMPT_ALLOW_BUTTON = -1;
 const PROMPT_NOT_NOW_BUTTON = 0;
 const PROMPT_NEVER_BUTTON = 1;
-const TEST_URL = "http://mochi.test:8888/browser/dom/notification/test/browser/notification.html";
+const TEST_URL = "https://example.com/browser/dom/notification/test/browser/notification.html";
 
 /**
  * Clicks the specified web-notifications prompt button.
  *
  * @param {Number} aButtonIndex Number indicating which button to click.
  *                              See the constants in this file.
  * @note modified from toolkit/components/passwordmgr/test/browser/head.js
  */
--- a/dom/notification/test/mochitest/mochitest.ini
+++ b/dom/notification/test/mochitest/mochitest.ini
@@ -1,12 +1,14 @@
 [DEFAULT]
 
 support-files =
   create_notification.html
   MockServices.js
   NotificationTest.js
 
 [test_notification_basics.html]
+# This test needs to be run on HTTP (not HTTPS).
+[test_notification_insecure_context.html]
 [test_notification_storage.html]
 [test_bug931307.html]
 skip-if = (os == 'android') # Bug 1258975 on android.
-[test_notification_tag.html]
\ No newline at end of file
+[test_notification_tag.html]
new file mode 100644
--- /dev/null
+++ b/dom/notification/test/mochitest/test_notification_insecure_context.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Tests that Notification permissions are denied in insecure context.
+https://bugzilla.mozilla.org/show_bug.cgi?id=1429432
+-->
+<head>
+  <title>Notification permission in insecure context</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="display: none">
+  </div>
+  <pre id="test">
+  <script class="testbody" type="text/javascript">
+  SimpleTest.waitForExplicitFinish();
+
+  // Add an allow permission for the mochitest origin to test this.
+  let script = SpecialPowers.loadChromeScript(function () {
+    let {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+    let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("http://mochi.test:8888");
+    Services.perms.addFromPrincipal(principal, "desktop-notification", Services.perms.ALLOW_ACTION);
+    addMessageListener("destroy", function() {
+      Services.perms.removeFromPrincipal(principal, "desktop-notification");
+    });
+  });
+
+  (async function runTest() {
+    let response = await Notification.requestPermission();
+    is(response, "denied", "Denied permission in insecure context");
+
+    await SpecialPowers.pushPrefEnv({"set": [["dom.webnotifications.allowinsecure", true]]});
+
+    response = await Notification.requestPermission();
+    is(response, "granted", "Granted permission in insecure context with pref set");
+
+    script.sendSyncMessage("destroy");
+    script.destroy();
+
+    SimpleTest.finish();
+  })();
+  </script>
+  </pre>
+</body>
+</html>
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -314,16 +314,22 @@ VARCACHE_PREF(
 
 VARCACHE_PREF(
   "dom.webnotifications.enabled",
    dom_webnotifications_enabled,
   RelaxedAtomicBool, true
 )
 
 VARCACHE_PREF(
+  "dom.webnotifications.allowinsecure",
+   dom_webnotifications_allowinsecure,
+  RelaxedAtomicBool, false
+)
+
+VARCACHE_PREF(
   "dom.webnotifications.serviceworker.enabled",
    dom_webnotifications_serviceworker_enabled,
   RelaxedAtomicBool, true
 )
 
 #ifdef NIGHTLY_BUILD
 # define PREF_VALUE  true
 #else