Bug 1201973 - 'Stop Sharing' should also revoke persistent permissions granted to frames, r=Gijs.
authorFlorian Quèze <florian@queze.net>
Fri, 11 Sep 2015 14:18:15 +0200
changeset 295157 2524d0d7a0418aef531343f637c92bee949b4b09
parent 295098 d9824a8871c8b73e0c79ad837deb766677e4baab
child 295158 b5297f88b43f537b79f63f3995461dc085e0b0d4
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1201973
milestone43.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 1201973 - 'Stop Sharing' should also revoke persistent permissions granted to frames, r=Gijs.
browser/base/content/test/general/browser_devices_get_user_media_in_frame.js
browser/modules/webrtcUI.jsm
--- a/browser/base/content/test/general/browser_devices_get_user_media_in_frame.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media_in_frame.js
@@ -264,26 +264,33 @@ let gTests = [
       info("requesting devices");
       global.requestDevice(true, true);
     });
     expectObserverCalled("getUserMedia:request");
     checkDeviceSelectors(true, true);
 
     let indicator = promiseIndicatorWindow();
     yield promiseMessage("ok", () => {
-      PopupNotifications.panel.firstChild.button.click();
+      activateSecondaryAction(kActionAlways);
     });
     expectObserverCalled("getUserMedia:response:allow");
     expectObserverCalled("recording-device-events");
     is(getMediaCaptureState(), "CameraAndMicrophone",
        "expected camera and microphone to be shared");
 
     yield indicator;
     yield checkSharingUI({video: true, audio: true});
 
+    let Perms = Services.perms;
+    let uri = Services.io.newURI("https://example.com/", null, null);
+    is(Perms.testExactPermission(uri, "microphone"), Perms.ALLOW_ACTION,
+                                 "microphone persistently allowed");
+    is(Perms.testExactPermission(uri, "camera"), Perms.ALLOW_ACTION,
+                                 "camera persistently allowed");
+
     yield promiseNotificationShown(PopupNotifications.getNotification("webRTC-sharingDevices"));
     activateSecondaryAction(kActionDeny);
 
     yield promiseObserverCalled("recording-device-events");
     expectObserverCalled("getUserMedia:revoke");
 
     yield promiseNoPopupNotification("webRTC-sharingDevices");
     expectObserverCalled("recording-window-ended");
@@ -291,16 +298,22 @@ let gTests = [
     if (gObservedTopics["recording-device-events"] == 1) {
       todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
       gObservedTopics["recording-device-events"] = 0;
     }
 
     expectNoObserverCalled();
     yield checkNotSharing();
 
+    // The persistent permissions for the frame should have been removed.
+    is(Perms.testExactPermission(uri, "microphone"), Perms.UNKNOWN_ACTION,
+                                 "microphone not persistently allowed");
+    is(Perms.testExactPermission(uri, "camera"), Perms.UNKNOWN_ACTION,
+                                 "camera not persistently allowed");
+
     // the stream is already closed, but this will do some cleanup anyway
     yield closeStream(global, true);
   }
 },
 
 {
   desc: "getUserMedia audio+video: reloading the frame removes all sharing UI",
   run: function checkReloading() {
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -388,17 +388,26 @@ function prompt(aBrowser, aRequest) {
         // and will grant audio access immediately.
         if ((!audioDevices.length || micPerm) && (!videoDevices.length || camPerm)) {
           // All permissions we were about to request are already persistently set.
           let allowedDevices = [];
           if (videoDevices.length && camPerm == perms.ALLOW_ACTION)
             allowedDevices.push(videoDevices[0].deviceIndex);
           if (audioDevices.length && micPerm == perms.ALLOW_ACTION)
             allowedDevices.push(audioDevices[0].deviceIndex);
-          let mm = this.browser.messageManager;
+
+          // Remember on which URIs we found persistent permissions so that we
+          // can remove them if the user clicks 'Stop Sharing'. There's no
+          // other way for the stop sharing code to know the hostnames of frames
+          // using devices until bug 1066082 is fixed.
+          let browser = this.browser;
+          browser._devicePermissionURIs = browser._devicePermissionURIs || [];
+          browser._devicePermissionURIs.push(uri);
+
+          let mm = browser.messageManager;
           mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
                                                windowID: aRequest.windowID,
                                                devices: allowedDevices});
           this.remove();
           return true;
         }
       }
 
