Bug 1335740 - getUserMedia() Add 2 prefs to control A) NotAllowedError in http (pref'd on), and B) [SecureContext] navigator.mediaDevices (pref'd off) r=bzbarsky,pehrsons
authorJan-Ivar Bruaroey <jib@mozilla.com>
Tue, 30 Apr 2019 15:20:59 +0000
changeset 530782 cec93c8315e9f80cdc187dc967e9758634a59c4c
parent 530781 d8571fb523a061813ecd4e92526f60024dbb87d3
child 530783 1e2987994551c0ff48be5aad4a095dc8f0c52366
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky, pehrsons
bugs1335740
milestone68.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() Add 2 prefs to control A) NotAllowedError in http (pref'd on), and B) [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
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1506,21 +1506,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
@@ -2351,16 +2351,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);
@@ -2405,18 +2408,19 @@ 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 || StaticPrefs::media_getusermedia_insecure_enabled())) {
     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;
@@ -2765,18 +2769,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.
             RefPtr<nsPIDOMWindowInner> window =
                 nsGlobalWindowInner::GetInnerWindowWithId(windowID);
             if (!window || !self->IsWindowListenerStillActive(windowListener)) {
               LOG("GetUserMedia: bad window (%" PRIu64
@@ -2854,17 +2859,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
@@ -1480,17 +1480,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
@@ -438,17 +438,16 @@ pref("media.videocontrols.picture-in-pic
 #else
 pref("media.videocontrols.picture-in-picture.enabled", false);
 pref("media.videocontrols.picture-in-picture.video-toggle.enabled", false);
 #endif
 pref("media.videocontrols.picture-in-picture.video-toggle.flyout-enabled", false);
 pref("media.videocontrols.picture-in-picture.video-toggle.flyout-wait-ms", 5000);
 
 #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);
@@ -463,17 +462,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]