Bug 1672432 - Don't remove persistent device permissions when clicking 'Stop Sharing' in the WebRTC global indicator. r=pbz
authorMike Conley <mconley@mozilla.com>
Tue, 27 Oct 2020 16:28:25 +0000
changeset 554736 efba64ab92d5184a0a8bafeb3a7b1310071a0487
parent 554735 4f179bf502cedd18bf16a625477d5902e4304c89
child 554737 6de570466e661b7ce1b61c81587b5c5ae9506765
push id37898
push userabutkovits@mozilla.com
push dateWed, 28 Oct 2020 09:24:21 +0000
treeherdermozilla-central@83bf4fd3b1fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbz
bugs1672432
milestone84.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 1672432 - Don't remove persistent device permissions when clicking 'Stop Sharing' in the WebRTC global indicator. r=pbz Differential Revision: https://phabricator.services.mozilla.com/D94501
browser/base/content/test/webrtc/browser.ini
browser/base/content/test/webrtc/browser_stop_sharing_button.js
browser/base/content/test/webrtc/browser_stop_streams_on_indicator_close.js
browser/base/content/test/webrtc/browser_tab_switch_warning.js
browser/base/content/test/webrtc/head.js
browser/base/content/webrtcIndicator.js
browser/modules/webrtcUI.jsm
--- a/browser/base/content/test/webrtc/browser.ini
+++ b/browser/base/content/test/webrtc/browser.ini
@@ -3,17 +3,17 @@ support-files =
   get_user_media.html
   get_user_media_in_frame.html
   get_user_media_in_xorigin_frame.html
   get_user_media_in_xorigin_frame_ancestor.html
   head.js
 prefs =
   privacy.webrtc.allowSilencingNotifications=true
   privacy.webrtc.legacyGlobalIndicator=false
-  privacy.webrtc.sharedTabWarning=true
+  privacy.webrtc.sharedTabWarning=false
 
 [browser_device_controls_menus.js]
 [browser_devices_get_user_media.js]
 skip-if = (os == "linux" && debug) # linux: bug 976544
 [browser_devices_get_user_media_anim.js]
 [browser_devices_get_user_media_default_permissions.js]
 [browser_devices_get_user_media_in_frame.js]
 skip-if = debug # bug 1369731
