From ee8e5475f42edf8bdbd6f196720669eb2d3efabb Mon Sep 17 00:00:00 2001 From: Mihai Alexandru Michis Date: Mon, 16 Sep 2019 22:02:47 +0300 Subject: [PATCH] Backed out 3 changesets (bug 1579489) for causing bc failures at browser_ext_webrtc.js CLOSED TREE Backed out changeset 71978ebe41f1 (bug 1579489) Backed out changeset b5e35c96c2f7 (bug 1579489) Backed out changeset 71130160afee (bug 1579489) --- .../extensions/test/browser/browser.ini | 1 - .../test/browser/browser_ext_webrtc.js | 125 --------- browser/modules/webrtcUI.jsm | 247 +++++++----------- 3 files changed, 99 insertions(+), 274 deletions(-) delete mode 100644 browser/components/extensions/test/browser/browser_ext_webrtc.js diff --git a/browser/components/extensions/test/browser/browser.ini b/browser/components/extensions/test/browser/browser.ini index 02db60f405ea..405f62c12a67 100644 --- a/browser/components/extensions/test/browser/browser.ini +++ b/browser/components/extensions/test/browser/browser.ini @@ -273,7 +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] [browser_ext_webNavigation_frameId0.js] [browser_ext_webNavigation_getFrames.js] [browser_ext_webNavigation_onCreatedNavigationTarget.js] diff --git a/browser/components/extensions/test/browser/browser_ext_webrtc.js b/browser/components/extensions/test/browser/browser_ext_webrtc.js deleted file mode 100644 index aa9fa7cc93c3..000000000000 --- a/browser/components/extensions/test/browser/browser_ext_webrtc.js +++ /dev/null @@ -1,125 +0,0 @@ -"use strict"; - -const { PermissionTestUtils } = ChromeUtils.import( - "resource://testing-common/PermissionTestUtils.jsm" -); - -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 => - `${url}`; - -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(); -}); diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm index 5e7757d284d9..06235e3599d4 100644 --- a/browser/modules/webrtcUI.jsm +++ b/browser/modules/webrtcUI.jsm @@ -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,9 +618,105 @@ 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)) { - this.remove(); - return true; + 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) { @@ -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,