Commit 06351a84 authored by Bogdan Tara's avatar Bogdan Tara
Browse files

Backed out 3 changesets (bug 1579489) for ES lint failure on browser_ext_webrtc.js CLOSED TREE

Backed out changeset 281d238e6259 (bug 1579489)
Backed out changeset 764628963a3c (bug 1579489)
Backed out changeset 680a45ca89b7 (bug 1579489)
parent d65daa1f
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -273,8 +273,6 @@ skip-if = os == 'mac' # Save as PDF not supported on Mac OS X
[browser_ext_urlbar_contextual_tip.js]
[browser_ext_user_events.js]
[browser_ext_webRequest.js]
[browser_ext_webrtc.js]
skip-if = os == 'mac' # Bug 1565738
[browser_ext_webNavigation_frameId0.js]
[browser_ext_webNavigation_getFrames.js]
[browser_ext_webNavigation_onCreatedNavigationTarget.js]
+0 −133
Original line number Diff line number Diff line
"use strict";

const { PermissionTestUtils } = ChromeUtils.import(
  "resource://testing-common/PermissionTestUtils.jsm"
);

add_task(async function setup() {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["media.navigator.permission.fake", true],
    ],
  });
});

add_task(async function test_background_request() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {},
    async background() {
      browser.test.onMessage.addListener(async msg => {
        if (msg.type != "testGUM") {
          browser.test.fail("unknown message");
        }

        await browser.test.assertRejects(
          navigator.mediaDevices.getUserMedia({ audio: true }),
          /The request is not allowed/,
          "Calling gUM in background pages throws an error"
        );
        browser.test.notifyPass("done");
      });
    },
  });

  await extension.startup();

  let policy = WebExtensionPolicy.getByID(extension.id);
  let principal = policy.extension.principal;
  // Add a permission for the extension to make sure that we throw even
  // if permission was given.
  PermissionTestUtils.add(principal, "microphone", Services.perms.ALLOW_ACTION);

  let finished = extension.awaitFinish("done");
  extension.sendMessage({ type: "testGUM" });
  await finished;

  PermissionTestUtils.remove(principal, "microphone");
  await extension.unload();
});

let scriptPage = url =>
  `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>${url}</body></html>`;

add_task(async function test_popup_request() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      browser_action: {
        default_popup: "popup.html",
        browser_style: true,
      },
    },

    files: {
      "popup.html": scriptPage("popup.js"),
      "popup.js": function() {
        browser.test
          .assertRejects(
            navigator.mediaDevices.getUserMedia({ audio: true }),
            /The request is not allowed/,
            "Calling gUM in popup pages without permission throws an error"
          )
          .then(function() {
            browser.test.notifyPass("done");
          });
      },
    },
  });

  await extension.startup();
  clickBrowserAction(extension);
  await extension.awaitFinish("done");
  await extension.unload();

  extension = ExtensionTestUtils.loadExtension({
    manifest: {
      // Use the same url for background page and browserAction popup,
      // to double-check that the page url is not being used to decide
      // if webRTC requests should be allowed or not.
      background: { page: "page.html" },
      browser_action: {
        default_popup: "page.html",
        browser_style: true,
      },
    },

    files: {
      "page.html": scriptPage("page.js"),
      "page.js": async function() {
        const isBackgroundPage =
          window == (await browser.runtime.getBackgroundPage());

        if (isBackgroundPage) {
          await browser.test.assertRejects(
            navigator.mediaDevices.getUserMedia({ audio: true }),
            /The request is not allowed/,
            "Calling gUM in background pages throws an error"
          );
        } else {
          try {
            await navigator.mediaDevices.getUserMedia({ audio: true });
            browser.test.notifyPass("done");
          } catch (err) {
            browser.test.fail(`Failed with error ${err.message}`);
            browser.test.notifyFail("done");
          }
        }
      },
    },
  });

  // Add a permission for the extension to make sure that we throw even
  // if permission was given.
  await extension.startup();

  let policy = WebExtensionPolicy.getByID(extension.id);
  let principal = policy.extension.principal;

  PermissionTestUtils.add(principal, "microphone", Services.perms.ALLOW_ACTION);
  clickBrowserAction(extension);

  await extension.awaitFinish("done");
  PermissionTestUtils.remove(principal, "microphone");
  await extension.unload();
});
+99 −148
Original line number Diff line number Diff line
@@ -468,115 +468,6 @@ function stopRecording(aBrowser, aRequest) {
  }
}

/**
 * Checks if the principal has sufficient permissions
 * to fulfill the given request. If the request can be
 * fulfilled, a message is sent to the child
 * signaling that WebRTC permissions were given and
 * this function will return true.
 */
function checkRequestAllowed(aRequest, aPrincipal, aBrowser) {
  if (!aRequest.secure) {
    return false;
  }

  let { audioDevices, videoDevices, sharingScreen } = aRequest;

  let micAllowed =
    SitePermissions.getForPrincipal(aPrincipal, "microphone").state ==
    SitePermissions.ALLOW;
  let camAllowed =
    SitePermissions.getForPrincipal(aPrincipal, "camera").state ==
    SitePermissions.ALLOW;

  let perms = Services.perms;
  let mediaManagerPerm = perms.testExactPermissionFromPrincipal(
    aPrincipal,
    "MediaManagerVideo"
  );
  if (mediaManagerPerm) {
    perms.removeFromPrincipal(aPrincipal, "MediaManagerVideo");
  }

  // Screen sharing shouldn't follow the camera permissions.
  if (videoDevices.length && sharingScreen) {
    camAllowed = false;
  }
  if (aRequest.isThirdPartyOrigin) {
    camAllowed = false;
    micAllowed = false;
  }

  let activeCamera;
  let activeMic;

  // Always prompt for screen sharing
  if (!sharingScreen) {
    for (let device of videoDevices) {
      let set = webrtcUI.activePerms.get(aBrowser.outerWindowID);
      if (set && set.has(aRequest.windowID + device.mediaSource + device.id)) {
        activeCamera = device;
        break;
      }
    }

    for (let device of audioDevices) {
      let set = webrtcUI.activePerms.get(aBrowser.outerWindowID);
      if (set && set.has(aRequest.windowID + device.mediaSource + device.id)) {
        activeMic = device;
        break;
      }
    }
  }

  if (
    (!audioDevices.length || micAllowed || activeMic) &&
    (!videoDevices.length || camAllowed || activeCamera)
  ) {
    let allowedDevices = [];
    if (videoDevices.length) {
      allowedDevices.push((activeCamera || videoDevices[0]).deviceIndex);
      Services.perms.addFromPrincipal(
        aPrincipal,
        "MediaManagerVideo",
        Services.perms.ALLOW_ACTION,
        Services.perms.EXPIRE_SESSION
      );
    }
    if (audioDevices.length) {
      allowedDevices.push((activeMic || audioDevices[0]).deviceIndex);
    }

    // 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 = aBrowser;
    browser._devicePermissionPrincipals =
      browser._devicePermissionPrincipals || [];
    browser._devicePermissionPrincipals.push(aPrincipal);

    let camNeeded = !!videoDevices.length;
    let micNeeded = !!audioDevices.length;
    checkOSPermission(camNeeded, micNeeded).then(havePermission => {
      if (havePermission) {
        let mm = browser.messageManager;
        mm.sendAsyncMessage("webrtc:Allow", {
          callID: aRequest.callID,
          windowID: aRequest.windowID,
          devices: allowedDevices,
        });
      } else {
        denyRequestNoPermission(browser, aRequest);
      }
    });

    return true;
  }

  return false;
}

function prompt(aBrowser, aRequest) {
  let {
    audioDevices,
@@ -590,39 +481,6 @@ function prompt(aBrowser, aRequest) {
    aRequest.origin
  );

  // For add-on principals, we immediately check for permission instead
  // of waiting for the notification to focus. This allows for supporting
  // cases such as browserAction popups where no prompt is shown.
  if (principal.addonPolicy) {
    let isPopup = false;
    let isBackground = false;

    for (let view of principal.addonPolicy.extension.views) {
      if (view.viewType == "popup" && view.xulBrowser == aBrowser) {
        isPopup = true;
      }
      if (view.viewType == "background" && view.xulBrowser == aBrowser) {
        isBackground = true;
      }
    }

    // Recording from background pages is considered too sensitive and will
    // always be denied.
    if (isBackground) {
      denyRequest(aBrowser, aRequest);
      return;
    }

    // If the request comes from a popup, we don't want to show the prompt,
    // but we do want to allow the request if the user previously gave permission.
    if (isPopup) {
      if (!checkRequestAllowed(aRequest, principal, aBrowser)) {
        denyRequest(aBrowser, aRequest);
      }
      return;
    }
  }

  // If the user has already denied access once in this tab,
  // deny again without even showing the notification icon.
  if (
@@ -760,10 +618,106 @@ function prompt(aBrowser, aRequest) {
      // it is handled synchronously before we add the notification.
      // Handling of ALLOW is delayed until the popupshowing event,
      // to avoid granting permissions automatically to background tabs.
      if (checkRequestAllowed(aRequest, principal, aBrowser)) {
      if (aRequest.secure) {
        let micAllowed =
          SitePermissions.getForPrincipal(principal, "microphone").state ==
          SitePermissions.ALLOW;
        let camAllowed =
          SitePermissions.getForPrincipal(principal, "camera").state ==
          SitePermissions.ALLOW;

        let perms = Services.perms;
        let mediaManagerPerm = perms.testExactPermissionFromPrincipal(
          principal,
          "MediaManagerVideo"
        );
        if (mediaManagerPerm) {
          perms.removeFromPrincipal(principal, "MediaManagerVideo");
        }

        // Screen sharing shouldn't follow the camera permissions.
        if (videoDevices.length && sharingScreen) {
          camAllowed = false;
        }
        if (aRequest.isThirdPartyOrigin) {
          camAllowed = false;
          micAllowed = false;
        }

        let activeCamera;
        let activeMic;

        // Always prompt for screen sharing
        if (!sharingScreen) {
          for (let device of videoDevices) {
            let set = webrtcUI.activePerms.get(aBrowser.outerWindowID);
            if (
              set &&
              set.has(aRequest.windowID + device.mediaSource + device.id)
            ) {
              activeCamera = device;
              break;
            }
          }

          for (let device of audioDevices) {
            let set = webrtcUI.activePerms.get(aBrowser.outerWindowID);
            if (
              set &&
              set.has(aRequest.windowID + device.mediaSource + device.id)
            ) {
              activeMic = device;
              break;
            }
          }
        }

        if (
          (!audioDevices.length || micAllowed || activeMic) &&
          (!videoDevices.length || camAllowed || activeCamera)
        ) {
          let allowedDevices = [];
          if (videoDevices.length) {
            allowedDevices.push((activeCamera || videoDevices[0]).deviceIndex);
            Services.perms.addFromPrincipal(
              principal,
              "MediaManagerVideo",
              Services.perms.ALLOW_ACTION,
              Services.perms.EXPIRE_SESSION
            );
          }
          if (audioDevices.length) {
            allowedDevices.push((activeMic || audioDevices[0]).deviceIndex);
          }

          // 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._devicePermissionPrincipals =
            browser._devicePermissionPrincipals || [];
          browser._devicePermissionPrincipals.push(principal);

          let camNeeded = !!videoDevices.length;
          let micNeeded = !!audioDevices.length;
          checkOSPermission(camNeeded, micNeeded).then(havePermission => {
            if (havePermission) {
              let mm = browser.messageManager;
              mm.sendAsyncMessage("webrtc:Allow", {
                callID: aRequest.callID,
                windowID: aRequest.windowID,
                devices: allowedDevices,
              });
            } else {
              denyRequestNoPermission(browser, aRequest);
            }
          });

          this.remove();
          return true;
        }
      }

      function listDevices(menupopup, devices) {
        while (menupopup.lastChild) {
@@ -1128,8 +1082,6 @@ function prompt(aBrowser, aRequest) {
          devices: allowedDevices,
        });
      };

      // If we haven't handled the permission yet, we want to show the doorhanger.
      return false;
    },
  };
@@ -1156,7 +1108,6 @@ function prompt(aBrowser, aRequest) {

    options.checkbox = {
      label: stringBundle.getString("getUserMedia.remember"),
      checked: principal.isAddonOrExpandedAddonPrincipal,
      checkedState: reasonForNoPermanentAllow
        ? {
            disableMainAction: true,