--- a/browser/base/content/test/webrtc/browser_stop_sharing_button.js
+++ b/browser/base/content/test/webrtc/browser_stop_sharing_button.js
@@ -21,25 +21,16 @@ add_task(async function setup() {
 });
 
 /**
  * Tests that if the user chooses to "Stop Sharing" a display while
  * also sharing their microphone or camera, that only the display
  * stream is stopped.
  */
 add_task(async function test_stop_sharing() {
-  let prefs = [
-    [PREF_PERMISSION_FAKE, true],
-    [PREF_AUDIO_LOOPBACK, ""],
-    [PREF_VIDEO_LOOPBACK, ""],
-    [PREF_FAKE_STREAMS, true],
-    [PREF_FOCUS_SOURCE, false],
-  ];
-  await SpecialPowers.pushPrefEnv({ set: prefs });
-
   await BrowserTestUtils.withNewTab(TEST_PAGE, async browser => {
     let indicatorPromise = promiseIndicatorWindow();
 
     await shareDevices(
       browser,
       true /* camera */,
       true /* microphone */,
       SHARE_SCREEN
@@ -110,8 +101,72 @@ add_task(async function test_stop_sharin
     BrowserTestUtils.is_hidden(
       indicator.document.getElementById("display-share")
     ),
     "The display-share section of the indicator should now be hidden."
   );
 
   BrowserTestUtils.removeTab(tab1);
 });
+
+/**
+ * Tests that if the user chooses to "Stop Sharing" a display, persistent
+ * permissions are not removed for camera or microphone devices.
+ */
+add_task(async function test_keep_permissions() {
+  await BrowserTestUtils.withNewTab(TEST_PAGE, async browser => {
+    let indicatorPromise = promiseIndicatorWindow();
+
+    await shareDevices(
+      browser,
+      true /* camera */,
+      true /* microphone */,
+      SHARE_SCREEN,
+      true /* remember */
+    );
+
+    let indicator = await indicatorPromise;
+
+    let stopSharingButton = indicator.document.getElementById("stop-sharing");
+    let stopSharingPromise = expectObserverCalled("recording-device-events");
+    stopSharingButton.click();
+    await stopSharingPromise;
+
+    // Ensure that we're still sharing the other streams.
+    await checkSharingUI({ audio: true, video: true });
+
+    // Ensure that the "display-share" section of the indicator is now hidden
+    Assert.ok(
+      BrowserTestUtils.is_hidden(
+        indicator.document.getElementById("display-share")
+      ),
+      "The display-share section of the indicator should now be hidden."
+    );
+
+    let { state: micState, scope: micScope } = SitePermissions.getForPrincipal(
+      browser.contentPrincipal,
+      "microphone",
+      browser
+    );
+
+    Assert.equal(micState, SitePermissions.ALLOW);
+    Assert.equal(micScope, SitePermissions.SCOPE_PERSISTENT);
+
+    let { state: camState, scope: camScope } = SitePermissions.getForPrincipal(
+      browser.contentPrincipal,
+      "camera",
+      browser
+    );
+    Assert.equal(camState, SitePermissions.ALLOW);
+    Assert.equal(camScope, SitePermissions.SCOPE_PERSISTENT);
+
+    SitePermissions.removeFromPrincipal(
+      browser.contentPrincipal,
+      "camera",
+      browser
+    );
+    SitePermissions.removeFromPrincipal(
+      browser.contentPrincipal,
+      "microphone",
+      browser
+    );
+  });
+});
--- a/browser/base/content/test/webrtc/browser_stop_streams_on_indicator_close.js
+++ b/browser/base/content/test/webrtc/browser_stop_streams_on_indicator_close.js
@@ -4,47 +4,57 @@
 "use strict";
 
 const TEST_ROOT = getRootDirectory(gTestPath).replace(
   "chrome://mochitests/content/",
   "https://example.com/"
 );
 const TEST_PAGE = TEST_ROOT + "get_user_media.html";
 
-/**
- * Tests that if the indicator is closed somehow by the user when streams
- * still ongoing, that all of those streams are stopped, and the most recent
- * tab that a stream was shared with is selected.
- */
-add_task(async function test_close_indicator() {
+add_task(async function setup() {
   let prefs = [
     [PREF_PERMISSION_FAKE, true],
     [PREF_AUDIO_LOOPBACK, ""],
     [PREF_VIDEO_LOOPBACK, ""],
     [PREF_FAKE_STREAMS, true],
     [PREF_FOCUS_SOURCE, false],
   ];
   await SpecialPowers.pushPrefEnv({ set: prefs });
+});
+
+/**
+ * Tests that if the indicator is closed somehow by the user when streams
+ * still ongoing, that all of those streams it represents are stopped, and
+ * the most recent tab that a stream was shared with is selected.
+ *
+ * This test makes sure the global mute toggles for camera and microphone
+ * are disabled, so the indicator only represents display streams, and only
+ * those streams should be stopped on close.
+ */
+add_task(async function test_close_indicator_no_global_toggles() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["privacy.webrtc.globalMuteToggles", false]],
+  });
 
   let indicatorPromise = promiseIndicatorWindow();
 
   info("Opening first tab");
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
   info("Sharing camera, microphone and screen");
-  await shareDevices(tab1.linkedBrowser, true, true, SHARE_SCREEN);
+  await shareDevices(tab1.linkedBrowser, true, true, SHARE_SCREEN, false);
 
   info("Opening second tab");
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
-  info("Sharing camera and screen");
-  await shareDevices(tab2.linkedBrowser, true, false, SHARE_SCREEN);
+  info("Sharing camera, microphone and screen");
+  await shareDevices(tab2.linkedBrowser, true, true, SHARE_SCREEN, true);
 
   info("Opening third tab");
   let tab3 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
   info("Sharing screen");
-  await shareDevices(tab3.linkedBrowser, false, false, SHARE_SCREEN);
+  await shareDevices(tab3.linkedBrowser, false, false, SHARE_SCREEN, false);
 
   info("Opening fourth tab");
   let tab4 = await BrowserTestUtils.openNewForegroundTab(
     gBrowser,
     "https://example.com"
   );
 
   Assert.equal(
@@ -52,26 +62,154 @@ add_task(async function test_close_indic
     tab4,
     "Most recently opened tab is selected"
   );
 
   let indicator = await indicatorPromise;
 
   indicator.close();
 
-  await checkNotSharing();
+  // Wait a tick of the event loop to give the unload handler in the indicator
+  // a chance to run.
+  await new Promise(resolve => executeSoon(resolve));
 
+  // Make sure the media capture state has a chance to flush up to the parent.
+  await getMediaCaptureState();
+
+  // The camera and microphone streams should still be active.
+  let camStreams = webrtcUI.getActiveStreams(true, false);
+  Assert.equal(camStreams.length, 2, "Should have found two camera streams");
+  let micStreams = webrtcUI.getActiveStreams(false, true);
   Assert.equal(
-    webrtcUI.activePerms.size,
-    0,
-    "There shouldn't be any active stream permissions."
+    micStreams.length,
+    2,
+    "Should have found two microphone streams"
   );
 
+  // The camera and microphone permission were remembered for tab2, so check to
+  // make sure that the permissions remain.
+  let { state: camState, scope: camScope } = SitePermissions.getForPrincipal(
+    tab2.linkedBrowser.contentPrincipal,
+    "camera",
+    tab2.linkedBrowser
+  );
+  Assert.equal(camState, SitePermissions.ALLOW);
+  Assert.equal(camScope, SitePermissions.SCOPE_PERSISTENT);
+
+  let { state: micState, scope: micScope } = SitePermissions.getForPrincipal(
+    tab2.linkedBrowser.contentPrincipal,
+    "microphone",
+    tab2.linkedBrowser
+  );
+  Assert.equal(micState, SitePermissions.ALLOW);
+  Assert.equal(micScope, SitePermissions.SCOPE_PERSISTENT);
+
   Assert.equal(
     gBrowser.selectedTab,
     tab3,
     "Most recently tab that streams were shared with is selected"
   );
+
+  SitePermissions.removeFromPrincipal(
+    tab2.linkedBrowser.contentPrincipal,
+    "camera",
+    tab2.linkedBrowser
+  );
+
+  SitePermissions.removeFromPrincipal(
+    tab2.linkedBrowser.contentPrincipal,
+    "microphone",
+    tab2.linkedBrowser
+  );
+
   BrowserTestUtils.removeTab(tab1);
   BrowserTestUtils.removeTab(tab2);
   BrowserTestUtils.removeTab(tab3);
   BrowserTestUtils.removeTab(tab4);
 });
+
+/**
+ * Tests that if the indicator is closed somehow by the user when streams
+ * still ongoing, that all of those streams is represents are stopped, and
+ * the most recent tab that a stream was shared with is selected.
+ *
+ * This test makes sure the global mute toggles are enabled. This means that
+ * when the user manages to close the indicator, we should revoke camera
+ * and microphone permissions too.
+ */
+add_task(async function test_close_indicator_with_global_toggles() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["privacy.webrtc.globalMuteToggles", true]],
+  });
+
+  let indicatorPromise = promiseIndicatorWindow();
+
+  info("Opening first tab");
+  let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
+  info("Sharing camera, microphone and screen");
+  await shareDevices(tab1.linkedBrowser, true, true, SHARE_SCREEN, false);
+
+  info("Opening second tab");
+  let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
+  info("Sharing camera, microphone and screen");
+  await shareDevices(tab2.linkedBrowser, true, true, SHARE_SCREEN, true);
+
+  info("Opening third tab");
+  let tab3 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
+  info("Sharing screen");
+  await shareDevices(tab3.linkedBrowser, false, false, SHARE_SCREEN, false);
+
+  info("Opening fourth tab");
+  let tab4 = await BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    "https://example.com"
+  );
+
+  Assert.equal(
+    gBrowser.selectedTab,
+    tab4,
+    "Most recently opened tab is selected"
+  );
+
+  let indicator = await indicatorPromise;
+
+  indicator.close();
+
+  // Wait a tick of the event loop to give the unload handler in the indicator
+  // a chance to run.
+  await new Promise(resolve => executeSoon(resolve));
+
+  Assert.deepEqual(
+    await getMediaCaptureState(),
+    {},
+    "expected nothing to be shared"
+  );
+
+  // Ensuring we no longer have any active streams.
+  let streams = webrtcUI.getActiveStreams(true, true, true, true);
+  Assert.equal(streams.length, 0, "Should have found no active streams");
+
+  // The camera and microphone permissions should have been cleared.
+  let { state: camState } = SitePermissions.getForPrincipal(
+    tab2.linkedBrowser.contentPrincipal,
+    "camera",
+    tab2.linkedBrowser
+  );
+  Assert.equal(camState, SitePermissions.UNKNOWN);
+
+  let { state: micState } = SitePermissions.getForPrincipal(
+    tab2.linkedBrowser.contentPrincipal,
+    "microphone",
+    tab2.linkedBrowser
+  );
+  Assert.equal(micState, SitePermissions.UNKNOWN);
+
+  Assert.equal(
+    gBrowser.selectedTab,
+    tab3,
+    "Most recently tab that streams were shared with is selected"
+  );
+
+  BrowserTestUtils.removeTab(tab1);
+  BrowserTestUtils.removeTab(tab2);
+  BrowserTestUtils.removeTab(tab3);
+  BrowserTestUtils.removeTab(tab4);
+});
--- a/browser/base/content/test/webrtc/browser_tab_switch_warning.js
+++ b/browser/base/content/test/webrtc/browser_tab_switch_warning.js
@@ -184,16 +184,20 @@ async function ensureWarning(tab) {
   Assert.equal(
     panel.anchorNode,
     tab,
     "Expected the warning to be anchored to the right tab."
   );
 }
 
 add_task(async function setup() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["privacy.webrtc.sharedTabWarning", true]],
+  });
+
   // Loads up NEW_BACKGROUND_TABS_TO_OPEN background tabs at about:blank,
   // and waits until they're fully open.
   let uris = new Array(NEW_BACKGROUND_TABS_TO_OPEN).fill("about:blank");
 
   let loadPromises = Promise.all(
     uris.map(uri => BrowserTestUtils.waitForNewTab(gBrowser, uri, false, true))
   );
 
--- a/browser/base/content/test/webrtc/head.js
+++ b/browser/base/content/test/webrtc/head.js
@@ -1030,33 +1030,48 @@ async function runTests(tests, options =
  * Given a browser from a tab in this window, chooses to share
  * some combination of camera, mic or screen.
  *
  * @param {<xul:browser} browser - The browser to share devices with.
  * @param {boolean} camera - True to share a camera device.
  * @param {boolean} mic - True to share a microphone device.
  * @param {Number} [screenOrWin] - One of either SHARE_WINDOW or SHARE_SCREEN
  *   to share a window or screen. Defaults to neither.
+ * @param {boolean} remember - True to persist the permission to the
+ *   SitePermissions database as SitePermissions.SCOPE_PERSISTENT. Note that
+ *   callers are responsible for clearing this persistent permission.
  * @return {Promise}
  * @resolves {undefined} - Once the sharing is complete.
  */
-async function shareDevices(browser, camera, mic, screenOrWin = 0) {
+async function shareDevices(
+  browser,
+  camera,
+  mic,
+  screenOrWin = 0,
+  remember = false
+) {
   if (camera || mic) {
     let promise = promisePopupNotificationShown(
       "webRTC-shareDevices",
       null,
       window
     );
 
     await promiseRequestDevice(mic, camera, null, null, browser);
     await promise;
 
     checkDeviceSelectors(mic, camera);
     let observerPromise1 = expectObserverCalled("getUserMedia:response:allow");
     let observerPromise2 = expectObserverCalled("recording-device-events");
+
+    let rememberCheck = PopupNotifications.panel.querySelector(
+      ".popup-notification-checkbox"
+    );
+    rememberCheck.checked = remember;
+
     promise = promiseMessage("ok", () => {
       PopupNotifications.panel.firstElementChild.button.click();
     });
 
     await observerPromise1;
     await observerPromise2;
     await promise;
   }
--- a/browser/base/content/webrtcIndicator.js
+++ b/browser/base/content/webrtcIndicator.js
@@ -346,16 +346,21 @@ const WebRTCIndicator = {
       case "popuphiding": {
         this.onPopupHiding(event);
         break;
       }
       case "command": {
         this.onCommand(event);
         break;
       }
+      case "DOMWindowClose":
+      case "close": {
+        this.onClose(event);
+        break;
+      }
     }
   },
 
   onLoad() {
     this.loaded = true;
 
     if (AppConstants.platform == "macosx" || AppConstants.platform == "win") {
       this.statusBar = Cc["@mozilla.org/widget/systemstatusbar;1"].getService(
@@ -364,16 +369,22 @@ const WebRTCIndicator = {
     }
 
     this.updateIndicatorState();
 
     window.addEventListener("click", this);
     window.addEventListener("change", this);
     window.addEventListener("sizemodechange", this);
 
+    // There are two ways that the dialog can close - either via the
+    // .close() window method, or via the OS. We handle both of those
+    // cases here.
+    window.addEventListener("DOMWindowClose", this);
+    window.addEventListener("close", this);
+
     if (this.statusBar) {
       // We only want these events for the system status bar menus.
       window.addEventListener("popupshowing", this);
       window.addEventListener("popuphiding", this);
       window.addEventListener("command", this);
     }
 
     window.windowRoot.addEventListener("MozUpdateWindowPos", this);
@@ -385,40 +396,68 @@ const WebRTCIndicator = {
       bubbles: true,
       cancelable: true,
     });
     document.documentElement.dispatchEvent(ev);
 
     this.loaded = true;
   },
 
+  onClose(event) {
+    // This event is fired from when the indicator window tries to be closed.
+    // If we preventDefault() the event, we are able to cancel that close
+    // attempt.
+    //
+    // We want to do that if we're not showing the global mute toggles
+    // and we're still sharing a camera or a microphone so that we can
+    // keep the status bar indicators present (since those status bar
+    // indicators are bound to this window).
+    if (
+      !this.showGlobalMuteToggles &&
+      (webrtcUI.showCameraIndicator || webrtcUI.showMicrophoneIndicator)
+    ) {
+      event.preventDefault();
+      this.setVisibility(false);
+    }
+
+    if (!this.isClosingInternally) {
+      // Something has tried to close the indicator, but it wasn't webrtcUI.
+      // This means we might still have some streams being shared. To protect
+      // the user from unknowingly sharing streams, we shut those streams
+      // down.
+      //
+      // This only includes the camera and microphone streams if the user
+      // has the global mute toggles enabled, since these toggles visually
+      // associate the indicator with those streams.
+      let activeStreams = webrtcUI.getActiveStreams(
+        this.showGlobalMuteToggles /* camera */,
+        this.showGlobalMuteToggles /* microphone */,
+        true /* screen */,
+        true /* window */
+      );
+      webrtcUI.stopSharingStreams(
+        activeStreams,
+        this.showGlobalMuteToggles /* camera */,
+        this.showGlobalMuteToggles /* microphone */,
+        true /* screen */,
+        true /* window */
+      );
+    }
+  },
+
   onUnload() {
     Services.ppmm.sharedData.set("WebRTC:GlobalCameraMute", false);
     Services.ppmm.sharedData.set("WebRTC:GlobalMicrophoneMute", false);
     Services.ppmm.sharedData.flush();
 
     if (this.statusBar) {
       for (let menu of this.statusBarMenus) {
         this.statusBar.removeItem(menu);
       }
     }
-
-    if (!this.isClosingInternally) {
-      // Something has closed the indicator, but it wasn't webrtcUI. This
-      // means we might still have some streams being shared. To protect
-      // the user from unknowingly sharing streams, we shut those streams
-      // down.
-      let activeStreams = webrtcUI.getActiveStreams(
-        true /* camera */,
-        true /* microphone */,
-        true /* screen */,
-        true /* window */
-      );
-      webrtcUI.stopSharingStreams(activeStreams);
-    }
   },
 
   onClick(event) {
     switch (event.target.id) {
       case "stop-sharing": {
         let activeStreams = webrtcUI.getActiveStreams(
           false /* camera */,
           false /* microphone */,
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -495,16 +495,19 @@ var webrtcUI = {
    * Given some set of streams, stops device access for those streams.
    * Optionally, it's possible to stop a subset of the devices on those
    * streams by passing in optional arguments.
    *
    * Once the streams have been stopped, this method will also find the
    * newest stream's <xul:browser> and window, focus the window, and
    * select the browser.
    *
+   * For camera and microphone streams, this will also revoke any associated
+   * persistent permissions from SitePermissions.
+   *
    * @param {Array<Object>} activeStreams - An array of streams obtained via webrtcUI.getActiveStreams.
    * @param {boolean} stopCameras - True to stop the camera streams (defaults to true)
    * @param {boolean} stopMics - True to stop the microphone streams (defaults to true)
    * @param {boolean} stopScreens - True to stop the screen streams (defaults to true)
    * @param {boolean} stopWindows - True to stop the window streams (defaults to true)
    */
   stopSharingStreams(
     activeStreams,
@@ -567,59 +570,64 @@ var webrtcUI = {
               scope: SitePermissions.SCOPE_REQUEST,
               sharingState: webrtcState[id],
             });
           }
         }
       }
 
       for (let permission of permissions) {
-        let windowId = tab._sharingState.webRTC.windowId;
+        if (clearRequested[permission.id]) {
+          let windowId = tab._sharingState.webRTC.windowId;
 
-        if (permission.id == "screen") {
-          windowId = `screen:${webrtcState.windowId}`;
-        } else if (permission.id == "camera" || permission.id == "microphone") {
-          // If we set persistent permissions or the sharing has
-          // started due to existing persistent permissions, we need
-          // to handle removing these even for frames with different hostnames.
-          let origins = browser.getDevicePermissionOrigins("webrtc");
-          for (let origin of origins) {
-            // It's not possible to stop sharing one of camera/microphone
-            // without the other.
-            let principal;
-            for (let id of ["camera", "microphone"]) {
-              if (webrtcState[id]) {
-                if (!principal) {
-                  principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
-                    origin
-                  );
-                }
-                let perm = SitePermissions.getForPrincipal(principal, id);
-                if (
-                  perm.state == SitePermissions.ALLOW &&
-                  perm.scope == SitePermissions.SCOPE_PERSISTENT
-                ) {
-                  SitePermissions.removeFromPrincipal(principal, id);
+          if (permission.id == "screen") {
+            windowId = `screen:${webrtcState.windowId}`;
+          } else if (
+            permission.id == "camera" ||
+            permission.id == "microphone"
+          ) {
+            // If we set persistent permissions or the sharing has
+            // started due to existing persistent permissions, we need
+            // to handle removing these even for frames with different hostnames.
+            let origins = browser.getDevicePermissionOrigins("webrtc");
+            for (let origin of origins) {
+              // It's not possible to stop sharing one of camera/microphone
+              // without the other.
+              let principal;
+              for (let id of ["camera", "microphone"]) {
+                if (webrtcState[id]) {
+                  if (!principal) {
+                    principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+                      origin
+                    );
+                  }
+                  let perm = SitePermissions.getForPrincipal(principal, id);
+                  if (
+                    perm.state == SitePermissions.ALLOW &&
+                    perm.scope == SitePermissions.SCOPE_PERSISTENT
+                  ) {
+                    SitePermissions.removeFromPrincipal(principal, id);
+                  }
                 }
               }
             }
           }
-        }
+
+          let bc = webrtcState.browsingContext;
+          bc.currentWindowGlobal
+            .getActor("WebRTC")
+            .sendAsyncMessage("webrtc:StopSharing", windowId);
+          webrtcUI.forgetActivePermissionsFromBrowser(browser);
 
-        let bc = webrtcState.browsingContext;
-        bc.currentWindowGlobal
-          .getActor("WebRTC")
-          .sendAsyncMessage("webrtc:StopSharing", windowId);
-        webrtcUI.forgetActivePermissionsFromBrowser(browser);
-
-        SitePermissions.removeFromPrincipal(
-          browser.contentPrincipal,
-          permission.id,
-          browser
-        );
+          SitePermissions.removeFromPrincipal(
+            browser.contentPrincipal,
+            permission.id,
+            browser
+          );
+        }
       }
     }
 
     let window = browserToSelect.ownerGlobal;
     let gBrowser = browserToSelect.getTabBrowser();
     let tab = gBrowser.getTabForBrowser(browserToSelect);
     window.focus();
     gBrowser.selectedTab = tab;