@@ -529,16 +538,23 @@ function prompt(aBrowser, aRequest) {
           }
         }
 
         if (!allowedDevices.length) {
           denyRequest(notification.browser, aRequest);
           return;
         }
 
+        if (aRemember) {
+          // Remember on which URIs we set persistent permissions so that we
+          // can remove them if the user clicks 'Stop Sharing'.
+          aBrowser._devicePermissionURIs = aBrowser._devicePermissionURIs || [];
+          aBrowser._devicePermissionURIs.push(uri);
+        }
+
         let mm = notification.browser.messageManager;
         mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
                                              windowID: aRequest.windowID,
                                              devices: allowedDevices});
       };
       return false;
     }
   };
@@ -857,25 +873,27 @@ function updateBrowserSpecificIndicator(
     accessKey: stringBundle.getString("getUserMedia.continueSharing.accesskey"),
     callback: function () {},
     dismiss: true
   };
   let secondaryActions = [{
     label: stringBundle.getString("getUserMedia.stopSharing.label"),
     accessKey: stringBundle.getString("getUserMedia.stopSharing.accesskey"),
     callback: function () {
-      let uri = Services.io.newURI(aState.documentURI, null, null);
+      let uris = aBrowser._devicePermissionURIs || [];
+      uris = uris.concat(Services.io.newURI(aState.documentURI, null, null));
       let perms = Services.perms;
-      if (aState.camera &&
-          perms.testExactPermission(uri, "camera") == perms.ALLOW_ACTION)
-        perms.remove(uri, "camera");
-      if (aState.microphone &&
-          perms.testExactPermission(uri, "microphone") == perms.ALLOW_ACTION)
-        perms.remove(uri, "microphone");
-
+      for (let uri of uris) {
+        if (aState.camera &&
+            perms.testExactPermission(uri, "camera") == perms.ALLOW_ACTION)
+          perms.remove(uri, "camera");
+        if (aState.microphone &&
+            perms.testExactPermission(uri, "microphone") == perms.ALLOW_ACTION)
+          perms.remove(uri, "microphone");
+      }
       let mm = notification.browser.messageManager;
       mm.sendAsyncMessage("webrtc:StopSharing", windowId);
     }
   }];
   let options = {
     hideNotNow: true,
     dismissed: true,
     eventCallback: function(aTopic, aNewBrowser) {
@@ -897,22 +915,23 @@ function updateBrowserSpecificIndicator(
     let anchorId = captureState == "Microphone" ? "webRTC-sharingMicrophone-notification-icon"
                                                 : "webRTC-sharingDevices-notification-icon";
     let message = stringBundle.getString("getUserMedia.sharing" + captureState + ".message2");
     notification =
       chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message,
                                         anchorId, mainAction, secondaryActions, options);
   }
   else {
-    removeBrowserNotification(aBrowser,"webRTC-sharingDevices");
+    removeBrowserNotification(aBrowser, "webRTC-sharingDevices");
+    aBrowser._devicePermissionURIs = null;
   }
 
   // Now handle the screen sharing indicator.
   if (!aState.screen) {
-    removeBrowserNotification(aBrowser,"webRTC-sharingScreen");
+    removeBrowserNotification(aBrowser, "webRTC-sharingScreen");
     return;
   }
 
   let screenSharingNotif; // Used by action callbacks.
   let isBrowserSharing = aState.screen == "Browser";
   options = {
     hideNotNow: !isBrowserSharing,
     dismissed: true,