зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1649032 - If the user manages to close the WebRTC indicator, close all of the active streams. r=pbz
Differential Revision: https://phabricator.services.mozilla.com/D82989
This commit is contained in:
Родитель
d432995562
Коммит
be5766d15a
|
@ -8,12 +8,6 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
const { webrtcUI } = ChromeUtils.import("resource:///modules/webrtcUI.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"SitePermissions",
|
||||
"resource:///modules/SitePermissions.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AppConstants",
|
||||
|
@ -47,6 +41,22 @@ function updateIndicatorState() {
|
|||
WebRTCIndicator.updateIndicatorState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public function called by webrtcUI to indicate that webrtcUI
|
||||
* is about to close the indicator. This is so that we can differentiate
|
||||
* between closes that are caused by webrtcUI, and closes that are
|
||||
* caused by other reasons (like the user closing the window via the
|
||||
* OS window controls somehow).
|
||||
*
|
||||
* If the window is closed without having called this method first, the
|
||||
* indicator will ask webrtcUI to shutdown any remaining streams and then
|
||||
* select and focus the most recent browser tab that a stream was shared
|
||||
* with.
|
||||
*/
|
||||
function closingInternally() {
|
||||
WebRTCIndicator.closingInternally();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main control object for the WebRTC global indicator
|
||||
*/
|
||||
|
@ -66,6 +76,7 @@ const WebRTCIndicator = {
|
|||
|
||||
this.updatingIndicatorState = false;
|
||||
this.loaded = false;
|
||||
this.isClosingInternally = false;
|
||||
|
||||
if (AppConstants.platform == "macosx") {
|
||||
this.macOSIndicator = new MacOSWebRTCStatusbarIndicator();
|
||||
|
@ -341,6 +352,21 @@ const WebRTCIndicator = {
|
|||
onUnload() {
|
||||
if (this.macOSIndicator) {
|
||||
this.macOSIndicator.close();
|
||||
this.macOSIndicator = null;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -353,7 +379,7 @@ const WebRTCIndicator = {
|
|||
true /* screen */,
|
||||
false /* window */
|
||||
);
|
||||
this.stopSharingScreen(activeStreams);
|
||||
webrtcUI.stopSharingStreams(activeStreams);
|
||||
break;
|
||||
}
|
||||
case "stop-sharing-window": {
|
||||
|
@ -363,14 +389,22 @@ const WebRTCIndicator = {
|
|||
false /* screen */,
|
||||
true /* window */
|
||||
);
|
||||
|
||||
if (this.sharingBrowserWindow) {
|
||||
let browserWindowStreams = activeStreams.filter(stream => {
|
||||
return stream.devices.some(device => device.scary);
|
||||
});
|
||||
this.stopSharingScreen(browserWindowStreams);
|
||||
} else {
|
||||
this.stopSharingScreen(activeStreams);
|
||||
webrtcUI.stopSharingStreams(
|
||||
browserWindowStreams,
|
||||
false /* camera */,
|
||||
false /* microphone */,
|
||||
false /* screen */,
|
||||
true /* window */
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
webrtcUI.stopSharingStreams(activeStreams);
|
||||
break;
|
||||
}
|
||||
case "microphone-button":
|
||||
|
@ -392,97 +426,6 @@ const WebRTCIndicator = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds the most recent share in the set of active streams passed,
|
||||
* and ends it.
|
||||
*
|
||||
* @param activeStreams (Array<Object>)
|
||||
* An array of streams obtained via webrtcUI.getActiveStreams.
|
||||
* It is presumed that one or more of those streams includes
|
||||
* one that is sharing a screen or window.
|
||||
*/
|
||||
stopSharingScreen(activeStreams) {
|
||||
if (!activeStreams.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We'll default to choosing the most recent active stream to
|
||||
// revoke the permissions from.
|
||||
let chosenStream = activeStreams[activeStreams.length - 1];
|
||||
let { browser } = chosenStream;
|
||||
|
||||
// This intentionally copies its approach from browser-siteIdentity.js,
|
||||
// which powers the permission revocation from the Permissions Panel.
|
||||
// Ideally, we would de-duplicate this with a shared revocation mechanism,
|
||||
// but to lower the risk of uplifting this change, we keep it separate for
|
||||
// now.
|
||||
let gBrowser = browser.getTabBrowser();
|
||||
if (!gBrowser) {
|
||||
Cu.reportError("Can't stop sharing screen - cannot find gBrowser.");
|
||||
return;
|
||||
}
|
||||
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (!tab) {
|
||||
Cu.reportError("Can't stop sharing screen - cannot find tab.");
|
||||
return;
|
||||
}
|
||||
|
||||
let permissions = SitePermissions.getAllPermissionDetailsForBrowser(
|
||||
browser
|
||||
);
|
||||
|
||||
let webrtcState = tab._sharingState.webRTC;
|
||||
let windowId = `screen:${webrtcState.windowId}`;
|
||||
// If WebRTC device or screen permissions are in use, we need to find
|
||||
// the associated permission item to set the sharingState field.
|
||||
if (webrtcState.screen) {
|
||||
let found = false;
|
||||
for (let permission of permissions) {
|
||||
if (permission.id != "screen") {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
permission.sharingState = webrtcState.screen;
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
// If the permission item we were looking for doesn't exist,
|
||||
// the user has temporarily allowed sharing and we need to add
|
||||
// an item in the permissions array to reflect this.
|
||||
permissions.push({
|
||||
id: "screen",
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: webrtcState.screen,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let permission = permissions.find(perm => {
|
||||
return perm.id == "screen";
|
||||
});
|
||||
|
||||
if (!permission) {
|
||||
Cu.reportError(
|
||||
"Can't stop sharing screen - cannot find screen permission."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let bc = webrtcState.browsingContext;
|
||||
bc.currentWindowGlobal
|
||||
.getActor("WebRTC")
|
||||
.sendAsyncMessage("webrtc:StopSharing", windowId);
|
||||
webrtcUI.forgetActivePermissionsFromBrowser(browser);
|
||||
|
||||
SitePermissions.removeFromPrincipal(
|
||||
browser.contentPrincipal,
|
||||
permission.id,
|
||||
browser
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the most recent share in the set of active streams passed,
|
||||
* and opens up the Permissions Panel for the associated tab to
|
||||
|
@ -517,6 +460,13 @@ const WebRTCIndicator = {
|
|||
docEl.removeAttribute(attr);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See the documentation on the script global closingInternally() function.
|
||||
*/
|
||||
closingInternally() {
|
||||
this.isClosingInternally = true;
|
||||
},
|
||||
};
|
||||
|
||||
WebRTCIndicator.init();
|
||||
|
|
|
@ -31,6 +31,11 @@ ChromeUtils.defineModuleGetter(
|
|||
"XPCOMUtils",
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"SitePermissions",
|
||||
"resource:///modules/SitePermissions.jsm"
|
||||
);
|
||||
|
||||
var webrtcUI = {
|
||||
initialized: false,
|
||||
|
@ -482,6 +487,140 @@ var webrtcUI = {
|
|||
this.updateGlobalIndicator();
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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,
|
||||
stopCameras = true,
|
||||
stopMics = true,
|
||||
stopScreens = true,
|
||||
stopWindows = true
|
||||
) {
|
||||
if (!activeStreams.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mostRecentStream = activeStreams[activeStreams.length - 1];
|
||||
let { browser: browserToSelect } = mostRecentStream;
|
||||
|
||||
for (let stream of activeStreams) {
|
||||
let { browser } = stream;
|
||||
|
||||
let gBrowser = browser.getTabBrowser();
|
||||
if (!gBrowser) {
|
||||
Cu.reportError("Can't stop sharing stream - cannot find gBrowser.");
|
||||
continue;
|
||||
}
|
||||
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (!tab) {
|
||||
Cu.reportError("Can't stop sharing stream - cannot find tab.");
|
||||
continue;
|
||||
}
|
||||
|
||||
let permissions = SitePermissions.getAllPermissionDetailsForBrowser(
|
||||
browser
|
||||
);
|
||||
|
||||
let webrtcState = tab._sharingState.webRTC;
|
||||
let clearRequested = {
|
||||
camera: stopCameras,
|
||||
microphone: stopMics,
|
||||
screen: stopScreens || stopWindows,
|
||||
};
|
||||
|
||||
for (let id of ["camera", "microphone", "screen"]) {
|
||||
if (webrtcState[id] && clearRequested[id]) {
|
||||
let found = false;
|
||||
for (let permission of permissions) {
|
||||
if (permission.id != id) {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
permission.sharingState = webrtcState[id];
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
// If the permission item we were looking for doesn't exist,
|
||||
// the user has temporarily allowed sharing and we need to add
|
||||
// an item in the permissions array to reflect this.
|
||||
permissions.push({
|
||||
id,
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: webrtcState[id],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let permission of permissions) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bc = webrtcState.browsingContext;
|
||||
bc.currentWindowGlobal
|
||||
.getActor("WebRTC")
|
||||
.sendAsyncMessage("webrtc:StopSharing", windowId);
|
||||
webrtcUI.forgetActivePermissionsFromBrowser(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;
|
||||
},
|
||||
|
||||
updateIndicators(aTopBrowsingContext) {
|
||||
let tabState = this.getCombinedStateForBrowser(aTopBrowsingContext);
|
||||
|
||||
|
@ -644,6 +783,17 @@ var webrtcUI = {
|
|||
}
|
||||
}
|
||||
} else if (gIndicatorWindow) {
|
||||
if (
|
||||
!webrtcUI.useLegacyGlobalIndicator &&
|
||||
gIndicatorWindow.closingInternally
|
||||
) {
|
||||
// Before calling .close(), we call .closingInternally() to allow us to
|
||||
// differentiate between situations where the indicator closes because
|
||||
// we no longer want to show the indicator (this case), and cases where
|
||||
// the user has found a way to close the indicator via OS window control
|
||||
// mechanisms.
|
||||
gIndicatorWindow.closingInternally();
|
||||
}
|
||||
gIndicatorWindow.close();
|
||||
gIndicatorWindow = null;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче