Bug 1335740 - getUserMedia() NotAllowedError in http (pref'd on), & [SecureContext] navigator.mediaDevices (pref'd off) r=bzbarsky,pehrsons
☠☠ backed out by 6b3a949f27ef ☠ ☠
authorJan-Ivar Bruaroey <jib@mozilla.com>
Wed, 27 Feb 2019 03:51:07 +0000
changeset 519286 e31483efc331715704bd18a686333d6a1d185b0c
parent 519285 1a6bfb6eba8a3c91cee898badfff9a73a72ad8ab
child 519287 1bddabb7bafb168ba9c64b755ee4f2844f0ac9cc
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)
reviewersbzbarsky, pehrsons
bugs1335740
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 1335740 - getUserMedia() NotAllowedError in http (pref'd on), & [SecureContext] navigator.mediaDevices (pref'd off) r=bzbarsky,pehrsons Differential Revision: https://phabricator.services.mozilla.com/D19549
dom/base/Navigator.cpp
dom/media/MediaManager.cpp
modules/libpref/init/StaticPrefList.h
modules/libpref/init/all.js
testing/web-platform/meta/mediacapture-streams/MediaDevices-SecureContext.html.ini
testing/web-platform/meta/mediacapture-streams/__dir__.ini
testing/web-platform/meta/mediacapture-streams/historical.html.ini
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1527,21 +1527,23 @@ void Navigator::OnNavigation() {
 }
 
 JSObject* Navigator::WrapObject(JSContext* cx,
                                 JS::Handle<JSObject*> aGivenProto) {
   return Navigator_Binding::Wrap(cx, this, aGivenProto);
 }
 
 /* static */
-bool Navigator::HasUserMediaSupport(JSContext* /* unused */,
-                                    JSObject* /* unused */) {
-  // Make enabling peerconnection enable getUserMedia() as well
-  return Preferences::GetBool("media.navigator.enabled", false) ||
-         Preferences::GetBool("media.peerconnection.enabled", false);
+bool Navigator::HasUserMediaSupport(JSContext* cx, JSObject* obj) {
+  // Make enabling peerconnection enable getUserMedia() as well.
+  // Emulate [SecureContext] unless media.devices.insecure.enabled=true
+  return (StaticPrefs::media_navigator_enabled() ||
+          StaticPrefs::media_peerconnection_enabled()) &&
+         (IsSecureContextOrObjectIsFromSecureContext(cx, obj) ||
+          StaticPrefs::media_devices_insecure_enabled());
 }
 
 /* static */
 already_AddRefed<nsPIDOMWindowInner> Navigator::GetWindowFromGlobal(
     JSObject* aGlobal) {
   nsCOMPtr<nsPIDOMWindowInner> win = xpc::WindowOrNull(aGlobal);
   return win.forget();
 }
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2370,16 +2370,19 @@ RefPtr<MediaManager::StreamPromise> Medi
   if (!docURI) {
     return StreamPromise::CreateAndReject(
         MakeRefPtr<MediaMgrError>(MediaMgrError::Name::AbortError), __func__);
   }
   bool isChrome = (aCallerType == dom::CallerType::System);
   bool privileged =
       isChrome ||
       Preferences::GetBool("media.navigator.permission.disabled", false);
+  bool isSecure = aWindow->IsSecureContext();
+  // Note: isHTTPS is for legacy telemetry only! Use isSecure for security, as
+  // it handles things like https iframes in http pages correctly.
   bool isHTTPS = false;
   bool isHandlingUserInput = EventStateManager::IsHandlingUserInput();
   docURI->SchemeIs("https", &isHTTPS);
   nsCString host;
   nsresult rv = docURI->GetHost(host);
   // Test for some other schemes that ServiceWorker recognizes
   bool isFile;
   docURI->SchemeIs("file", &isFile);
@@ -2424,18 +2427,20 @@ RefPtr<MediaManager::StreamPromise> Medi
 
   dom::Document* doc = aWindow->GetExtantDoc();
   if (NS_WARN_IF(!doc)) {
     return StreamPromise::CreateAndReject(
         MakeRefPtr<MediaMgrError>(MediaMgrError::Name::SecurityError),
         __func__);
   }
 
-  // Disallow access to null principal pages.
-  if (principal->GetIsNullPrincipal()) {
+  // Disallow access to null principal pages and http pages (unless pref)
+  if (principal->GetIsNullPrincipal() ||
+      !(isSecure ||
+        Preferences::GetBool("media.getusermedia.insecure.enabled", false))) {
     return StreamPromise::CreateAndReject(
         MakeRefPtr<MediaMgrError>(MediaMgrError::Name::NotAllowedError),
         __func__);
   }
 
   // This principal needs to be sent to different threads and so via IPC.
   // For this reason it's better to convert it to PrincipalInfo right now.
   ipc::PrincipalInfo principalInfo;
@@ -2786,18 +2791,19 @@ RefPtr<MediaManager::StreamPromise> Medi
             LOG("GetUserMedia: post enumeration EnumerateDevicesImpl "
                 "failure callback called!");
             return BadConstraintsPromise::CreateAndReject(std::move(aError),
                                                           __func__);
           })
       ->Then(
           GetCurrentThreadSerialEventTarget(), __func__,
           [self, windowID, c, windowListener, sourceListener, askPermission,
-           prefs, isHTTPS, isHandlingUserInput, callID, principalInfo, isChrome,
-           devices, resistFingerprinting](const char* badConstraint) mutable {
+           prefs, isSecure, isHandlingUserInput, callID, principalInfo,
+           isChrome, devices,
+           resistFingerprinting](const char* badConstraint) mutable {
             LOG("GetUserMedia: starting post enumeration promise2 success "
                 "callback!");
 
             // Ensure that the window is still good.
             auto* globalWindow =
                 nsGlobalWindowInner::GetInnerWindowWithId(windowID);
             RefPtr<nsPIDOMWindowInner> window =
                 globalWindow ? globalWindow->AsInner() : nullptr;
@@ -2877,17 +2883,17 @@ RefPtr<MediaManager::StreamPromise> Medi
             array->AppendElement(callID);
 
             nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
             if (!askPermission) {
               obs->NotifyObservers(devicesCopy, "getUserMedia:privileged:allow",
                                    callID.BeginReading());
             } else {
               auto req = MakeRefPtr<GetUserMediaRequest>(
-                  window, callID, c, isHTTPS, isHandlingUserInput);
+                  window, callID, c, isSecure, isHandlingUserInput);
               if (!Preferences::GetBool("media.navigator.permission.force") &&
                   array->Length() > 1) {
                 // there is at least 1 pending gUM request
                 // For the scarySources test case, always send the
                 // request
                 self->mPendingGUMRequest.AppendElement(req.forget());
               } else {
                 obs->NotifyObservers(req, "getUserMedia:request", nullptr);
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1228,17 +1228,57 @@ VARCACHE_PREF(
 VARCACHE_PREF(
   "media.android-media-codec.preferred",
    MediaAndroidMediaCodecPreferred,
   RelaxedAtomicBool, true
 )
 
 #endif // ANDROID
 
-// WebRTC
+//---------------------------------------------------------------------------
+// MediaCapture prefs
+//---------------------------------------------------------------------------
+
+// Enables navigator.mediaDevices and getUserMedia() support. See also
+// media.peerconnection.enabled
+VARCACHE_PREF(
+              "media.navigator.enabled",
+              media_navigator_enabled,
+              bool, true
+              )
+
+// This pref turns off [SecureContext] on the navigator.mediaDevices object, for
+// more compatible legacy behavior.
+VARCACHE_PREF(
+              "media.devices.insecure.enabled",
+              media_devices_insecure_enabled,
+              bool, true
+              )
+
+// If the above pref is also enabled, this pref enabled getUserMedia() support
+// in http, bypassing the instant NotAllowedError you get otherwise.
+VARCACHE_PREF(
+              "media.getusermedia.insecure.enabled",
+              media_getusermedia_insecure_enabled,
+              bool, false
+              )
+
+//---------------------------------------------------------------------------
+// WebRTC prefs
+//---------------------------------------------------------------------------
+
+// Enables RTCPeerConnection support. Note that, when true, this pref enables
+// navigator.mediaDevices and getUserMedia() support as well.
+// See also media.navigator.enabled
+VARCACHE_PREF(
+              "media.peerconnection.enabled",
+              media_peerconnection_enabled,
+              bool, true
+              )
+
 #ifdef MOZ_WEBRTC
 #ifdef ANDROID
 
 VARCACHE_PREF(
   "media.navigator.hardware.vp8_encode.acceleration_remote_enabled",
    MediaNavigatorHardwareVp8encodeAccelerationRemoteEnabled,
   bool, true
 )
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -423,17 +423,16 @@ pref("media.decoder-doctor.notifications
 pref("media.decoder-doctor.decode-errors-allowed", "");
 pref("media.decoder-doctor.decode-warnings-allowed", "");
 // Whether we report partial failures.
 pref("media.decoder-doctor.verbose", false);
 // URL to report decode issues
 pref("media.decoder-doctor.new-issue-endpoint", "https://webcompat.com/issues/new");
 
 #ifdef MOZ_WEBRTC
-pref("media.navigator.enabled", true);
 pref("media.navigator.video.enabled", true);
 pref("media.navigator.video.default_fps",30);
 pref("media.navigator.video.use_remb", true);
 pref("media.navigator.video.use_tmmbr", false);
 pref("media.navigator.audio.use_fec", true);
 pref("media.navigator.video.red_ulpfec_enabled", false);
 
 pref("media.peerconnection.dtmf.enabled", true);
@@ -448,17 +447,16 @@ pref("media.peerconnection.sdp.rust.comp
 
 pref("media.webrtc.debug.trace_mask", 0);
 pref("media.webrtc.debug.multi_log", false);
 pref("media.webrtc.debug.log_file", "");
 pref("media.webrtc.debug.aec_dump_max_size", 4194304); // 4MB
 
 pref("media.navigator.video.default_width",0);  // adaptive default
 pref("media.navigator.video.default_height",0); // adaptive default
-pref("media.peerconnection.enabled", true);
 pref("media.peerconnection.video.enabled", true);
 pref("media.navigator.video.max_fs", 12288); // Enough for 2048x1536
 pref("media.navigator.video.max_fr", 60);
 pref("media.navigator.video.h264.level", 31); // 0x42E01f - level 3.1
 pref("media.navigator.video.h264.max_br", 0);
 pref("media.navigator.video.h264.max_mbps", 0);
 #if defined(NIGHTLY_BUILD) && !defined(ANDROID)
 pref("media.navigator.mediadatadecoder_vpx_enabled", true);
deleted file mode 100644
--- a/testing/web-platform/meta/mediacapture-streams/MediaDevices-SecureContext.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[MediaDevices-SecureContext.html]
-  [MediaDevices and SecureContext]
-    expected: FAIL
-
--- a/testing/web-platform/meta/mediacapture-streams/__dir__.ini
+++ b/testing/web-platform/meta/mediacapture-streams/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [media.navigator.permission.disabled:true, media.navigator.streams.fake:true, dom.security.featurePolicy.enabled:true, dom.security.featurePolicy.header.enabled:true, dom.security.featurePolicy.webidl.enabled:true]
+prefs: [media.navigator.permission.disabled:true, media.navigator.streams.fake:true, media.devices.insecure.enabled:false, dom.security.featurePolicy.enabled:true, dom.security.featurePolicy.header.enabled:true, dom.security.featurePolicy.webidl.enabled:true]
deleted file mode 100644
--- a/testing/web-platform/meta/mediacapture-streams/historical.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[historical.html]
-  [navigator.mozGetUserMedia should not exist]
-    expected: FAIL
-