зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1483631
) for failing at browser_temporary_permissions.js on a CLOSED TREE.
Backed out changeset f5bb5f6a148f (bug1483631
) Backed out changeset c5e562c1d590 (bug1483631
) Backed out changeset 7ef09193a7ef (bug1483631
) Backed out changeset a909dcbbea2b (bug1483631
)
This commit is contained in:
Родитель
2eee21b4c3
Коммит
4f21dcd081
|
@ -284,40 +284,14 @@ function prompt(
|
|||
// So, what you are looking at here is not a real nsIContentPermissionRequest, but
|
||||
// something that looks really similar and will be transmitted to webrtcUI.jsm
|
||||
// for showing the prompt.
|
||||
// Note that we basically do the permission delegate check in
|
||||
// nsIContentPermissionRequest, but because webrtc uses their own prompting
|
||||
// system, we should manually apply the delegate policy here. Permission
|
||||
// should be delegated using Feature Policy and top principal
|
||||
const shouldDelegatePermission =
|
||||
Services.prefs.getBoolPref("permissions.delegation.enabled", false) &&
|
||||
Services.prefs.getBoolPref("dom.security.featurePolicy.enabled", false);
|
||||
|
||||
const origin = shouldDelegatePermission
|
||||
? aContentWindow.top.document.nodePrincipal.origin
|
||||
: aContentWindow.document.nodePrincipal.origin;
|
||||
|
||||
let secondOrigin = undefined;
|
||||
if (shouldDelegatePermission) {
|
||||
const permDelegateHandler = aContentWindow.document.permDelegateHandler.QueryInterface(
|
||||
Ci.nsIPermissionDelegateHandler
|
||||
);
|
||||
if (permDelegateHandler.maybeUnsafePermissionDelegate(requestTypes)) {
|
||||
// We are going to prompt both first party and third party origin.
|
||||
// SecondOrigin should be third party
|
||||
secondOrigin = aContentWindow.document.nodePrincipal.origin;
|
||||
}
|
||||
}
|
||||
|
||||
let request = {
|
||||
callID: aCallID,
|
||||
windowID: aWindowID,
|
||||
origin,
|
||||
secondOrigin,
|
||||
origin: aContentWindow.document.nodePrincipal.origin,
|
||||
documentURI: aContentWindow.document.documentURI,
|
||||
secure: aSecure,
|
||||
isHandlingUserInput: aIsHandlingUserInput,
|
||||
isThirdPartyOrigin,
|
||||
shouldDelegatePermission,
|
||||
requestTypes,
|
||||
sharingScreen,
|
||||
sharingAudio,
|
||||
|
|
|
@ -421,9 +421,9 @@ pref("permissions.postPrompt.animate", true);
|
|||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("permissions.delegation.enabled", true);
|
||||
pref("permissions.delegation.enable", true);
|
||||
#else
|
||||
pref("permissions.delegation.enabled", false);
|
||||
pref("permissions.delegation.enable", false);
|
||||
#endif
|
||||
|
||||
// handle links targeting new windows
|
||||
|
@ -1721,12 +1721,6 @@ pref("view_source.tab", true);
|
|||
|
||||
pref("dom.serviceWorkers.enabled", true);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("dom.security.featurePolicy.enabled", true);
|
||||
#else
|
||||
pref("dom.security.featurePolicy.enabled", false);
|
||||
#endif
|
||||
|
||||
// Enable Push API.
|
||||
pref("dom.push.enabled", true);
|
||||
|
||||
|
|
|
@ -2,16 +2,13 @@
|
|||
support-files=
|
||||
head.js
|
||||
permissions.html
|
||||
temporary_permissions_subframe.html
|
||||
temporary_permissions_frame.html
|
||||
|
||||
[browser_canvas_fingerprinting_resistance.js]
|
||||
skip-if = debug || os == "linux" && asan # Bug 1522069
|
||||
[browser_permissions.js]
|
||||
[browser_permissions_delegate_vibrate.js]
|
||||
support-files=
|
||||
empty.html
|
||||
[browser_permission_delegate_geo.js]
|
||||
skip-if = fission # Bug 1587743
|
||||
[browser_permissions_event_telemetry.js]
|
||||
[browser_permissions_postPrompt.js]
|
||||
support-files=
|
||||
|
@ -22,6 +19,7 @@ support-files=
|
|||
[browser_reservedkey.js]
|
||||
[browser_temporary_permissions.js]
|
||||
support-files =
|
||||
temporary_permissions_subframe.html
|
||||
../webrtc/get_user_media.html
|
||||
[browser_autoplay_blocked.js]
|
||||
support-files =
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const ORIGIN = "https://example.com";
|
||||
const CROSS_SUBFRAME_PAGE =
|
||||
getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) +
|
||||
"temporary_permissions_subframe.html";
|
||||
|
||||
const CROSS_FRAME_PAGE =
|
||||
getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) +
|
||||
"temporary_permissions_frame.html";
|
||||
|
||||
const PromptResult = {
|
||||
ALLOW: "allow",
|
||||
DENY: "deny",
|
||||
PROMPT: "prompt",
|
||||
};
|
||||
|
||||
var Perms = Services.perms;
|
||||
var uri = NetUtil.newURI(ORIGIN);
|
||||
var principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
|
||||
|
||||
async function checkNotificationBothOrigins(
|
||||
firstPartyOrigin,
|
||||
thirdPartyOrigin
|
||||
) {
|
||||
// Notification is shown, check label and deny to clean
|
||||
let popuphidden = BrowserTestUtils.waitForEvent(
|
||||
PopupNotifications.panel,
|
||||
"popuphidden"
|
||||
);
|
||||
|
||||
let notification = PopupNotifications.panel.firstElementChild;
|
||||
// Check the label of the notificaiton should be the first party
|
||||
is(
|
||||
PopupNotifications.getNotification("geolocation").options.name,
|
||||
firstPartyOrigin,
|
||||
"Use first party's origin"
|
||||
);
|
||||
|
||||
// Check the second name of the notificaiton should be the third party
|
||||
is(
|
||||
PopupNotifications.getNotification("geolocation").options.secondName,
|
||||
thirdPartyOrigin,
|
||||
"Use third party's origin"
|
||||
);
|
||||
|
||||
// Check remember checkbox is hidden
|
||||
let checkbox = notification.checkbox;
|
||||
ok(!!checkbox, "checkbox is present");
|
||||
ok(checkbox.hidden, "checkbox is not visible");
|
||||
ok(!checkbox.checked, "checkbox not checked");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
|
||||
await popuphidden;
|
||||
}
|
||||
|
||||
async function checkGeolocation(browser, frameId, expect) {
|
||||
let waitForPrompt = BrowserTestUtils.waitForEvent(
|
||||
PopupNotifications.panel,
|
||||
"popupshown"
|
||||
);
|
||||
|
||||
let isPrompt = expect == PromptResult.PROMPT;
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ frameId, expect, isPrompt }],
|
||||
async args => {
|
||||
let frame = content.document.getElementById(args.frameId);
|
||||
|
||||
let waitForNoPrompt = new Promise(resolve => {
|
||||
function onMessage(event) {
|
||||
// Check the result right here because there's no notification
|
||||
Assert.equal(
|
||||
event.data,
|
||||
args.expect,
|
||||
"Correct expectation for third party"
|
||||
);
|
||||
content.window.removeEventListener("message", onMessage);
|
||||
resolve();
|
||||
}
|
||||
|
||||
if (!args.isPrompt) {
|
||||
content.window.addEventListener("message", onMessage);
|
||||
}
|
||||
});
|
||||
|
||||
await content.SpecialPowers.spawn(frame, [], async () => {
|
||||
const { E10SUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/E10SUtils.jsm"
|
||||
);
|
||||
|
||||
E10SUtils.wrapHandlingUserInput(this.content, true, function() {
|
||||
let frameDoc = this.content.document;
|
||||
frameDoc.getElementById("geo").click();
|
||||
});
|
||||
});
|
||||
|
||||
if (!args.isPrompt) {
|
||||
await waitForNoPrompt;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (isPrompt) {
|
||||
await waitForPrompt;
|
||||
}
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await new Promise(r => {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{
|
||||
set: [
|
||||
["dom.security.featurePolicy.enabled", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true],
|
||||
["permissions.delegation.enabled", true],
|
||||
],
|
||||
},
|
||||
r
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Test that temp blocked permissions in first party affect the third party
|
||||
// iframe.
|
||||
add_task(async function testUseTempPermissionsFirstParty() {
|
||||
await BrowserTestUtils.withNewTab(CROSS_SUBFRAME_PAGE, async function(
|
||||
browser
|
||||
) {
|
||||
SitePermissions.setForPrincipal(
|
||||
principal,
|
||||
"geo",
|
||||
SitePermissions.BLOCK,
|
||||
SitePermissions.SCOPE_TEMPORARY,
|
||||
browser
|
||||
);
|
||||
|
||||
await checkGeolocation(browser, "frame", PromptResult.DENY);
|
||||
|
||||
SitePermissions.removeFromPrincipal(principal, "geo", browser);
|
||||
});
|
||||
});
|
||||
|
||||
// Test that persistent permissions in first party affect the third party
|
||||
// iframe.
|
||||
add_task(async function testUsePersistentPermissionsFirstParty() {
|
||||
await BrowserTestUtils.withNewTab(CROSS_SUBFRAME_PAGE, async function(
|
||||
browser
|
||||
) {
|
||||
async function checkPermission(aPermission, aExpect) {
|
||||
PermissionTestUtils.add(uri, "geo", aPermission);
|
||||
await checkGeolocation(browser, "frame", aExpect);
|
||||
|
||||
if (aExpect == PromptResult.PROMPT) {
|
||||
// Notification is shown, check label and deny to clean
|
||||
let popuphidden = BrowserTestUtils.waitForEvent(
|
||||
PopupNotifications.panel,
|
||||
"popuphidden"
|
||||
);
|
||||
|
||||
let notification = PopupNotifications.panel.firstElementChild;
|
||||
// Check the label of the notificaiton should be the first party
|
||||
is(
|
||||
PopupNotifications.getNotification("geolocation").options.name,
|
||||
uri.host,
|
||||
"Use first party's origin"
|
||||
);
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
|
||||
|
||||
await popuphidden;
|
||||
SitePermissions.removeFromPrincipal(null, "geo", browser);
|
||||
}
|
||||
|
||||
PermissionTestUtils.remove(uri, "geo");
|
||||
}
|
||||
|
||||
await checkPermission(Perms.PROMPT_ACTION, PromptResult.PROMPT);
|
||||
await checkPermission(Perms.DENY_ACTION, PromptResult.DENY);
|
||||
await checkPermission(Perms.ALLOW_ACTION, PromptResult.ALLOW);
|
||||
});
|
||||
});
|
||||
|
||||
// Test that we should prompt if we are in unsafe permission delegation. The
|
||||
// prompt popup should include both first and third party origin.
|
||||
add_task(async function testPromptInMaybeUnsafePermissionDelegation() {
|
||||
await BrowserTestUtils.withNewTab(CROSS_SUBFRAME_PAGE, async function(
|
||||
browser
|
||||
) {
|
||||
// Persistent allow top level origin
|
||||
PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION);
|
||||
|
||||
await checkGeolocation(browser, "frameAllowsAll", PromptResult.PROMPT);
|
||||
await checkNotificationBothOrigins(uri.host, "example.org");
|
||||
|
||||
SitePermissions.removeFromPrincipal(null, "geo", browser);
|
||||
PermissionTestUtils.remove(uri, "geo");
|
||||
});
|
||||
});
|
||||
|
||||
// Test that we should prompt if we are in unsafe permission delegation and
|
||||
// change location to origin which is not explicitly trusted. The prompt popup
|
||||
// should include both first and third party origin.
|
||||
add_task(async function testPromptChangeLocatioUnsafePermissionDelegation() {
|
||||
await BrowserTestUtils.withNewTab(CROSS_SUBFRAME_PAGE, async function(
|
||||
browser
|
||||
) {
|
||||
// Persistent allow top level origin
|
||||
PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION);
|
||||
|
||||
// Request change location.
|
||||
await ContentTask.spawn(browser, { host: uri.host }, async function(args) {
|
||||
let frame = content.document.getElementById("frameAllowsAll");
|
||||
await new Promise(resolve => {
|
||||
function listener() {
|
||||
frame.removeEventListener("load", listener, true);
|
||||
resolve();
|
||||
}
|
||||
frame.addEventListener("load", listener, true);
|
||||
|
||||
frame.contentWindow.location =
|
||||
"https://test1.example.com/browser/browser/base/content/test/permissions/permissions.html";
|
||||
});
|
||||
});
|
||||
|
||||
await checkGeolocation(browser, "frameAllowsAll", PromptResult.PROMPT);
|
||||
await checkNotificationBothOrigins(uri.host, "test1.example.com");
|
||||
|
||||
SitePermissions.removeFromPrincipal(null, "geo", browser);
|
||||
PermissionTestUtils.remove(uri, "geo");
|
||||
});
|
||||
});
|
||||
|
||||
// If we are in unsafe permission delegation and the origin is explicitly
|
||||
// trusted in ancestor chain. Do not need prompt
|
||||
add_task(async function testExplicitlyAllowedInChain() {
|
||||
await BrowserTestUtils.withNewTab(CROSS_FRAME_PAGE, async function(browser) {
|
||||
// Persistent allow top level origin
|
||||
PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION);
|
||||
|
||||
const iframeAncestor = await SpecialPowers.spawn(browser, [], () => {
|
||||
return content.document.getElementById("frameAncestor").browsingContext;
|
||||
});
|
||||
|
||||
await checkGeolocation(
|
||||
iframeAncestor,
|
||||
"frameAllowsAll",
|
||||
PromptResult.ALLOW
|
||||
);
|
||||
|
||||
PermissionTestUtils.remove(uri, "geo");
|
||||
});
|
||||
});
|
|
@ -14,7 +14,7 @@ add_task(async function testNoPermissionPrompt() {
|
|||
{
|
||||
set: [
|
||||
["dom.security.featurePolicy.enabled", true],
|
||||
["permissions.delegation.enabled", true],
|
||||
["permissions.delegation.enable", true],
|
||||
["dom.vibrator.enabled", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true],
|
||||
|
|
|
@ -18,16 +18,6 @@ function requestPush() {
|
|||
});
|
||||
}
|
||||
|
||||
function requestGeo() {
|
||||
return navigator.geolocation.getCurrentPosition(() => {
|
||||
parent.postMessage("allow", "*");
|
||||
}, error => {
|
||||
// PERMISSION_DENIED = 1
|
||||
parent.postMessage(error.code == 1 ? "deny" : "allow", "*");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
window.onmessage = function(event) {
|
||||
switch (event.data) {
|
||||
case "push":
|
||||
|
@ -40,7 +30,7 @@ window.onmessage = function(event) {
|
|||
<body onkeydown="gKeyDowns++;" onkeypress="gKeyPresses++">
|
||||
<!-- This page could eventually request permissions from content
|
||||
and make sure that chrome responds appropriately -->
|
||||
<button id="geo" onclick="requestGeo()">Geolocation</button>
|
||||
<button id="geo" onclick="navigator.geolocation.getCurrentPosition(() => {})">Geolocation</button>
|
||||
<button id="desktop-notification" onclick="Notification.requestPermission()">Notifications</button>
|
||||
<button id="push" onclick="requestPush()">Push Notifications</button>
|
||||
<button id="camera" onclick="navigator.mediaDevices.getUserMedia({video: true, fake: true})">Camera</button>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Permissions Subframe Test</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="frameAncestor"
|
||||
src="https://test1.example.com/browser/browser/base/content/test/permissions/temporary_permissions_subframe.html"
|
||||
allow="geolocation 'src' https://example.org"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -5,7 +5,6 @@
|
|||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="frame" src="https://example.org/browser/browser/base/content/test/permissions/permissions.html" allow="geolocation"></iframe>
|
||||
<iframe id="frameAllowsAll" src="https://example.org/browser/browser/base/content/test/permissions/permissions.html" allow="geolocation *"></iframe>
|
||||
<iframe id="frame" src="https://example.org/browser/browser/base/content/test/permissions/permissions.html" allow="geolocation"/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,7 +3,6 @@ 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
|
||||
|
||||
[browser_devices_get_user_media.js]
|
||||
|
@ -14,7 +13,6 @@ skip-if = (os == "linux" && debug) # linux: bug 976544
|
|||
skip-if = debug # bug 1369731
|
||||
[browser_devices_get_user_media_in_xorigin_frame.js]
|
||||
skip-if = debug # bug 1369731
|
||||
[browser_devices_get_user_media_in_xorigin_frame_chain.js]
|
||||
[browser_devices_get_user_media_multi_process.js]
|
||||
skip-if = (debug && os == "win") # bug 1393761
|
||||
[browser_devices_get_user_media_paused.js]
|
||||
|
|
|
@ -1,175 +1,41 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
const permissionError =
|
||||
"error: NotAllowedError: The request is not allowed " +
|
||||
"by the user agent or the platform in the current context.";
|
||||
|
||||
const PromptResult = {
|
||||
ALLOW: "allow",
|
||||
DENY: "deny",
|
||||
PROMPT: "prompt",
|
||||
};
|
||||
|
||||
const Perms = Services.perms;
|
||||
|
||||
async function promptNoDelegate(aThirdPartyOrgin) {
|
||||
// Persistent allowed first party origin
|
||||
const uri = gBrowser.selectedBrowser.documentURI;
|
||||
PermissionTestUtils.add(uri, "microphone", Services.perms.ALLOW_ACTION);
|
||||
PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION);
|
||||
|
||||
// Check that we get a prompt.
|
||||
const observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
const promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
await promiseRequestDevice(true, true, "frame4");
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
// The 'Remember this decision' checkbox is hidden.
|
||||
const notification = PopupNotifications.panel.firstElementChild;
|
||||
const checkbox = notification.checkbox;
|
||||
ok(!!checkbox, "checkbox is present");
|
||||
ok(checkbox.hidden, "checkbox is not visible");
|
||||
ok(!checkbox.checked, "checkbox not checked");
|
||||
|
||||
// Check the label of the notification should be the first party
|
||||
is(
|
||||
PopupNotifications.getNotification("webRTC-shareDevices").options.name,
|
||||
uri.host,
|
||||
"Use first party's origin"
|
||||
);
|
||||
|
||||
// Check the secondName of the notification should be the third party
|
||||
is(
|
||||
PopupNotifications.getNotification("webRTC-shareDevices").options
|
||||
.secondName,
|
||||
aThirdPartyOrgin,
|
||||
"Use third party's origin as secondName"
|
||||
);
|
||||
|
||||
let indicator = promiseIndicatorWindow();
|
||||
let observerPromise1 = expectObserverCalled("getUserMedia:response:allow");
|
||||
let observerPromise2 = expectObserverCalled("recording-device-events");
|
||||
await promiseMessage("ok", () =>
|
||||
EventUtils.synthesizeMouseAtCenter(notification.button, {})
|
||||
);
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
Assert.deepEqual(
|
||||
await getMediaCaptureState(),
|
||||
{ audio: true, video: true },
|
||||
"expected camera and microphone to be shared"
|
||||
);
|
||||
await indicator;
|
||||
await checkSharingUI({ audio: true, video: true });
|
||||
|
||||
// Cleanup.
|
||||
await closeStream(false, "frame4");
|
||||
|
||||
PermissionTestUtils.remove(uri, "camera");
|
||||
PermissionTestUtils.remove(uri, "microphone");
|
||||
}
|
||||
|
||||
async function promptNoDelegateScreenSharing(aThirdPartyOrgin) {
|
||||
// Persistent allow screen sharing
|
||||
const uri = gBrowser.selectedBrowser.documentURI;
|
||||
PermissionTestUtils.add(uri, "screen", Services.perms.ALLOW_ACTION);
|
||||
|
||||
const observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
const promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
await promiseRequestDevice(false, true, "frame4", "screen");
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
checkDeviceSelectors(false, false, true);
|
||||
const notification = PopupNotifications.panel.firstElementChild;
|
||||
const iconclass = notification.getAttribute("iconclass");
|
||||
ok(iconclass.includes("screen-icon"), "panel using screen icon");
|
||||
|
||||
// The 'Remember this decision' checkbox is hidden.
|
||||
const checkbox = notification.checkbox;
|
||||
ok(!!checkbox, "checkbox is present");
|
||||
ok(checkbox.hidden, "checkbox is not visible");
|
||||
ok(!checkbox.checked, "checkbox not checked");
|
||||
|
||||
// Check the label of the notification should be the first party
|
||||
is(
|
||||
PopupNotifications.getNotification("webRTC-shareDevices").options.name,
|
||||
uri.host,
|
||||
"Use first party's origin"
|
||||
);
|
||||
|
||||
// Check the secondName of the notification should be the third party
|
||||
is(
|
||||
PopupNotifications.getNotification("webRTC-shareDevices").options
|
||||
.secondName,
|
||||
aThirdPartyOrgin,
|
||||
"Use third party's origin as secondName"
|
||||
);
|
||||
|
||||
const menulist = document.getElementById("webRTC-selectWindow-menulist");
|
||||
const count = menulist.itemCount;
|
||||
menulist.getItemAtIndex(count - 1).doCommand();
|
||||
ok(!notification.button.disabled, "Allow button is enabled");
|
||||
|
||||
const indicator = promiseIndicatorWindow();
|
||||
const observerPromise1 = expectObserverCalled("getUserMedia:response:allow");
|
||||
const observerPromise2 = expectObserverCalled("recording-device-events");
|
||||
await promiseMessage("ok", () =>
|
||||
EventUtils.synthesizeMouseAtCenter(notification.button, {})
|
||||
);
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
Assert.deepEqual(
|
||||
await getMediaCaptureState(),
|
||||
{ screen: "Screen" },
|
||||
"expected screen to be shared"
|
||||
);
|
||||
|
||||
await indicator;
|
||||
await checkSharingUI({ screen: "Screen" });
|
||||
await closeStream(false, "frame4");
|
||||
|
||||
PermissionTestUtils.remove(uri, "screen");
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
desc:
|
||||
"'Always Allow' enabled on third party pages, when origin is explicitly allowed",
|
||||
desc: "'Always Allow' disabled on third party pages",
|
||||
run: async function checkNoAlwaysOnThirdParty() {
|
||||
// Initially set both permissions to 'prompt'.
|
||||
const uri = gBrowser.selectedBrowser.documentURI;
|
||||
PermissionTestUtils.add(uri, "microphone", Services.perms.PROMPT_ACTION);
|
||||
PermissionTestUtils.add(uri, "camera", Services.perms.PROMPT_ACTION);
|
||||
// Initially set both permissions to 'allow'.
|
||||
let origin = "https://test1.example.com/";
|
||||
PermissionTestUtils.add(
|
||||
origin,
|
||||
"microphone",
|
||||
Services.perms.ALLOW_ACTION
|
||||
);
|
||||
PermissionTestUtils.add(origin, "camera", Services.perms.ALLOW_ACTION);
|
||||
|
||||
const observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
const promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
// Request devices and expect a prompt despite the saved 'Allow' permission,
|
||||
// because we're a third party.
|
||||
let observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
let promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
await promiseRequestDevice(true, true, "frame1");
|
||||
await promise;
|
||||
await observerPromise;
|
||||
checkDeviceSelectors(true, true);
|
||||
|
||||
// The 'Remember this decision' checkbox is visible.
|
||||
const notification = PopupNotifications.panel.firstElementChild;
|
||||
const checkbox = notification.checkbox;
|
||||
// Ensure that the 'Remember this decision' checkbox is absent.
|
||||
let notification = PopupNotifications.panel.firstElementChild;
|
||||
let checkbox = notification.checkbox;
|
||||
ok(!!checkbox, "checkbox is present");
|
||||
ok(!checkbox.hidden, "checkbox is visible");
|
||||
ok(checkbox.hidden, "checkbox is not visible");
|
||||
ok(!checkbox.checked, "checkbox not checked");
|
||||
|
||||
// Check the label of the notification should be the first party
|
||||
is(
|
||||
PopupNotifications.getNotification("webRTC-shareDevices").options.name,
|
||||
uri.host,
|
||||
"Use first party's origin"
|
||||
);
|
||||
|
||||
const indicator = promiseIndicatorWindow();
|
||||
const observerPromise1 = expectObserverCalled(
|
||||
let indicator = promiseIndicatorWindow();
|
||||
let observerPromise1 = expectObserverCalled(
|
||||
"getUserMedia:response:allow"
|
||||
);
|
||||
const observerPromise2 = expectObserverCalled("recording-device-events");
|
||||
let observerPromise2 = expectObserverCalled("recording-device-events");
|
||||
await promiseMessage("ok", () =>
|
||||
EventUtils.synthesizeMouseAtCenter(notification.button, {})
|
||||
);
|
||||
|
@ -185,39 +51,38 @@ var gTests = [
|
|||
|
||||
// Cleanup.
|
||||
await closeStream(false, "frame1");
|
||||
PermissionTestUtils.remove(uri, "camera");
|
||||
PermissionTestUtils.remove(uri, "microphone");
|
||||
PermissionTestUtils.remove(origin, "camera");
|
||||
PermissionTestUtils.remove(origin, "microphone");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"'Always Allow' disabled when sharing screen in third party iframes, when origin is explicitly allowed",
|
||||
desc: "'Always Allow' disabled when sharing screen in third party iframes",
|
||||
run: async function checkScreenSharing() {
|
||||
const observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
const promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
let observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
let promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
await promiseRequestDevice(false, true, "frame1", "screen");
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
checkDeviceSelectors(false, false, true);
|
||||
const notification = PopupNotifications.panel.firstElementChild;
|
||||
const iconclass = notification.getAttribute("iconclass");
|
||||
let notification = PopupNotifications.panel.firstElementChild;
|
||||
let iconclass = notification.getAttribute("iconclass");
|
||||
ok(iconclass.includes("screen-icon"), "panel using screen icon");
|
||||
|
||||
// The 'Remember this decision' checkbox is visible.
|
||||
const checkbox = notification.checkbox;
|
||||
// Ensure that the 'Remember this decision' checkbox is absent.
|
||||
let checkbox = notification.checkbox;
|
||||
ok(!!checkbox, "checkbox is present");
|
||||
ok(!checkbox.hidden, "checkbox is visible");
|
||||
ok(checkbox.hidden, "checkbox is not visible");
|
||||
ok(!checkbox.checked, "checkbox not checked");
|
||||
|
||||
const menulist = document.getElementById("webRTC-selectWindow-menulist");
|
||||
const count = menulist.itemCount;
|
||||
let menulist = document.getElementById("webRTC-selectWindow-menulist");
|
||||
let count = menulist.itemCount;
|
||||
ok(
|
||||
count >= 4,
|
||||
"There should be the 'Select Window or Screen' item, a separator and at least one window and one screen"
|
||||
);
|
||||
|
||||
const noWindowOrScreenItem = menulist.getItemAtIndex(0);
|
||||
let noWindowOrScreenItem = menulist.getItemAtIndex(0);
|
||||
ok(
|
||||
noWindowOrScreenItem.hasAttribute("selected"),
|
||||
"the 'Select Window or Screen' item is selected"
|
||||
|
@ -241,11 +106,11 @@ var gTests = [
|
|||
menulist.getItemAtIndex(count - 1).doCommand();
|
||||
ok(!notification.button.disabled, "Allow button is enabled");
|
||||
|
||||
const indicator = promiseIndicatorWindow();
|
||||
const observerPromise1 = expectObserverCalled(
|
||||
let indicator = promiseIndicatorWindow();
|
||||
let observerPromise1 = expectObserverCalled(
|
||||
"getUserMedia:response:allow"
|
||||
);
|
||||
const observerPromise2 = expectObserverCalled("recording-device-events");
|
||||
let observerPromise2 = expectObserverCalled("recording-device-events");
|
||||
await promiseMessage("ok", () =>
|
||||
EventUtils.synthesizeMouseAtCenter(notification.button, {})
|
||||
);
|
||||
|
@ -262,325 +127,9 @@ var gTests = [
|
|||
await closeStream(false, "frame1");
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
desc: "getUserMedia use persistent permissions from first party",
|
||||
run: async function checkUsePersistentPermissionsFirstParty() {
|
||||
async function checkPersistentPermission(
|
||||
aPermission,
|
||||
aRequestType,
|
||||
aIframeId,
|
||||
aExpect
|
||||
) {
|
||||
info(
|
||||
`Test persistent permission ${aPermission} type ${aRequestType} expect ${aExpect}`
|
||||
);
|
||||
const uri = gBrowser.selectedBrowser.documentURI;
|
||||
// Persistent allow/deny for first party uri
|
||||
PermissionTestUtils.add(uri, aRequestType, aPermission);
|
||||
|
||||
let audio = aRequestType == "microphone";
|
||||
let video = aRequestType == "camera";
|
||||
const screen = aRequestType == "screen" ? "screen" : undefined;
|
||||
if (screen) {
|
||||
audio = false;
|
||||
video = true;
|
||||
}
|
||||
if (aExpect == PromptResult.PROMPT) {
|
||||
// Check that we get a prompt.
|
||||
const observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
const observerPromise1 = expectObserverCalled(
|
||||
"getUserMedia:response:deny"
|
||||
);
|
||||
const observerPromise2 = expectObserverCalled(
|
||||
"recording-window-ended"
|
||||
);
|
||||
const promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
await promiseRequestDevice(audio, video, aIframeId, screen);
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
// Check the label of the notification should be the first party
|
||||
is(
|
||||
PopupNotifications.getNotification("webRTC-shareDevices").options
|
||||
.name,
|
||||
uri.host,
|
||||
"Use first party's origin"
|
||||
);
|
||||
|
||||
// Deny the request to cleanup...
|
||||
await promiseMessage(permissionError, () => {
|
||||
activateSecondaryAction(kActionDeny);
|
||||
});
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
SitePermissions.removeFromPrincipal(null, aRequestType, browser);
|
||||
} else if (aExpect == PromptResult.ALLOW) {
|
||||
const observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
const observerPromise1 = expectObserverCalled(
|
||||
"getUserMedia:response:allow"
|
||||
);
|
||||
const observerPromise2 = expectObserverCalled(
|
||||
"recording-device-events"
|
||||
);
|
||||
const promise = promiseMessage("ok");
|
||||
await promiseRequestDevice(audio, video, aIframeId, screen);
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
await promiseNoPopupNotification("webRTC-shareDevices");
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
|
||||
let expected = {};
|
||||
if (audio) {
|
||||
expected.audio = audio;
|
||||
}
|
||||
if (video) {
|
||||
expected.video = video;
|
||||
}
|
||||
|
||||
Assert.deepEqual(
|
||||
await getMediaCaptureState(),
|
||||
expected,
|
||||
"expected " + Object.keys(expected).join(" and ") + " to be shared"
|
||||
);
|
||||
|
||||
await closeStream(false, "frame1");
|
||||
} else if (aExpect == PromptResult.DENY) {
|
||||
const observerPromise = expectObserverCalled(
|
||||
"recording-window-ended"
|
||||
);
|
||||
const promise = promiseMessage(permissionError);
|
||||
await promiseRequestDevice(audio, video, aIframeId, screen);
|
||||
await promise;
|
||||
await observerPromise;
|
||||
}
|
||||
|
||||
PermissionTestUtils.remove(uri, aRequestType);
|
||||
}
|
||||
|
||||
await checkPersistentPermission(
|
||||
Perms.PROMPT_ACTION,
|
||||
"camera",
|
||||
"frame1",
|
||||
PromptResult.PROMPT
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.DENY_ACTION,
|
||||
"camera",
|
||||
"frame1",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.ALLOW_ACTION,
|
||||
"camera",
|
||||
"frame1",
|
||||
PromptResult.ALLOW
|
||||
);
|
||||
|
||||
await checkPersistentPermission(
|
||||
Perms.PROMPT_ACTION,
|
||||
"microphone",
|
||||
"frame1",
|
||||
PromptResult.PROMPT
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.DENY_ACTION,
|
||||
"microphone",
|
||||
"frame1",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.ALLOW_ACTION,
|
||||
"microphone",
|
||||
"frame1",
|
||||
PromptResult.ALLOW
|
||||
);
|
||||
|
||||
await checkPersistentPermission(
|
||||
Perms.PROMPT_ACTION,
|
||||
"screen",
|
||||
"frame1",
|
||||
PromptResult.PROMPT
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.DENY_ACTION,
|
||||
"screen",
|
||||
"frame1",
|
||||
PromptResult.DENY
|
||||
);
|
||||
// Always prompt screen sharing
|
||||
await checkPersistentPermission(
|
||||
Perms.ALLOW_ACTION,
|
||||
"screen",
|
||||
"frame1",
|
||||
PromptResult.PROMPT
|
||||
);
|
||||
|
||||
// Denied by default if allow is not defined
|
||||
await checkPersistentPermission(
|
||||
Perms.PROMPT_ACTION,
|
||||
"camera",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.DENY_ACTION,
|
||||
"camera",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.ALLOW_ACTION,
|
||||
"camera",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
|
||||
await checkPersistentPermission(
|
||||
Perms.PROMPT_ACTION,
|
||||
"microphone",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.DENY_ACTION,
|
||||
"microphone",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.ALLOW_ACTION,
|
||||
"microphone",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
|
||||
await checkPersistentPermission(
|
||||
Perms.PROMPT_ACTION,
|
||||
"screen",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.DENY_ACTION,
|
||||
"screen",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
await checkPersistentPermission(
|
||||
Perms.ALLOW_ACTION,
|
||||
"screen",
|
||||
"frame3",
|
||||
PromptResult.DENY
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
desc: "getUserMedia use temporary blocked permissions from first party",
|
||||
run: async function checkUseTempPermissionsBlockFirstParty() {
|
||||
async function checkTempPermission(aRequestType) {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
let observerPromise1 = expectObserverCalled(
|
||||
"getUserMedia:response:deny"
|
||||
);
|
||||
let observerPromise2 = expectObserverCalled("recording-window-ended");
|
||||
let promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
let audio = aRequestType == "microphone";
|
||||
let video = aRequestType == "camera";
|
||||
const screen = aRequestType == "screen" ? "screen" : undefined;
|
||||
if (screen) {
|
||||
audio = false;
|
||||
video = true;
|
||||
}
|
||||
|
||||
await promiseRequestDevice(audio, video, null, screen);
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
// Temporarily grant/deny from top level
|
||||
// Only need to check allow and deny temporary permissions
|
||||
await promiseMessage(permissionError, () => {
|
||||
activateSecondaryAction(kActionDeny);
|
||||
});
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
await checkNotSharing();
|
||||
|
||||
observerPromise = expectObserverCalled("getUserMedia:request");
|
||||
observerPromise1 = expectObserverCalled("getUserMedia:response:deny");
|
||||
observerPromise2 = expectObserverCalled("recording-window-ended");
|
||||
promise = promiseMessage(permissionError);
|
||||
await promiseRequestDevice(audio, video, "frame1", screen);
|
||||
await promise;
|
||||
|
||||
await observerPromise;
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
|
||||
SitePermissions.removeFromPrincipal(null, aRequestType, browser);
|
||||
}
|
||||
|
||||
// At the moment we only save temporary deny
|
||||
await checkTempPermission("camera");
|
||||
await checkTempPermission("microphone");
|
||||
await checkTempPermission("screen");
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
desc:
|
||||
"Prompt and display both first party and third party origin in maybe unsafe permission delegation",
|
||||
run: async function checkPromptNoDelegate() {
|
||||
await promptNoDelegate("test1.example.com");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Prompt and display both first party and third party origin when sharing screen in unsafe permission delegation",
|
||||
run: async function checkPromptNoDelegateScreenSharing() {
|
||||
await promptNoDelegateScreenSharing("test1.example.com");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Change location, prompt and display both first party and third party origin in maybe unsafe permission delegation",
|
||||
run: async function checkPromptNoDelegateChangeLoxation() {
|
||||
await promiseChangeLocationFrame(
|
||||
"frame4",
|
||||
"https://test2.example.com/browser/browser/base/content/test/webrtc/get_user_media.html"
|
||||
);
|
||||
await promptNoDelegate("test2.example.com");
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
desc:
|
||||
"Change location, prompt and display both first party and third party origin when sharing screen in unsafe permission delegation",
|
||||
run: async function checkPromptNoDelegateScreenSharingChangeLocation() {
|
||||
await promiseChangeLocationFrame(
|
||||
"frame4",
|
||||
"https://test2.example.com/browser/browser/base/content/test/webrtc/get_user_media.html"
|
||||
);
|
||||
await promptNoDelegateScreenSharing("test2.example.com");
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["permissions.delegation.enabled", true],
|
||||
["dom.security.featurePolicy.enabled", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
await runTests(gTests, {
|
||||
relativeURI: "get_user_media_in_xorigin_frame.html",
|
||||
});
|
||||
|
|
|
@ -1,253 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
const permissionError =
|
||||
"error: NotAllowedError: The request is not allowed " +
|
||||
"by the user agent or the platform in the current context.";
|
||||
|
||||
const PromptResult = {
|
||||
ALLOW: "allow",
|
||||
DENY: "deny",
|
||||
PROMPT: "prompt",
|
||||
};
|
||||
|
||||
const Perms = Services.perms;
|
||||
|
||||
function expectObserverCalledAncestor(aTopic, browsingContext) {
|
||||
if (!gMultiProcessBrowser) {
|
||||
return expectObserverCalledInProcess(aTopic);
|
||||
}
|
||||
|
||||
return BrowserTestUtils.contentTopicObserved(browsingContext, aTopic);
|
||||
}
|
||||
|
||||
function enableObserverVerificationAncestor(browsingContext) {
|
||||
// Skip these checks in single process mode as it isn't worth implementing it.
|
||||
if (!gMultiProcessBrowser) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return BrowserTestUtils.startObservingTopics(browsingContext, observerTopics);
|
||||
}
|
||||
|
||||
function disableObserverVerificationAncestor(browsingContextt) {
|
||||
if (!gMultiProcessBrowser) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return BrowserTestUtils.stopObservingTopics(
|
||||
browsingContextt,
|
||||
observerTopics
|
||||
).catch(reason => {
|
||||
ok(false, "Failed " + reason);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseRequestDeviceAncestor(
|
||||
aRequestAudio,
|
||||
aRequestVideo,
|
||||
aType,
|
||||
aBrowser,
|
||||
aBadDevice = false
|
||||
) {
|
||||
info("requesting devices");
|
||||
return SpecialPowers.spawn(
|
||||
aBrowser,
|
||||
[{ aRequestAudio, aRequestVideo, aType, aBadDevice }],
|
||||
async function(args) {
|
||||
let global = content.wrappedJSObject.document.getElementById("frame4")
|
||||
.contentWindow;
|
||||
global.requestDevice(
|
||||
args.aRequestAudio,
|
||||
args.aRequestVideo,
|
||||
args.aType,
|
||||
args.aBadDevice
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function closeStreamAncestor(browser) {
|
||||
let observerPromises = [];
|
||||
observerPromises.push(
|
||||
expectObserverCalledAncestor("recording-device-events", browser)
|
||||
);
|
||||
observerPromises.push(
|
||||
expectObserverCalledAncestor("recording-window-ended", browser)
|
||||
);
|
||||
|
||||
info("closing the stream");
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let global = content.wrappedJSObject.document.getElementById("frame4")
|
||||
.contentWindow;
|
||||
global.closeStream();
|
||||
});
|
||||
|
||||
await Promise.all(observerPromises);
|
||||
|
||||
await assertWebRTCIndicatorStatus(null);
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
desc:
|
||||
"getUserMedia use persistent permissions from first party if third party is explicitly trusted",
|
||||
skipObserverVerification: true,
|
||||
run: async function checkPermissionsAncestorChain() {
|
||||
async function checkPermission(aPermission, aRequestType, aExpect) {
|
||||
info(
|
||||
`Test persistent permission ${aPermission} type ${aRequestType} expect ${aExpect}`
|
||||
);
|
||||
const uri = gBrowser.selectedBrowser.documentURI;
|
||||
// Persistent allow/deny for first party uri
|
||||
PermissionTestUtils.add(uri, aRequestType, aPermission);
|
||||
|
||||
let audio = aRequestType == "microphone";
|
||||
let video = aRequestType == "camera";
|
||||
const screen = aRequestType == "screen" ? "screen" : undefined;
|
||||
if (screen) {
|
||||
audio = false;
|
||||
video = true;
|
||||
}
|
||||
const iframeAncestor = await SpecialPowers.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
[],
|
||||
() => {
|
||||
return content.document.getElementById("frameAncestor")
|
||||
.browsingContext;
|
||||
}
|
||||
);
|
||||
|
||||
if (aExpect == PromptResult.PROMPT) {
|
||||
// Check that we get a prompt.
|
||||
const observerPromise = expectObserverCalledAncestor(
|
||||
"getUserMedia:request",
|
||||
iframeAncestor
|
||||
);
|
||||
const promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
|
||||
await promiseRequestDeviceAncestor(
|
||||
audio,
|
||||
video,
|
||||
screen,
|
||||
iframeAncestor
|
||||
);
|
||||
await promise;
|
||||
await observerPromise;
|
||||
|
||||
// Check the label of the notification should be the first party
|
||||
is(
|
||||
PopupNotifications.getNotification("webRTC-shareDevices").options
|
||||
.name,
|
||||
uri.host,
|
||||
"Use first party's origin"
|
||||
);
|
||||
const observerPromise1 = expectObserverCalledAncestor(
|
||||
"getUserMedia:response:deny",
|
||||
iframeAncestor
|
||||
);
|
||||
const observerPromise2 = expectObserverCalledAncestor(
|
||||
"recording-window-ended",
|
||||
iframeAncestor
|
||||
);
|
||||
// Deny the request to cleanup...
|
||||
activateSecondaryAction(kActionDeny);
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
SitePermissions.removeFromPrincipal(null, aRequestType, browser);
|
||||
} else if (aExpect == PromptResult.ALLOW) {
|
||||
const observerPromise = expectObserverCalledAncestor(
|
||||
"getUserMedia:request",
|
||||
iframeAncestor
|
||||
);
|
||||
const observerPromise1 = expectObserverCalledAncestor(
|
||||
"getUserMedia:response:allow",
|
||||
iframeAncestor
|
||||
);
|
||||
const observerPromise2 = expectObserverCalledAncestor(
|
||||
"recording-device-events",
|
||||
iframeAncestor
|
||||
);
|
||||
await promiseRequestDeviceAncestor(
|
||||
audio,
|
||||
video,
|
||||
screen,
|
||||
iframeAncestor
|
||||
);
|
||||
await observerPromise;
|
||||
|
||||
await promiseNoPopupNotification("webRTC-shareDevices");
|
||||
await observerPromise1;
|
||||
await observerPromise2;
|
||||
|
||||
let expected = {};
|
||||
if (audio) {
|
||||
expected.audio = audio;
|
||||
}
|
||||
if (video) {
|
||||
expected.video = video;
|
||||
}
|
||||
|
||||
Assert.deepEqual(
|
||||
await getMediaCaptureState(),
|
||||
expected,
|
||||
"expected " + Object.keys(expected).join(" and ") + " to be shared"
|
||||
);
|
||||
|
||||
await closeStreamAncestor(iframeAncestor);
|
||||
} else if (aExpect == PromptResult.DENY) {
|
||||
const observerPromise = expectObserverCalledAncestor(
|
||||
"recording-window-ended",
|
||||
iframeAncestor
|
||||
);
|
||||
await promiseRequestDeviceAncestor(
|
||||
audio,
|
||||
video,
|
||||
screen,
|
||||
iframeAncestor
|
||||
);
|
||||
await observerPromise;
|
||||
}
|
||||
|
||||
PermissionTestUtils.remove(uri, aRequestType);
|
||||
}
|
||||
|
||||
await checkPermission(Perms.PROMPT_ACTION, "camera", PromptResult.PROMPT);
|
||||
await checkPermission(Perms.DENY_ACTION, "camera", PromptResult.DENY);
|
||||
await checkPermission(Perms.ALLOW_ACTION, "camera", PromptResult.ALLOW);
|
||||
|
||||
await checkPermission(
|
||||
Perms.PROMPT_ACTION,
|
||||
"microphone",
|
||||
PromptResult.PROMPT
|
||||
);
|
||||
await checkPermission(Perms.DENY_ACTION, "microphone", PromptResult.DENY);
|
||||
await checkPermission(
|
||||
Perms.ALLOW_ACTION,
|
||||
"microphone",
|
||||
PromptResult.ALLOW
|
||||
);
|
||||
|
||||
await checkPermission(Perms.PROMPT_ACTION, "screen", PromptResult.PROMPT);
|
||||
await checkPermission(Perms.DENY_ACTION, "screen", PromptResult.DENY);
|
||||
// Always prompt screen sharing
|
||||
await checkPermission(Perms.ALLOW_ACTION, "screen", PromptResult.PROMPT);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["permissions.delegation.enabled", true],
|
||||
["dom.security.featurePolicy.enabled", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
await runTests(gTests, {
|
||||
relativeURI: "get_user_media_in_xorigin_frame_ancestor.html",
|
||||
});
|
||||
});
|
|
@ -20,7 +20,7 @@ try {
|
|||
function message(m) {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
document.getElementById("message").innerHTML = m;
|
||||
parent.postMessage(m, "*");
|
||||
window.parent.postMessage(m, "*");
|
||||
}
|
||||
|
||||
var gStreams = [];
|
||||
|
@ -51,7 +51,7 @@ function requestDevice(aAudio, aVideo, aShare, aBadDevice = false) {
|
|||
opts.fake = true;
|
||||
}
|
||||
|
||||
navigator.mediaDevices.getUserMedia(opts)
|
||||
window.navigator.mediaDevices.getUserMedia(opts)
|
||||
.then(stream => {
|
||||
gStreams.push(stream);
|
||||
message("ok");
|
||||
|
|
|
@ -57,7 +57,5 @@ function closeStream() {
|
|||
</script>
|
||||
<iframe id="frame1" allow="camera;microphone;display-capture" src="https://test1.example.com/browser/browser/base/content/test/webrtc/get_user_media.html"></iframe>
|
||||
<iframe id="frame2" allow="camera;microphone" src="https://test1.example.com/browser/browser/base/content/test/webrtc/get_user_media.html"></iframe>
|
||||
<iframe id="frame3" src="https://test1.example.com/browser/browser/base/content/test/webrtc/get_user_media.html"></iframe>
|
||||
<iframe id="frame4" allow="camera *;microphone *;display-capture *" src="https://test1.example.com/browser/browser/base/content/test/webrtc/get_user_media.html"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Permissions Test</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="frameAncestor"
|
||||
src="https://test2.example.com/browser/browser/base/content/test/webrtc/get_user_media_in_xorigin_frame.html"
|
||||
allow="camera 'src' https://test1.example.com;microphone 'src' https://test1.example.com;display-capture 'src' https://test1.example.com"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -665,29 +665,6 @@ function promiseReloadFrame(aFrameId) {
|
|||
);
|
||||
}
|
||||
|
||||
function promiseChangeLocationFrame(aFrameId, aNewLocation) {
|
||||
return SpecialPowers.spawn(
|
||||
gBrowser.selectedBrowser.browsingContext,
|
||||
[{ aFrameId, aNewLocation }],
|
||||
async function(args) {
|
||||
let frame = content.wrappedJSObject.document.getElementById(
|
||||
args.aFrameId
|
||||
);
|
||||
return new Promise(resolve => {
|
||||
function listener() {
|
||||
frame.removeEventListener("load", listener, true);
|
||||
resolve();
|
||||
}
|
||||
frame.addEventListener("load", listener, true);
|
||||
|
||||
content.wrappedJSObject.document.getElementById(
|
||||
args.aFrameId
|
||||
).contentWindow.location = args.aNewLocation;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function openNewTestTab(leaf = "get_user_media.html") {
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace(
|
||||
|
|
|
@ -623,9 +623,6 @@ geolocation.dontAllowLocation=Don’t Allow
|
|||
geolocation.dontAllowLocation.accesskey=n
|
||||
geolocation.shareWithSite3=Will you allow %S to access your location?
|
||||
geolocation.shareWithFile3=Will you allow this local file to access your location?
|
||||
# LOCALIZATION NOTE(geolocation.shareWithSiteUnsafeDelegation):
|
||||
# %1$S is the first party origin, %2$S is the third party origin.
|
||||
geolocation.shareWithSiteUnsafeDelegation=Will you allow %1$S to give %2$S permission to access your location?
|
||||
geolocation.remember=Remember this decision
|
||||
|
||||
# Persistent storage UI
|
||||
|
@ -729,24 +726,6 @@ getUserMedia.shareCameraAndAudioCapture2.message = Will you allow %S to use your
|
|||
getUserMedia.shareScreenAndMicrophone3.message = Will you allow %S to use your microphone and see your screen?
|
||||
getUserMedia.shareScreenAndAudioCapture3.message = Will you allow %S to listen to this tab’s audio and see your screen?
|
||||
getUserMedia.shareAudioCapture2.message = Will you allow %S to listen to this tab’s audio?
|
||||
|
||||
# LOCALIZATION NOTE (getUserMedia.shareCameraUnsafeDelegation.message,
|
||||
# getUserMedia.shareMicrophoneUnsafeDelegation.message,
|
||||
# getUserMedia.shareScreenUnsafeDelegation.message,
|
||||
# getUserMedia.shareCameraAndMicrophoneUnsafeDelegation.message,
|
||||
# getUserMedia.shareCameraAndAudioCaptureUnsafeDelegation.message,
|
||||
# getUserMedia.shareScreenAndMicrophoneUnsafeDelegation.message,
|
||||
# getUserMedia.shareScreenAndAudioCaptureUnsafeDelegation.message,
|
||||
# %1$S is the first party origin.
|
||||
# %2$S is the third party origin.
|
||||
getUserMedia.shareCameraUnsafeDelegation.message = Will you allow %1$S to give %2$S access to your camera?
|
||||
getUserMedia.shareMicrophoneUnsafeDelegations.message = Will you allow %1$S to give %2$S access to your microphone?
|
||||
getUserMedia.shareScreenUnsafeDelegation.message = Will you allow %1$S to give %2$S permission to see your screen?
|
||||
getUserMedia.shareCameraAndMicrophoneUnsafeDelegation.message = Will you allow %1$S to give %2$S access to your camera and microphone?
|
||||
getUserMedia.shareCameraAndAudioCaptureUnsafeDelegation.message = Will you allow %1$S to give %2$S access to your camera and listen to this tab’s audio?
|
||||
getUserMedia.shareScreenAndMicrophoneUnsafeDelegation.message = Will you allow %1$S to give %2$S access to your microphone and see your screen?
|
||||
getUserMedia.shareScreenAndAudioCaptureUnsafeDelegation.message = Will you allow %1$S to give %2$S permission to listen to this tab’s audio and see your screen?
|
||||
|
||||
# LOCALIZATION NOTE (getUserMedia.shareScreenWarning.message): NB: inserted via innerHTML, so please don't use <, > or & in this string.
|
||||
# %S will be the 'learn more' link
|
||||
getUserMedia.shareScreenWarning.message = Only share screens with sites you trust. Sharing can allow deceptive sites to browse as you and steal your private data. %S
|
||||
|
|
|
@ -149,11 +149,17 @@ var PermissionPromptPrototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Indicates the type of the permission request from content. This type might
|
||||
* be different from the permission key used in the permissions database.
|
||||
* Provides the preferred name to use in the permission popups,
|
||||
* based on the principal URI (the URI.hostPort for any URI scheme
|
||||
* besides the moz-extension one which should default to the
|
||||
* extension name).
|
||||
*/
|
||||
get type() {
|
||||
return undefined;
|
||||
get principalName() {
|
||||
if (this.principal.addonPolicy) {
|
||||
return this.principal.addonPolicy.name;
|
||||
}
|
||||
|
||||
return this.principal.URI.hostPort;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -269,20 +275,6 @@ var PermissionPromptPrototype = {
|
|||
throw new Error("Not implemented.");
|
||||
},
|
||||
|
||||
/**
|
||||
* Provides the preferred name to use in the permission popups,
|
||||
* based on the principal URI (the URI.hostPort for any URI scheme
|
||||
* besides the moz-extension one which should default to the
|
||||
* extension name).
|
||||
*/
|
||||
getPrincipalName(principal = this.principal) {
|
||||
if (principal.addonPolicy) {
|
||||
return principal.addonPolicy.name;
|
||||
}
|
||||
|
||||
return principal.URI.hostPort;
|
||||
},
|
||||
|
||||
/**
|
||||
* This will be called if the request is to be cancelled.
|
||||
*
|
||||
|
@ -421,10 +413,7 @@ var PermissionPromptPrototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
state == SitePermissions.ALLOW &&
|
||||
!this.request.maybeUnsafePermissionDelegate
|
||||
) {
|
||||
if (state == SitePermissions.ALLOW) {
|
||||
this.allow();
|
||||
return;
|
||||
}
|
||||
|
@ -722,8 +711,7 @@ var PermissionPromptForRequestPrototype = {
|
|||
},
|
||||
|
||||
get principal() {
|
||||
let request = this.request.QueryInterface(Ci.nsIContentPermissionRequest);
|
||||
return request.getDelegatePrincipal(this.type);
|
||||
return this.request.principal;
|
||||
},
|
||||
|
||||
cancel() {
|
||||
|
@ -751,10 +739,6 @@ function GeolocationPermissionPrompt(request) {
|
|||
GeolocationPermissionPrompt.prototype = {
|
||||
__proto__: PermissionPromptForRequestPrototype,
|
||||
|
||||
get type() {
|
||||
return "geo";
|
||||
},
|
||||
|
||||
get permissionKey() {
|
||||
return "geo";
|
||||
},
|
||||
|
@ -768,7 +752,7 @@ GeolocationPermissionPrompt.prototype = {
|
|||
let options = {
|
||||
learnMoreURL: Services.urlFormatter.formatURLPref(pref),
|
||||
displayURI: false,
|
||||
name: this.getPrincipalName(),
|
||||
name: this.principalName,
|
||||
};
|
||||
|
||||
if (this.principal.schemeIs("file")) {
|
||||
|
@ -780,12 +764,6 @@ GeolocationPermissionPrompt.prototype = {
|
|||
};
|
||||
}
|
||||
|
||||
if (this.request.maybeUnsafePermissionDelegate) {
|
||||
// Second name should be the third party origin
|
||||
options.secondName = this.getPrincipalName(this.request.principal);
|
||||
options.checkbox = { show: false };
|
||||
}
|
||||
|
||||
if (options.checkbox.show) {
|
||||
options.checkbox.label = gBrowserBundle.GetStringFromName(
|
||||
"geolocation.remember"
|
||||
|
@ -808,13 +786,6 @@ GeolocationPermissionPrompt.prototype = {
|
|||
return gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
|
||||
}
|
||||
|
||||
if (this.request.maybeUnsafePermissionDelegate) {
|
||||
return gBrowserBundle.formatStringFromName(
|
||||
"geolocation.shareWithSiteUnsafeDelegation",
|
||||
["<>", "{}"]
|
||||
);
|
||||
}
|
||||
|
||||
return gBrowserBundle.formatStringFromName("geolocation.shareWithSite3", [
|
||||
"<>",
|
||||
]);
|
||||
|
@ -917,10 +888,6 @@ function DesktopNotificationPermissionPrompt(request) {
|
|||
DesktopNotificationPermissionPrompt.prototype = {
|
||||
__proto__: PermissionPromptForRequestPrototype,
|
||||
|
||||
get type() {
|
||||
return "desktop-notification";
|
||||
},
|
||||
|
||||
get permissionKey() {
|
||||
return "desktop-notification";
|
||||
},
|
||||
|
@ -936,7 +903,7 @@ DesktopNotificationPermissionPrompt.prototype = {
|
|||
return {
|
||||
learnMoreURL,
|
||||
displayURI: false,
|
||||
name: this.getPrincipalName(),
|
||||
name: this.principalName,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -1024,10 +991,6 @@ function PersistentStoragePermissionPrompt(request) {
|
|||
PersistentStoragePermissionPrompt.prototype = {
|
||||
__proto__: PermissionPromptForRequestPrototype,
|
||||
|
||||
get type() {
|
||||
return "persistent-storage";
|
||||
},
|
||||
|
||||
get permissionKey() {
|
||||
return "persistent-storage";
|
||||
},
|
||||
|
@ -1039,7 +1002,7 @@ PersistentStoragePermissionPrompt.prototype = {
|
|||
return {
|
||||
learnMoreURL,
|
||||
displayURI: false,
|
||||
name: this.getPrincipalName(),
|
||||
name: this.principalName,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -1116,10 +1079,6 @@ function MIDIPermissionPrompt(request) {
|
|||
MIDIPermissionPrompt.prototype = {
|
||||
__proto__: PermissionPromptForRequestPrototype,
|
||||
|
||||
get type() {
|
||||
return "midi";
|
||||
},
|
||||
|
||||
get permissionKey() {
|
||||
return this.permName;
|
||||
},
|
||||
|
@ -1128,7 +1087,7 @@ MIDIPermissionPrompt.prototype = {
|
|||
// TODO (bug 1433235) We need a security/permissions explanation URL for this
|
||||
let options = {
|
||||
displayURI: false,
|
||||
name: this.getPrincipalName(),
|
||||
name: this.principalName,
|
||||
};
|
||||
|
||||
if (this.principal.schemeIs("file")) {
|
||||
|
@ -1212,10 +1171,6 @@ StorageAccessPermissionPrompt.prototype = {
|
|||
return false;
|
||||
},
|
||||
|
||||
get type() {
|
||||
return "storage-access";
|
||||
},
|
||||
|
||||
get permissionKey() {
|
||||
// Make sure this name is unique per each third-party tracker
|
||||
return "storage-access-" + this.principal.origin;
|
||||
|
|
|
@ -85,14 +85,13 @@ function makeMockPermissionRequest(browser) {
|
|||
};
|
||||
let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
types.appendElement(type);
|
||||
let principal = browser.contentPrincipal;
|
||||
let result = {
|
||||
types,
|
||||
documentDOMContentLoadedTimestamp: 0,
|
||||
isHandlingUserInput: false,
|
||||
userHadInteractedWithDocument: false,
|
||||
principal,
|
||||
topLevelPrincipal: principal,
|
||||
principal: browser.contentPrincipal,
|
||||
topLevelPrincipal: browser.contentPrincipal,
|
||||
requester: null,
|
||||
_cancelled: false,
|
||||
cancel() {
|
||||
|
@ -102,9 +101,6 @@ function makeMockPermissionRequest(browser) {
|
|||
allow() {
|
||||
this._allowed = true;
|
||||
},
|
||||
getDelegatePrincipal(aType) {
|
||||
return principal;
|
||||
},
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionRequest]),
|
||||
};
|
||||
|
||||
|
|
|
@ -529,7 +529,7 @@ function checkRequestAllowed(aRequest, aPrincipal, aBrowser) {
|
|||
if (videoDevices.length && sharingScreen) {
|
||||
camAllowed = false;
|
||||
}
|
||||
if (aRequest.isThirdPartyOrigin && !aRequest.shouldDelegatePermission) {
|
||||
if (aRequest.isThirdPartyOrigin) {
|
||||
camAllowed = false;
|
||||
micAllowed = false;
|
||||
}
|
||||
|
@ -643,10 +643,7 @@ function prompt(aBrowser, aRequest) {
|
|||
// 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 (
|
||||
aRequest.secondOrigin ||
|
||||
!checkRequestAllowed(aRequest, principal, aBrowser)
|
||||
) {
|
||||
if (!checkRequestAllowed(aRequest, principal, aBrowser)) {
|
||||
denyRequest(aBrowser, aRequest);
|
||||
}
|
||||
return;
|
||||
|
@ -683,39 +680,20 @@ function prompt(aBrowser, aRequest) {
|
|||
// "includes()". This allows the rotation of string identifiers. We list the
|
||||
// full identifiers here so they can be cross-referenced more easily.
|
||||
let joinedRequestTypes = requestTypes.join("And");
|
||||
let requestMessages;
|
||||
if (aRequest.secondOrigin) {
|
||||
requestMessages = [
|
||||
// Individual request types first.
|
||||
"getUserMedia.shareCameraUnsafeDelegation.message",
|
||||
"getUserMedia.shareMicrophoneUnsafeDelegation.message",
|
||||
"getUserMedia.shareScreenUnsafeDelegation.message",
|
||||
"getUserMedia.shareAudioCaptureUnsafeDelegation.message",
|
||||
// Combinations of the above request types last.
|
||||
"getUserMedia.shareCameraAndMicrophoneUnsafeDelegation.message",
|
||||
"getUserMedia.shareCameraAndAudioCaptureUnsafeDelegation.message",
|
||||
"getUserMedia.shareScreenAndMicrophoneUnsafeDelegation.message",
|
||||
"getUserMedia.shareScreenAndAudioCaptureUnsafeDelegation.message",
|
||||
];
|
||||
} else {
|
||||
requestMessages = [
|
||||
// Individual request types first.
|
||||
"getUserMedia.shareCamera2.message",
|
||||
"getUserMedia.shareMicrophone2.message",
|
||||
"getUserMedia.shareScreen3.message",
|
||||
"getUserMedia.shareAudioCapture2.message",
|
||||
// Combinations of the above request types last.
|
||||
"getUserMedia.shareCameraAndMicrophone2.message",
|
||||
"getUserMedia.shareCameraAndAudioCapture2.me ssage",
|
||||
"getUserMedia.shareScreenAndMicrophone3.message",
|
||||
"getUserMedia.shareScreenAndAudioCapture3.message",
|
||||
];
|
||||
}
|
||||
let stringId = [
|
||||
// Individual request types first.
|
||||
"getUserMedia.shareCamera2.message",
|
||||
"getUserMedia.shareMicrophone2.message",
|
||||
"getUserMedia.shareScreen3.message",
|
||||
"getUserMedia.shareAudioCapture2.message",
|
||||
// Combinations of the above request types last.
|
||||
"getUserMedia.shareCameraAndMicrophone2.message",
|
||||
"getUserMedia.shareCameraAndAudioCapture2.message",
|
||||
"getUserMedia.shareScreenAndMicrophone3.message",
|
||||
"getUserMedia.shareScreenAndAudioCapture3.message",
|
||||
].find(id => id.includes(joinedRequestTypes));
|
||||
|
||||
let stringId = requestMessages.find(id => id.includes(joinedRequestTypes));
|
||||
let message = aRequest.secondOrigin
|
||||
? stringBundle.getFormattedString(stringId, ["<>", "{}"])
|
||||
: stringBundle.getFormattedString(stringId, ["<>"]);
|
||||
let message = stringBundle.getFormattedString(stringId, ["<>"], 1);
|
||||
|
||||
let notification; // Used by action callbacks.
|
||||
let mainAction = {
|
||||
|
@ -809,12 +787,7 @@ 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 we have a secondOrigin, it means this request is lacking explicit
|
||||
// trust, and we should always prompt even in with persistent permission.
|
||||
if (
|
||||
!aRequest.secondOrigin &&
|
||||
checkRequestAllowed(aRequest, principal, aBrowser)
|
||||
) {
|
||||
if (checkRequestAllowed(aRequest, principal, aBrowser)) {
|
||||
this.remove();
|
||||
return true;
|
||||
}
|
||||
|
@ -1208,28 +1181,11 @@ function prompt(aBrowser, aRequest) {
|
|||
},
|
||||
};
|
||||
|
||||
function shouldShowAlwaysRemember() {
|
||||
// Don't offer "always remember" action in PB mode
|
||||
if (PrivateBrowsingUtils.isBrowserPrivate(aBrowser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't offer "always remember" action in third party with no permission
|
||||
// delegation
|
||||
if (aRequest.isThirdPartyOrigin && !aRequest.shouldDelegatePermission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't offer "always remember" action in maybe unsafe permission
|
||||
// delegation
|
||||
if (aRequest.shouldDelegatePermission && aRequest.secondOrigin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shouldShowAlwaysRemember()) {
|
||||
// Don't offer "always remember" action in PB mode or from third party
|
||||
if (
|
||||
!PrivateBrowsingUtils.isBrowserPrivate(aBrowser) &&
|
||||
!aRequest.isThirdPartyOrigin
|
||||
) {
|
||||
// Disable the permanent 'Allow' action if the connection isn't secure, or for
|
||||
// screen/audio sharing (because we can't guess which window the user wants to
|
||||
// share without prompting).
|
||||
|
@ -1278,10 +1234,6 @@ function prompt(aBrowser, aRequest) {
|
|||
}
|
||||
options.popupIconClass = iconClass + "-icon";
|
||||
|
||||
if (aRequest.secondOrigin) {
|
||||
options.secondName = getHostOrExtensionName(null, aRequest.secondOrigin);
|
||||
}
|
||||
|
||||
notification = chromeDoc.defaultView.PopupNotifications.show(
|
||||
aBrowser,
|
||||
"webRTC-shareDevices",
|
||||
|
|
|
@ -8337,10 +8337,6 @@ void Document::SetPrototypeDocument(nsXULPrototypeDocument* aPrototype) {
|
|||
mSynchronousDOMContentLoaded = true;
|
||||
}
|
||||
|
||||
nsIPermissionDelegateHandler* Document::PermDelegateHandler() {
|
||||
return GetPermissionDelegateHandler();
|
||||
}
|
||||
|
||||
Document* Document::RequestExternalResource(
|
||||
nsIURI* aURI, nsIReferrerInfo* aReferrerInfo, nsINode* aRequestingNode,
|
||||
ExternalResourceLoad** aPendingLoad) {
|
||||
|
|
|
@ -134,7 +134,6 @@ class nsIAppWindow;
|
|||
class nsXULPrototypeDocument;
|
||||
class nsXULPrototypeElement;
|
||||
class PermissionDelegateHandler;
|
||||
class nsIPermissionDelegateHandler;
|
||||
struct nsFont;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -4199,8 +4198,6 @@ class Document : public nsINode,
|
|||
|
||||
void SetPrototypeDocument(nsXULPrototypeDocument* aPrototype);
|
||||
|
||||
nsIPermissionDelegateHandler* PermDelegateHandler();
|
||||
|
||||
// Returns true if we use overlay scrollbars on the system wide or on the
|
||||
// given document.
|
||||
static bool UseOverlayScrollbars(const Document* aDocument);
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
using mozilla::Unused; // <snicker>
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla;
|
||||
using DelegateInfo = PermissionDelegateHandler::PermissionDelegateInfo;
|
||||
|
||||
#define kVisibilityChange "visibilitychange"
|
||||
|
||||
class VisibilityChangeListener final : public nsIDOMEventListener {
|
||||
|
@ -124,7 +124,6 @@ class ContentPermissionRequestParent : public PContentPermissionRequestParent {
|
|||
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
|
||||
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
|
||||
const bool aIsHandlingUserInput,
|
||||
const bool aMaybeUnsafePermissionDelegate,
|
||||
const bool aUserHadInteractedWithDocument,
|
||||
const DOMTimeStamp aDocumentDOMContentLoadedTimestamp);
|
||||
virtual ~ContentPermissionRequestParent();
|
||||
|
@ -135,7 +134,6 @@ class ContentPermissionRequestParent : public PContentPermissionRequestParent {
|
|||
nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
|
||||
nsCOMPtr<Element> mElement;
|
||||
bool mIsHandlingUserInput;
|
||||
bool mMaybeUnsafePermissionDelegate;
|
||||
bool mUserHadInteractedWithDocument;
|
||||
DOMTimeStamp mDocumentDOMContentLoadedTimestamp;
|
||||
RefPtr<nsContentPermissionRequestProxy> mProxy;
|
||||
|
@ -154,8 +152,7 @@ class ContentPermissionRequestParent : public PContentPermissionRequestParent {
|
|||
ContentPermissionRequestParent::ContentPermissionRequestParent(
|
||||
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
|
||||
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
|
||||
const bool aIsHandlingUserInput, const bool aMaybeUnsafePermissionDelegate,
|
||||
const bool aUserHadInteractedWithDocument,
|
||||
const bool aIsHandlingUserInput, const bool aUserHadInteractedWithDocument,
|
||||
const DOMTimeStamp aDocumentDOMContentLoadedTimestamp) {
|
||||
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
|
||||
|
||||
|
@ -164,7 +161,6 @@ ContentPermissionRequestParent::ContentPermissionRequestParent(
|
|||
mElement = aElement;
|
||||
mRequests = aRequests;
|
||||
mIsHandlingUserInput = aIsHandlingUserInput;
|
||||
mMaybeUnsafePermissionDelegate = aMaybeUnsafePermissionDelegate;
|
||||
mUserHadInteractedWithDocument = aUserHadInteractedWithDocument;
|
||||
mDocumentDOMContentLoadedTimestamp = aDocumentDOMContentLoadedTimestamp;
|
||||
}
|
||||
|
@ -333,14 +329,12 @@ PContentPermissionRequestParent*
|
|||
nsContentPermissionUtils::CreateContentPermissionRequestParent(
|
||||
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
|
||||
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
|
||||
const bool aIsHandlingUserInput, const bool aMaybeUnsafePermissionDelegate,
|
||||
const bool aUserHadInteractedWithDocument,
|
||||
const bool aIsHandlingUserInput, const bool aUserHadInteractedWithDocument,
|
||||
const DOMTimeStamp aDocumentDOMContentLoadedTimestamp,
|
||||
const TabId& aTabId) {
|
||||
PContentPermissionRequestParent* parent = new ContentPermissionRequestParent(
|
||||
aRequests, aElement, aPrincipal, aTopLevelPrincipal, aIsHandlingUserInput,
|
||||
aMaybeUnsafePermissionDelegate, aUserHadInteractedWithDocument,
|
||||
aDocumentDOMContentLoadedTimestamp);
|
||||
aUserHadInteractedWithDocument, aDocumentDOMContentLoadedTimestamp);
|
||||
ContentPermissionRequestParentMap()[parent] = aTabId;
|
||||
|
||||
return parent;
|
||||
|
@ -380,11 +374,6 @@ nsresult nsContentPermissionUtils::AskPermission(
|
|||
rv = aRequest->GetIsHandlingUserInput(&isHandlingUserInput);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool maybeUnsafePermissionDelegate;
|
||||
rv = aRequest->GetMaybeUnsafePermissionDelegate(
|
||||
&maybeUnsafePermissionDelegate);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool userHadInteractedWithDocument;
|
||||
rv = aRequest->GetUserHadInteractedWithDocument(
|
||||
&userHadInteractedWithDocument);
|
||||
|
@ -402,8 +391,8 @@ nsresult nsContentPermissionUtils::AskPermission(
|
|||
ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor(
|
||||
req, permArray, IPC::Principal(principal),
|
||||
IPC::Principal(topLevelPrincipal), isHandlingUserInput,
|
||||
maybeUnsafePermissionDelegate, userHadInteractedWithDocument,
|
||||
documentDOMContentLoadedTimestamp, child->GetTabId());
|
||||
userHadInteractedWithDocument, documentDOMContentLoadedTimestamp,
|
||||
child->GetTabId());
|
||||
ContentPermissionRequestChildMap()[req.get()] = child->GetTabId();
|
||||
|
||||
req->Sendprompt();
|
||||
|
@ -564,7 +553,6 @@ ContentPermissionRequestBase::ContentPermissionRequestBase(
|
|||
mType(aType),
|
||||
mIsHandlingUserInput(UserActivation::IsHandlingUserInput()),
|
||||
mUserHadInteractedWithDocument(false),
|
||||
mMaybeUnsafePermissionDelegate(false),
|
||||
mDocumentDOMContentLoadedTimestamp(0) {
|
||||
if (!aWindow) {
|
||||
return;
|
||||
|
@ -576,12 +564,6 @@ ContentPermissionRequestBase::ContentPermissionRequestBase(
|
|||
}
|
||||
|
||||
mPermissionHandler = doc->GetPermissionDelegateHandler();
|
||||
if (mPermissionHandler) {
|
||||
nsTArray<nsCString> types;
|
||||
types.AppendElement(mType);
|
||||
mPermissionHandler->MaybeUnsafePermissionDelegate(
|
||||
types, &mMaybeUnsafePermissionDelegate);
|
||||
}
|
||||
|
||||
mUserHadInteractedWithDocument = doc->UserHasInteracted();
|
||||
|
||||
|
@ -599,20 +581,6 @@ ContentPermissionRequestBase::GetPrincipal(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentPermissionRequestBase::GetDelegatePrincipal(
|
||||
const nsACString& aType, nsIPrincipal** aRequestingPrincipal) {
|
||||
return PermissionDelegateHandler::GetDelegatePrincipal(aType, this,
|
||||
aRequestingPrincipal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentPermissionRequestBase::GetMaybeUnsafePermissionDelegate(
|
||||
bool* aMaybeUnsafePermissionDelegate) {
|
||||
*aMaybeUnsafePermissionDelegate = mMaybeUnsafePermissionDelegate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentPermissionRequestBase::GetTopLevelPrincipal(
|
||||
nsIPrincipal** aRequestingPrincipal) {
|
||||
|
@ -947,18 +915,6 @@ nsContentPermissionRequestProxy::GetTopLevelPrincipal(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentPermissionRequestProxy::GetDelegatePrincipal(
|
||||
const nsACString& aType, nsIPrincipal** aRequestingPrincipal) {
|
||||
NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
|
||||
if (mParent == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return PermissionDelegateHandler::GetDelegatePrincipal(aType, this,
|
||||
aRequestingPrincipal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentPermissionRequestProxy::GetElement(Element** aRequestingElement) {
|
||||
NS_ENSURE_ARG_POINTER(aRequestingElement);
|
||||
|
@ -982,17 +938,6 @@ nsContentPermissionRequestProxy::GetIsHandlingUserInput(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentPermissionRequestProxy::GetMaybeUnsafePermissionDelegate(
|
||||
bool* aMaybeUnsafePermissionDelegate) {
|
||||
NS_ENSURE_ARG_POINTER(aMaybeUnsafePermissionDelegate);
|
||||
if (mParent == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aMaybeUnsafePermissionDelegate = mParent->mMaybeUnsafePermissionDelegate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentPermissionRequestProxy::GetUserHadInteractedWithDocument(
|
||||
bool* aUserHadInteractedWithDocument) {
|
||||
|
|
|
@ -73,7 +73,6 @@ class nsContentPermissionUtils {
|
|||
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
|
||||
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
|
||||
const bool aIsHandlingUserInput,
|
||||
const bool aMaybeUnsafePermissionDelegate,
|
||||
const bool aUserHadInteractedWithDocument,
|
||||
const DOMTimeStamp aDocumentDOMContentLoadedTimestamp,
|
||||
const TabId& aTabId);
|
||||
|
@ -121,14 +120,10 @@ class ContentPermissionRequestBase : public nsIContentPermissionRequest {
|
|||
|
||||
NS_IMETHOD GetTypes(nsIArray** aTypes) override;
|
||||
NS_IMETHOD GetPrincipal(nsIPrincipal** aPrincipal) override;
|
||||
NS_IMETHOD GetDelegatePrincipal(const nsACString& aType,
|
||||
nsIPrincipal** aPrincipal) override;
|
||||
NS_IMETHOD GetTopLevelPrincipal(nsIPrincipal** aTopLevelPrincipal) override;
|
||||
NS_IMETHOD GetWindow(mozIDOMWindow** aWindow) override;
|
||||
NS_IMETHOD GetElement(mozilla::dom::Element** aElement) override;
|
||||
NS_IMETHOD GetIsHandlingUserInput(bool* aIsHandlingUserInput) override;
|
||||
NS_IMETHOD GetMaybeUnsafePermissionDelegate(
|
||||
bool* aMaybeUnsafePermissionDelegate) override;
|
||||
NS_IMETHOD GetUserHadInteractedWithDocument(
|
||||
bool* aUserHadInteractedWithDocument) override;
|
||||
NS_IMETHOD GetDocumentDOMContentLoadedTimestamp(
|
||||
|
@ -172,7 +167,6 @@ class ContentPermissionRequestBase : public nsIContentPermissionRequest {
|
|||
nsCString mType;
|
||||
bool mIsHandlingUserInput;
|
||||
bool mUserHadInteractedWithDocument;
|
||||
bool mMaybeUnsafePermissionDelegate;
|
||||
DOMTimeStamp mDocumentDOMContentLoadedTimestamp;
|
||||
};
|
||||
|
||||
|
|
|
@ -1858,6 +1858,3 @@ addExternalIface('XULTemplateRuleFilter', nativeType='nsIXULTemplateRuleFilter',
|
|||
notflattened=True)
|
||||
addExternalIface('nsISHistory', nativeType='nsISHistory', notflattened=True)
|
||||
addExternalIface('ReferrerInfo', nativeType='nsIReferrerInfo')
|
||||
addExternalIface('nsIPermissionDelegateHandler',
|
||||
nativeType='nsIPermissionDelegateHandler',
|
||||
notflattened=True)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h" // for nsAutoMicroTask
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/FeaturePolicyUtils.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/GeolocationPositionError.h"
|
||||
#include "mozilla/dom/GeolocationPositionErrorBinding.h"
|
||||
|
@ -983,6 +984,21 @@ bool Geolocation::ShouldBlockInsecureRequests() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Geolocation::FeaturePolicyBlocked() const {
|
||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryReferent(mOwner);
|
||||
if (!win) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> doc = win->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return FeaturePolicyUtils::IsFeatureAllowed(doc,
|
||||
NS_LITERAL_STRING("geolocation"));
|
||||
}
|
||||
|
||||
bool Geolocation::ClearPendingRequest(nsGeolocationRequest* aRequest) {
|
||||
if (aRequest->IsWatch() && this->IsAlreadyCleared(aRequest)) {
|
||||
this->NotifyAllowedRequest(aRequest);
|
||||
|
@ -1035,7 +1051,7 @@ nsresult Geolocation::GetCurrentPosition(GeoPositionCallback callback,
|
|||
static_cast<uint8_t>(mProtocolType), target);
|
||||
|
||||
if (!StaticPrefs::geo_enabled() || ShouldBlockInsecureRequests() ||
|
||||
!request->CheckPermissionDelegate()) {
|
||||
!FeaturePolicyBlocked()) {
|
||||
request->RequestDelayedTask(target,
|
||||
nsGeolocationRequest::DelayedTaskType::Deny);
|
||||
return NS_OK;
|
||||
|
@ -1108,7 +1124,7 @@ int32_t Geolocation::WatchPosition(GeoPositionCallback aCallback,
|
|||
watchId);
|
||||
|
||||
if (!StaticPrefs::geo_enabled() || ShouldBlockInsecureRequests() ||
|
||||
!request->CheckPermissionDelegate()) {
|
||||
!FeaturePolicyBlocked()) {
|
||||
request->RequestDelayedTask(target,
|
||||
nsGeolocationRequest::DelayedTaskType::Deny);
|
||||
return watchId;
|
||||
|
|
|
@ -205,6 +205,10 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
|||
// within a context that is not secure.
|
||||
bool ShouldBlockInsecureRequests() const;
|
||||
|
||||
// Return whather the Feature 'geolocation' is blocked by FeaturePolicy
|
||||
// directive.
|
||||
bool FeaturePolicyBlocked() const;
|
||||
|
||||
// Two callback arrays. The first |mPendingCallbacks| holds objects for only
|
||||
// one callback and then they are released/removed from the array. The second
|
||||
// |mWatchingCallbacks| holds objects until the object is explictly removed or
|
||||
|
|
|
@ -21,7 +21,6 @@ XPIDL_SOURCES += [
|
|||
'nsIDOMWindow.idl',
|
||||
'nsIDOMWindowUtils.idl',
|
||||
'nsIFocusManager.idl',
|
||||
'nsIPermissionDelegateHandler.idl',
|
||||
'nsIQueryContentEventResult.idl',
|
||||
'nsIRemoteTab.idl',
|
||||
'nsIServiceWorkerManager.idl',
|
||||
|
|
|
@ -92,22 +92,12 @@ interface nsIContentPermissionRequest : nsISupports {
|
|||
readonly attribute boolean userHadInteractedWithDocument;
|
||||
readonly attribute DOMTimeStamp documentDOMContentLoadedTimestamp;
|
||||
|
||||
readonly attribute boolean maybeUnsafePermissionDelegate;
|
||||
/**
|
||||
* The requester to get the required information of
|
||||
* the window.
|
||||
*/
|
||||
readonly attribute nsIContentPermissionRequester requester;
|
||||
|
||||
/*
|
||||
* Get delegate principal of the permission request. This will return nullptr,
|
||||
* or request's principal or top level principal based on the delegate policy
|
||||
* will be applied for a given type.
|
||||
*
|
||||
* @param aType the permission type to get
|
||||
*/
|
||||
nsIPrincipal getDelegatePrincipal(in ACString aType);
|
||||
|
||||
/**
|
||||
* allow or cancel the request
|
||||
*/
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This file contains an interface to the Permission Delegate Handler,
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, builtinclass, uuid(07611dc6-bf4d-4d8a-a64b-f3a5904dddc7)]
|
||||
interface nsIPermissionDelegateHandler : nsISupports
|
||||
{
|
||||
/*
|
||||
* Return true if we are delegating permission to a third party which is not
|
||||
* explicitly trusted. An orgin is not explicitly trusted means it is not
|
||||
* presented in the Feature Policy ancestor chain, via src, explicitly listed
|
||||
* in allow, and it is not the top-level origin.
|
||||
*
|
||||
* @param aTypes the permission types to check
|
||||
*/
|
||||
boolean maybeUnsafePermissionDelegate(in Array<ACString> aTypes);
|
||||
};
|
||||
|
|
@ -3151,10 +3151,8 @@ PContentPermissionRequestChild*
|
|||
ContentChild::AllocPContentPermissionRequestChild(
|
||||
const nsTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal, const IPC::Principal& aTopLevelPrincipal,
|
||||
const bool& aIsHandlingUserInput,
|
||||
const bool& aMaybeUnsafePermissionDelegate,
|
||||
const bool& aDocumentHasUserInput, const DOMTimeStamp aPageLoadTimestamp,
|
||||
const TabId& aTabId) {
|
||||
const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
|
||||
const DOMTimeStamp aPageLoadTimestamp, const TabId& aTabId) {
|
||||
MOZ_CRASH("unused");
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -528,10 +528,8 @@ class ContentChild final
|
|||
const nsTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal,
|
||||
const IPC::Principal& aTopLevelPrincipal,
|
||||
const bool& aIsHandlingUserInput,
|
||||
const bool& aMaybeUnsafePermissionDelegate,
|
||||
const bool& aDocumentHasUserInput, const DOMTimeStamp aPageLoadTimestamp,
|
||||
const TabId& aTabId);
|
||||
const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
|
||||
const DOMTimeStamp aPageLoadTimestamp, const TabId& aTabId);
|
||||
bool DeallocPContentPermissionRequestChild(
|
||||
PContentPermissionRequestChild* actor);
|
||||
|
||||
|
|
|
@ -4632,10 +4632,8 @@ PContentPermissionRequestParent*
|
|||
ContentParent::AllocPContentPermissionRequestParent(
|
||||
const nsTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal, const IPC::Principal& aTopLevelPrincipal,
|
||||
const bool& aIsHandlingUserInput,
|
||||
const bool& aMaybeUnsafePermissionDelegate,
|
||||
const bool& aDocumentHasUserInput, const DOMTimeStamp& aPageLoadTimestamp,
|
||||
const TabId& aTabId) {
|
||||
const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
|
||||
const DOMTimeStamp& aPageLoadTimestamp, const TabId& aTabId) {
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
RefPtr<BrowserParent> tp =
|
||||
cpm->GetTopLevelBrowserParentByProcessAndTabId(this->ChildID(), aTabId);
|
||||
|
@ -4645,8 +4643,7 @@ ContentParent::AllocPContentPermissionRequestParent(
|
|||
|
||||
return nsContentPermissionUtils::CreateContentPermissionRequestParent(
|
||||
aRequests, tp->GetOwnerElement(), aPrincipal, aTopLevelPrincipal,
|
||||
aIsHandlingUserInput, aMaybeUnsafePermissionDelegate,
|
||||
aDocumentHasUserInput, aPageLoadTimestamp, aTabId);
|
||||
aIsHandlingUserInput, aDocumentHasUserInput, aPageLoadTimestamp, aTabId);
|
||||
}
|
||||
|
||||
bool ContentParent::DeallocPContentPermissionRequestParent(
|
||||
|
|
|
@ -508,10 +508,8 @@ class ContentParent final
|
|||
const nsTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal,
|
||||
const IPC::Principal& aTopLevelPrincipal,
|
||||
const bool& aIsHandlingUserInput,
|
||||
const bool& aMaybeUnsafePermissionDelegate,
|
||||
const bool& aDocumentHasUserInput, const DOMTimeStamp& aPageLoadTimestamp,
|
||||
const TabId& aTabId);
|
||||
const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
|
||||
const DOMTimeStamp& aPageLoadTimestamp, const TabId& aTabId);
|
||||
|
||||
bool DeallocPContentPermissionRequestParent(
|
||||
PContentPermissionRequestParent* actor);
|
||||
|
|
|
@ -1168,13 +1168,9 @@ parent:
|
|||
* principals that can live in the content process should
|
||||
* provided.
|
||||
*/
|
||||
async PContentPermissionRequest(PermissionRequest[] aRequests,
|
||||
Principal aPrincipal,
|
||||
Principal aTopLevelPrincipal,
|
||||
bool aIsHandlingUserInput,
|
||||
bool aMaybeUnsafePermissionDelegate,
|
||||
bool aDocumentHasUserInput,
|
||||
uint64_t aPageLoadTimestamp, TabId tabId);
|
||||
async PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
|
||||
Principal aTopLevelPrincipal, bool aIsHandlingUserInput,
|
||||
bool aDocumentHasUserInput, uint64_t aPageLoadTimestamp, TabId tabId);
|
||||
|
||||
async ShutdownProfile(nsCString aProfile);
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
#include "nsProxyRelease.h"
|
||||
#include "nss.h"
|
||||
#include "nsVariant.h"
|
||||
#include "PermissionDelegateHandler.h"
|
||||
#include "pk11pub.h"
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
#include "VideoStreamTrack.h"
|
||||
|
@ -1023,7 +1022,7 @@ MediaDevice::GetMediaSource(nsAString& aMediaSource) {
|
|||
|
||||
nsresult MediaDevice::Allocate(const MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
uint64_t aWindowID,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) {
|
||||
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
||||
MOZ_ASSERT(mSource);
|
||||
|
@ -1035,7 +1034,8 @@ nsresult MediaDevice::Allocate(const MediaTrackConstraints& aConstraints,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return mSource->Allocate(aConstraints, aPrefs, aWindowID, aOutBadConstraint);
|
||||
return mSource->Allocate(aConstraints, aPrefs, aPrincipalInfo,
|
||||
aOutBadConstraint);
|
||||
}
|
||||
|
||||
void MediaDevice::SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
|
@ -1502,7 +1502,7 @@ class GetUserMediaTask : public Runnable {
|
|||
|
||||
if (mAudioDevice) {
|
||||
auto& constraints = GetInvariant(mConstraints.mAudio);
|
||||
rv = mAudioDevice->Allocate(constraints, mPrefs, mWindowID,
|
||||
rv = mAudioDevice->Allocate(constraints, mPrefs, mPrincipalInfo,
|
||||
&badConstraint);
|
||||
if (NS_FAILED(rv)) {
|
||||
errorMsg = "Failed to allocate audiosource";
|
||||
|
@ -1516,7 +1516,7 @@ class GetUserMediaTask : public Runnable {
|
|||
}
|
||||
if (!errorMsg && mVideoDevice) {
|
||||
auto& constraints = GetInvariant(mConstraints.mVideo);
|
||||
rv = mVideoDevice->Allocate(constraints, mPrefs, mWindowID,
|
||||
rv = mVideoDevice->Allocate(constraints, mPrefs, mPrincipalInfo,
|
||||
&badConstraint);
|
||||
if (NS_FAILED(rv)) {
|
||||
errorMsg = "Failed to allocate videosource";
|
||||
|
@ -2543,41 +2543,55 @@ RefPtr<MediaManager::StreamPromise> MediaManager::GetUserMedia(
|
|||
|
||||
if (!privileged) {
|
||||
// Check if this site has had persistent permissions denied.
|
||||
RefPtr<PermissionDelegateHandler> permDelegate =
|
||||
doc->GetPermissionDelegateHandler();
|
||||
MOZ_RELEASE_ASSERT(permDelegate);
|
||||
nsCOMPtr<nsIPermissionManager> permManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
uint32_t audioPerm = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
if (IsOn(c.mAudio)) {
|
||||
if (audioType == MediaSourceEnum::Microphone) {
|
||||
if (Preferences::GetBool("media.getusermedia.microphone.deny", false)) {
|
||||
if (Preferences::GetBool("media.getusermedia.microphone.deny", false) ||
|
||||
!FeaturePolicyUtils::IsFeatureAllowed(
|
||||
doc, NS_LITERAL_STRING("microphone"))) {
|
||||
audioPerm = nsIPermissionManager::DENY_ACTION;
|
||||
} else {
|
||||
rv = permDelegate->GetPermission(NS_LITERAL_CSTRING("microphone"),
|
||||
&audioPerm, true);
|
||||
rv = permManager->TestExactPermissionFromPrincipal(
|
||||
principal, NS_LITERAL_CSTRING("microphone"), &audioPerm);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
} else {
|
||||
rv = permDelegate->GetPermission(NS_LITERAL_CSTRING("screen"),
|
||||
&audioPerm, true);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (!FeaturePolicyUtils::IsFeatureAllowed(
|
||||
doc, NS_LITERAL_STRING("display-capture"))) {
|
||||
audioPerm = nsIPermissionManager::DENY_ACTION;
|
||||
} else {
|
||||
rv = permManager->TestExactPermissionFromPrincipal(
|
||||
principal, NS_LITERAL_CSTRING("screen"), &audioPerm);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t videoPerm = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
if (IsOn(c.mVideo)) {
|
||||
if (videoType == MediaSourceEnum::Camera) {
|
||||
if (Preferences::GetBool("media.getusermedia.camera.deny", false)) {
|
||||
if (Preferences::GetBool("media.getusermedia.camera.deny", false) ||
|
||||
!FeaturePolicyUtils::IsFeatureAllowed(
|
||||
doc, NS_LITERAL_STRING("camera"))) {
|
||||
videoPerm = nsIPermissionManager::DENY_ACTION;
|
||||
} else {
|
||||
rv = permDelegate->GetPermission(NS_LITERAL_CSTRING("camera"),
|
||||
&videoPerm, true);
|
||||
rv = permManager->TestExactPermissionFromPrincipal(
|
||||
principal, NS_LITERAL_CSTRING("camera"), &videoPerm);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
} else {
|
||||
rv = permDelegate->GetPermission(NS_LITERAL_CSTRING("screen"),
|
||||
&videoPerm, true);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (!FeaturePolicyUtils::IsFeatureAllowed(
|
||||
doc, NS_LITERAL_STRING("display-capture"))) {
|
||||
videoPerm = nsIPermissionManager::DENY_ACTION;
|
||||
} else {
|
||||
rv = permManager->TestExactPermissionFromPrincipal(
|
||||
principal, NS_LITERAL_CSTRING("screen"), &videoPerm);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3987,24 +4001,35 @@ bool MediaManager::IsActivelyCapturingOrHasAPermission(uint64_t aWindowId) {
|
|||
|
||||
// Check if this site has persistent permissions.
|
||||
nsresult rv;
|
||||
RefPtr<PermissionDelegateHandler> permDelegate =
|
||||
doc->GetPermissionDelegateHandler();
|
||||
if (NS_WARN_IF(!permDelegate)) {
|
||||
return false;
|
||||
nsCOMPtr<nsIPermissionManager> mgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false; // no permission manager no permissions!
|
||||
}
|
||||
|
||||
uint32_t audio = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
{
|
||||
rv = permDelegate->GetPermission(NS_LITERAL_CSTRING("microphone"), &audio,
|
||||
true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
if (!FeaturePolicyUtils::IsFeatureAllowed(
|
||||
doc, NS_LITERAL_STRING("microphone"))) {
|
||||
audio = nsIPermissionManager::DENY_ACTION;
|
||||
} else {
|
||||
rv = mgr->TestExactPermissionFromPrincipal(
|
||||
principal, NS_LITERAL_CSTRING("microphone"), &audio);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
rv =
|
||||
permDelegate->GetPermission(NS_LITERAL_CSTRING("camera"), &video, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
|
||||
if (!FeaturePolicyUtils::IsFeatureAllowed(doc,
|
||||
NS_LITERAL_STRING("camera"))) {
|
||||
video = nsIPermissionManager::DENY_ACTION;
|
||||
} else {
|
||||
rv = mgr->TestExactPermissionFromPrincipal(
|
||||
principal, NS_LITERAL_CSTRING("camera"), &video);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return audio == nsIPermissionManager::ALLOW_ACTION ||
|
||||
|
|
|
@ -82,7 +82,8 @@ class MediaDevice : public nsIMediaDevice {
|
|||
bool aIsChrome);
|
||||
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowId,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint);
|
||||
void SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
const PrincipalHandle& aPrincipal);
|
||||
|
|
|
@ -33,9 +33,9 @@ class MockMediaEngineSource : public MediaEngineSource {
|
|||
MOCK_CONST_METHOD0(GetUUID, nsCString());
|
||||
MOCK_CONST_METHOD0(GetGroupId, nsString());
|
||||
MOCK_CONST_METHOD1(GetSettings, void(dom::MediaTrackSettings&));
|
||||
MOCK_METHOD4(Allocate,
|
||||
nsresult(const dom::MediaTrackConstraints&,
|
||||
const MediaEnginePrefs&, uint64_t, const char**));
|
||||
MOCK_METHOD4(Allocate, nsresult(const dom::MediaTrackConstraints&,
|
||||
const MediaEnginePrefs&,
|
||||
const ipc::PrincipalInfo&, const char**));
|
||||
MOCK_METHOD2(SetTrack,
|
||||
void(const RefPtr<SourceMediaTrack>&, const PrincipalHandle&));
|
||||
MOCK_METHOD0(Start, nsresult());
|
||||
|
|
|
@ -326,17 +326,18 @@ mozilla::ipc::IPCResult CamerasChild::RecvReplyGetCaptureDevice(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
int CamerasChild::AllocateCaptureDevice(CaptureEngine aCapEngine,
|
||||
const char* unique_idUTF8,
|
||||
const unsigned int unique_idUTF8Length,
|
||||
int& aStreamId, uint64_t aWindowID) {
|
||||
int CamerasChild::AllocateCaptureDevice(
|
||||
CaptureEngine aCapEngine, const char* unique_idUTF8,
|
||||
const unsigned int unique_idUTF8Length, int& aStreamId,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
|
||||
LOG(("%s", __PRETTY_FUNCTION__));
|
||||
nsCString unique_id(unique_idUTF8);
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
mozilla::NewRunnableMethod<CaptureEngine, nsCString, const uint64_t&>(
|
||||
mozilla::NewRunnableMethod<CaptureEngine, nsCString,
|
||||
const mozilla::ipc::PrincipalInfo&>(
|
||||
"camera::PCamerasChild::SendAllocateCaptureDevice", this,
|
||||
&CamerasChild::SendAllocateCaptureDevice, aCapEngine, unique_id,
|
||||
aWindowID);
|
||||
aPrincipalInfo);
|
||||
LockAndDispatch<> dispatcher(this, __func__, runnable, -1, mZero);
|
||||
if (dispatcher.Success()) {
|
||||
LOG(("Capture Device allocated: %d", mReplyInteger));
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace mozilla {
|
|||
|
||||
namespace ipc {
|
||||
class BackgroundChildImpl;
|
||||
class PrincipalInfo;
|
||||
} // namespace ipc
|
||||
|
||||
namespace camera {
|
||||
|
@ -181,7 +182,8 @@ class CamerasChild final : public PCamerasChild {
|
|||
int StopCapture(CaptureEngine aCapEngine, const int capture_id);
|
||||
int AllocateCaptureDevice(CaptureEngine aCapEngine, const char* unique_idUTF8,
|
||||
const unsigned int unique_idUTF8Length,
|
||||
int& capture_id, uint64_t aWindowID);
|
||||
int& capture_id,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||
int GetCaptureCapability(CaptureEngine aCapEngine, const char* unique_idUTF8,
|
||||
const unsigned int capability_number,
|
||||
webrtc::VideoCaptureCapability& capability);
|
||||
|
|
|
@ -15,10 +15,7 @@
|
|||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_permissions.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -635,45 +632,28 @@ mozilla::ipc::IPCResult CamerasParent::RecvGetCaptureDevice(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
// Find out whether the given window with id has permission to use the
|
||||
// camera. If the permission is not persistent, we'll make it a one-shot by
|
||||
// removing the (session) permission.
|
||||
static bool HasCameraPermission(const uint64_t& aWindowId) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<dom::WindowGlobalParent> window =
|
||||
dom::WindowGlobalParent::GetByInnerWindowId(aWindowId);
|
||||
if (!window) {
|
||||
// Could not find window by id
|
||||
// Find out whether the given principal has permission to use the
|
||||
// camera. If the permission is not persistent, we'll make it
|
||||
// a one-shot by removing the (session) permission.
|
||||
static bool HasCameraPermission(const ipc::PrincipalInfo& aPrincipalInfo) {
|
||||
if (aPrincipalInfo.type() == ipc::PrincipalInfo::TNullPrincipalInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we delegate permission from first party, we should use the top level
|
||||
// window
|
||||
if (StaticPrefs::dom_security_featurePolicy_enabled() &&
|
||||
StaticPrefs::permissions_delegation_enabled()) {
|
||||
RefPtr<dom::BrowsingContext> topBC = window->BrowsingContext()->Top();
|
||||
window = topBC->Canonical()->GetCurrentWindowGlobal();
|
||||
}
|
||||
|
||||
// Return false if the window is not the currently-active window for its
|
||||
// BrowsingContext.
|
||||
if (!window || !window->IsCurrentGlobal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIPrincipal* principal = window->DocumentPrincipal();
|
||||
if (principal->GetIsNullPrincipal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (principal->IsSystemPrincipal()) {
|
||||
if (aPrincipalInfo.type() == ipc::PrincipalInfo::TSystemPrincipalInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(principal->GetIsContentPrincipal());
|
||||
MOZ_ASSERT(aPrincipalInfo.type() ==
|
||||
ipc::PrincipalInfo::TContentPrincipalInfo);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Name used with nsIPermissionManager
|
||||
static const nsLiteralCString cameraPermission =
|
||||
NS_LITERAL_CSTRING("MediaManagerVideo");
|
||||
|
@ -702,15 +682,15 @@ static bool HasCameraPermission(const uint64_t& aWindowId) {
|
|||
|
||||
mozilla::ipc::IPCResult CamerasParent::RecvAllocateCaptureDevice(
|
||||
const CaptureEngine& aCapEngine, const nsCString& unique_id,
|
||||
const uint64_t& aWindowID) {
|
||||
const PrincipalInfo& aPrincipalInfo) {
|
||||
LOG(("%s: Verifying permissions", __PRETTY_FUNCTION__));
|
||||
RefPtr<CamerasParent> self(this);
|
||||
RefPtr<Runnable> mainthread_runnable = NewRunnableFrom([self, aCapEngine,
|
||||
unique_id,
|
||||
aWindowID]() {
|
||||
aPrincipalInfo]() {
|
||||
// Verify whether the claimed origin has received permission
|
||||
// to use the camera, either persistently or this session (one shot).
|
||||
bool allowed = HasCameraPermission(aWindowID);
|
||||
bool allowed = HasCameraPermission(aPrincipalInfo);
|
||||
if (!allowed) {
|
||||
// Developer preference for turning off permission check.
|
||||
if (Preferences::GetBool("media.navigator.permission.disabled", false) ||
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
}
|
||||
|
||||
namespace camera {
|
||||
|
||||
class CamerasParent;
|
||||
|
@ -76,7 +80,7 @@ class CamerasParent final : public PCamerasParent,
|
|||
// Messages received form the child. These run on the IPC/PBackground thread.
|
||||
mozilla::ipc::IPCResult RecvAllocateCaptureDevice(
|
||||
const CaptureEngine& aEngine, const nsCString& aUnique_idUTF8,
|
||||
const uint64_t& aWindowID) override;
|
||||
const ipc::PrincipalInfo& aPrincipalInfo) override;
|
||||
mozilla::ipc::IPCResult RecvReleaseCaptureDevice(const CaptureEngine&,
|
||||
const int&) override;
|
||||
mozilla::ipc::IPCResult RecvNumberOfCaptureDevices(
|
||||
|
|
|
@ -75,7 +75,7 @@ parent:
|
|||
async GetCaptureDevice(CaptureEngine engine, int num);
|
||||
|
||||
async AllocateCaptureDevice(CaptureEngine engine, nsCString unique_idUTF8,
|
||||
uint64_t windowID);
|
||||
PrincipalInfo principal);
|
||||
async ReleaseCaptureDevice(CaptureEngine engine, int numdev);
|
||||
async StartCapture(CaptureEngine engine, int numdev, VideoCaptureCapability capability);
|
||||
async FocusOnSelectedSource(CaptureEngine engine, int numdev);
|
||||
|
|
|
@ -132,7 +132,8 @@ void MediaEngineDefaultVideoSource::GetSettings(
|
|||
|
||||
nsresult MediaEngineDefaultVideoSource::Allocate(
|
||||
const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
|
||||
uint64_t aWindowID, const char** aOutBadConstraint) {
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_ASSERT(mState == kReleased);
|
||||
|
@ -409,7 +410,8 @@ void MediaEngineDefaultAudioSource::GetSettings(
|
|||
|
||||
nsresult MediaEngineDefaultAudioSource::Allocate(
|
||||
const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
|
||||
uint64_t aWindowID, const char** aOutBadConstraint) {
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_ASSERT(mState == kReleased);
|
||||
|
|
|
@ -42,7 +42,8 @@ class MediaEngineDefaultVideoSource : public MediaEngineSource {
|
|||
nsString GetGroupId() const override;
|
||||
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) override;
|
||||
void SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
const PrincipalHandle& aPrincipal) override;
|
||||
|
@ -104,7 +105,8 @@ class MediaEngineDefaultAudioSource : public MediaEngineSource {
|
|||
nsString GetGroupId() const override;
|
||||
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) override;
|
||||
void SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
const PrincipalHandle& aPrincipal) override;
|
||||
|
|
|
@ -192,7 +192,8 @@ nsString MediaEngineRemoteVideoSource::GetGroupId() const {
|
|||
|
||||
nsresult MediaEngineRemoteVideoSource::Allocate(
|
||||
const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
|
||||
uint64_t aWindowID, const char** aOutBadConstraint) {
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) {
|
||||
LOG("%s", __PRETTY_FUNCTION__);
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
|
@ -215,7 +216,7 @@ nsresult MediaEngineRemoteVideoSource::Allocate(
|
|||
|
||||
if (camera::GetChildAndCall(&camera::CamerasChild::AllocateCaptureDevice,
|
||||
mCapEngine, mUniqueId.get(), kMaxUniqueIdLength,
|
||||
mCaptureIndex, aWindowID)) {
|
||||
mCaptureIndex, aPrincipalInfo)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,8 @@ class MediaEngineRemoteVideoSource : public MediaEngineSource,
|
|||
// MediaEngineSource
|
||||
dom::MediaSourceEnum GetMediaSource() const override;
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) override;
|
||||
nsresult Deallocate() override;
|
||||
void SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
|
|
|
@ -109,7 +109,8 @@ class MediaEngineSourceInterface {
|
|||
* Called by MediaEngine to allocate an instance of this source.
|
||||
*/
|
||||
virtual nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) = 0;
|
||||
|
||||
/**
|
||||
|
|
|
@ -127,7 +127,8 @@ nsString MediaEngineTabVideoSource::GetGroupId() const {
|
|||
|
||||
nsresult MediaEngineTabVideoSource::Allocate(
|
||||
const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ class MediaEngineTabVideoSource : public MediaEngineSource {
|
|||
}
|
||||
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) override;
|
||||
nsresult Deallocate() override;
|
||||
void SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
|
|
|
@ -370,7 +370,7 @@ void MediaEngineWebRTCMicrophoneSource::ApplySettings(
|
|||
|
||||
nsresult MediaEngineWebRTCMicrophoneSource::Allocate(
|
||||
const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs, const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@ class MediaEngineWebRTCMicrophoneSource : public MediaEngineSource {
|
|||
nsString GetGroupId() const override;
|
||||
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) override;
|
||||
nsresult Deallocate() override;
|
||||
void SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
|
@ -277,7 +278,8 @@ class MediaEngineWebRTCAudioCaptureSource : public MediaEngineSource {
|
|||
nsCString GetUUID() const override;
|
||||
nsString GetGroupId() const override;
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const char** aOutBadConstraint) override {
|
||||
// Nothing to do here, everything is managed in MediaManager.cpp
|
||||
return NS_OK;
|
||||
|
|
|
@ -21,7 +21,7 @@ add_task(async function test_notifications_permission() {
|
|||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
// Set pref to exercise relevant code path for regression test.
|
||||
["permissions.delegation.enabled", true],
|
||||
["permissions.delegation.enable", true],
|
||||
// Automatically dismiss the permission request when it appears.
|
||||
["dom.webnotifications.requireuserinteraction", true],
|
||||
],
|
||||
|
|
|
@ -231,7 +231,7 @@
|
|||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["permissions.delegation.enabled", true],
|
||||
["permissions.delegation.enable", true],
|
||||
]}).then(nextTest);
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -24,7 +24,7 @@ add_task(async function testNoPermissionPrompt() {
|
|||
{
|
||||
set: [
|
||||
["dom.security.featurePolicy.enabled", true],
|
||||
["permissions.delegation.enabled", true],
|
||||
["permissions.delegation.enable", true],
|
||||
["dom.security.featurePolicy.header.enabled", true],
|
||||
["dom.security.featurePolicy.webidl.enabled", true],
|
||||
],
|
||||
|
|
|
@ -32,20 +32,9 @@ void FeaturePolicy::InheritPolicy(FeaturePolicy* aParentPolicy) {
|
|||
|
||||
RefPtr<FeaturePolicy> dest = this;
|
||||
RefPtr<FeaturePolicy> src = aParentPolicy;
|
||||
|
||||
// Inherit origins which explicitly declared policy in chain
|
||||
for (const Feature& featureInChain :
|
||||
aParentPolicy->mDeclaredFeaturesInAncestorChain) {
|
||||
dest->AppendToDeclaredAllowInAncestorChain(featureInChain);
|
||||
}
|
||||
|
||||
FeaturePolicyUtils::ForEachFeature([dest, src](const char* aFeatureName) {
|
||||
nsString featureName;
|
||||
featureName.AppendASCII(aFeatureName);
|
||||
// Store unsafe allows all (allow=*)
|
||||
if (src->HasFeatureUnsafeAllowsAll(featureName)) {
|
||||
dest->mParentAllowedAllFeatures.AppendElement(featureName);
|
||||
}
|
||||
|
||||
// If the destination has a declared feature (via the HTTP header or 'allow'
|
||||
// attribute) we allow the feature if the destination allows it and the
|
||||
|
@ -87,38 +76,6 @@ bool FeaturePolicy::HasDeclaredFeature(const nsAString& aFeatureName) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool FeaturePolicy::HasFeatureUnsafeAllowsAll(
|
||||
const nsAString& aFeatureName) const {
|
||||
for (const Feature& feature : mFeatures) {
|
||||
if (feature.AllowsAll() && feature.Name().Equals(aFeatureName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// We should look into parent too (for example, document of iframe which
|
||||
// allows all, would be unsafe)
|
||||
return mParentAllowedAllFeatures.Contains(aFeatureName);
|
||||
}
|
||||
|
||||
void FeaturePolicy::AppendToDeclaredAllowInAncestorChain(
|
||||
const Feature& aFeature) {
|
||||
for (Feature& featureInChain : mDeclaredFeaturesInAncestorChain) {
|
||||
if (featureInChain.Name().Equals(aFeature.Name())) {
|
||||
MOZ_ASSERT(featureInChain.HasAllowList());
|
||||
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> list;
|
||||
aFeature.GetAllowList(list);
|
||||
|
||||
for (nsIPrincipal* principal : list) {
|
||||
featureInChain.AppendToAllowList(principal);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mDeclaredFeaturesInAncestorChain.AppendElement(aFeature);
|
||||
}
|
||||
|
||||
void FeaturePolicy::SetDeclaredPolicy(Document* aDocument,
|
||||
const nsAString& aPolicyString,
|
||||
nsIPrincipal* aSelfOrigin,
|
||||
|
@ -131,13 +88,6 @@ void FeaturePolicy::SetDeclaredPolicy(Document* aDocument,
|
|||
|
||||
Unused << NS_WARN_IF(!FeaturePolicyParser::ParseString(
|
||||
aPolicyString, aDocument, aSelfOrigin, aSrcOrigin, mFeatures));
|
||||
|
||||
// Only store explicitly declared allowlist
|
||||
for (const Feature& feature : mFeatures) {
|
||||
if (feature.HasAllowList()) {
|
||||
AppendToDeclaredAllowInAncestorChain(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FeaturePolicy::ResetDeclaredPolicy() {
|
||||
|
@ -145,7 +95,6 @@ void FeaturePolicy::ResetDeclaredPolicy() {
|
|||
mDeclaredString.Truncate();
|
||||
mSelfOrigin = nullptr;
|
||||
mSrcOrigin = nullptr;
|
||||
mDeclaredFeaturesInAncestorChain.Clear();
|
||||
}
|
||||
|
||||
JSObject* FeaturePolicy::WrapObject(JSContext* aCx,
|
||||
|
@ -175,19 +124,6 @@ bool FeaturePolicy::AllowsFeature(const nsAString& aFeatureName,
|
|||
return AllowsFeatureInternal(aFeatureName, origin);
|
||||
}
|
||||
|
||||
bool FeaturePolicy::AllowsFeatureExplicitlyInAncestorChain(
|
||||
const nsAString& aFeatureName, nsIPrincipal* aOrigin) const {
|
||||
MOZ_ASSERT(aOrigin);
|
||||
|
||||
for (const Feature& feature : mDeclaredFeaturesInAncestorChain) {
|
||||
if (feature.Name().Equals(aFeatureName)) {
|
||||
return feature.AllowListContains(aOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FeaturePolicy::AllowsFeatureInternal(const nsAString& aFeatureName,
|
||||
nsIPrincipal* aOrigin) const {
|
||||
MOZ_ASSERT(aOrigin);
|
||||
|
|
|
@ -101,20 +101,6 @@ class FeaturePolicy final : public nsISupports, public nsWrapperCache {
|
|||
// policy.
|
||||
void ResetDeclaredPolicy();
|
||||
|
||||
// This method appends a feature to in-chain declared allowlist. If the name's
|
||||
// feature existed in the list, we only need to append the allowlist of new
|
||||
// feature to the existed one.
|
||||
void AppendToDeclaredAllowInAncestorChain(const Feature& aFeature);
|
||||
|
||||
// This method returns true if aFeatureName is declared as "*" (allow all)
|
||||
// in parent.
|
||||
bool HasFeatureUnsafeAllowsAll(const nsAString& aFeatureName) const;
|
||||
|
||||
// This method returns true if the aFeatureName is allowed for aOrigin
|
||||
// explicitly in ancestor chain,
|
||||
bool AllowsFeatureExplicitlyInAncestorChain(const nsAString& aFeatureName,
|
||||
nsIPrincipal* aOrigin) const;
|
||||
|
||||
// WebIDL internal methods.
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
|
@ -173,14 +159,6 @@ class FeaturePolicy final : public nsISupports, public nsWrapperCache {
|
|||
// current context.
|
||||
nsTArray<nsString> mInheritedDeniedFeatureNames;
|
||||
|
||||
// This is set of feature names when the parent allows all for that feature.
|
||||
nsTArray<nsString> mParentAllowedAllFeatures;
|
||||
|
||||
// The explicitly declared policy contains allowlist as a set of origins
|
||||
// except 'none' and '*'. This set contains all explicitly declared policies
|
||||
// in ancestor chain
|
||||
nsTArray<Feature> mDeclaredFeaturesInAncestorChain;
|
||||
|
||||
// Feature policy for the current context.
|
||||
nsTArray<Feature> mFeatures;
|
||||
|
||||
|
|
|
@ -123,51 +123,6 @@ FeaturePolicyUtils::DefaultAllowListFeature(const nsAString& aFeatureName) {
|
|||
return FeaturePolicyValue::eNone;
|
||||
}
|
||||
|
||||
static bool IsSameOriginAsTop(Document* aDocument) {
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
BrowsingContext* browsingContext = aDocument->GetBrowsingContext();
|
||||
if (!browsingContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsPIDOMWindowOuter* topWindow = browsingContext->Top()->GetDOMWindow();
|
||||
if (!topWindow) {
|
||||
// If we don't have a DOMWindow, We are not in same origin.
|
||||
return false;
|
||||
}
|
||||
|
||||
Document* topLevelDocument = topWindow->GetExtantDoc();
|
||||
if (!topLevelDocument) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return NS_SUCCEEDED(
|
||||
nsContentUtils::CheckSameOrigin(topLevelDocument, aDocument));
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool FeaturePolicyUtils::IsFeatureUnsafeAllowedAll(
|
||||
Document* aDocument, const nsAString& aFeatureName) {
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
if (!StaticPrefs::dom_security_featurePolicy_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aDocument->IsHTMLDocument()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FeaturePolicy* policy = aDocument->FeaturePolicy();
|
||||
MOZ_ASSERT(policy);
|
||||
|
||||
return policy->HasFeatureUnsafeAllowsAll(aFeatureName) &&
|
||||
!policy->AllowsFeatureExplicitlyInAncestorChain(
|
||||
aFeatureName, policy->DefaultOrigin()) &&
|
||||
!IsSameOriginAsTop(aDocument);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool FeaturePolicyUtils::IsFeatureAllowed(Document* aDocument,
|
||||
const nsAString& aFeatureName) {
|
||||
|
|
|
@ -49,13 +49,6 @@ class FeaturePolicyUtils final {
|
|||
static FeaturePolicyValue DefaultAllowListFeature(
|
||||
const nsAString& aFeatureName);
|
||||
|
||||
// This method returns true if aFeatureName is in unsafe allowed "*" case.
|
||||
// We are in "unsafe" case when there is 'allow "*"' presents for an origin
|
||||
// that's not presented in the ancestor feature policy chain, via src, via
|
||||
// explicitly listed in allow, and not being the top-level origin.
|
||||
static bool IsFeatureUnsafeAllowedAll(Document* aDocument,
|
||||
const nsAString& aFeatureName);
|
||||
|
||||
private:
|
||||
static void ReportViolation(Document* aDocument,
|
||||
const nsAString& aFeatureName);
|
||||
|
|
|
@ -23,7 +23,6 @@ interface URI;
|
|||
interface nsIDocShell;
|
||||
interface nsILoadGroup;
|
||||
interface nsIReferrerInfo;
|
||||
interface nsIPermissionDelegateHandler;
|
||||
interface XULCommandDispatcher;
|
||||
|
||||
enum VisibilityState { "hidden", "visible" };
|
||||
|
@ -687,9 +686,3 @@ partial interface Document {
|
|||
[ChromeOnly, BinaryName="setUserHasInteracted"]
|
||||
void userInteractionForTesting();
|
||||
};
|
||||
|
||||
// Extension for permission delegation.
|
||||
partial interface Document {
|
||||
[Pref="permissions.delegation.enabled", ChromeOnly, Pure]
|
||||
readonly attribute nsIPermissionDelegateHandler permDelegateHandler;
|
||||
};
|
||||
|
|
|
@ -32,11 +32,6 @@ static const DelegateInfo sPermissionsMap[] = {
|
|||
DelegatePolicy::ePersistDeniedCrossOrigin},
|
||||
{"persistent-storage", nullptr, DelegatePolicy::ePersistDeniedCrossOrigin},
|
||||
{"vibration", nullptr, DelegatePolicy::ePersistDeniedCrossOrigin},
|
||||
{"midi", nullptr, DelegatePolicy::eDelegateUseIframeOrigin},
|
||||
{"storage-access", nullptr, DelegatePolicy::eDelegateUseIframeOrigin},
|
||||
{"camera", u"camera", DelegatePolicy::eDelegateUseFeaturePolicy},
|
||||
{"microphone", u"microphone", DelegatePolicy::eDelegateUseFeaturePolicy},
|
||||
{"screen", u"display-capture", DelegatePolicy::eDelegateUseFeaturePolicy},
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(PermissionDelegateHandler)
|
||||
|
@ -44,7 +39,6 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(PermissionDelegateHandler)
|
|||
NS_IMPL_CYCLE_COLLECTING_RELEASE(PermissionDelegateHandler)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PermissionDelegateHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPermissionDelegateHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
@ -53,9 +47,8 @@ PermissionDelegateHandler::PermissionDelegateHandler(dom::Document* aDocument)
|
|||
MOZ_ASSERT(aDocument);
|
||||
}
|
||||
|
||||
/* static */
|
||||
const DelegateInfo* PermissionDelegateHandler::GetPermissionDelegateInfo(
|
||||
const nsAString& aPermissionName) {
|
||||
const nsAString& aPermissionName) const {
|
||||
nsAutoString lowerContent(aPermissionName);
|
||||
ToLowerCase(lowerContent);
|
||||
|
||||
|
@ -68,57 +61,6 @@ const DelegateInfo* PermissionDelegateHandler::GetPermissionDelegateInfo(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PermissionDelegateHandler::MaybeUnsafePermissionDelegate(
|
||||
const nsTArray<nsCString>& aTypes, bool* aMaybeUnsafe) {
|
||||
*aMaybeUnsafe = false;
|
||||
if (!StaticPrefs::permissions_delegation_enabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
for (auto& type : aTypes) {
|
||||
const DelegateInfo* info =
|
||||
GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(type));
|
||||
if (!info) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString featureName(info->mFeatureName);
|
||||
if (FeaturePolicyUtils::IsFeatureUnsafeAllowedAll(mDocument, featureName)) {
|
||||
*aMaybeUnsafe = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult PermissionDelegateHandler::GetDelegatePrincipal(
|
||||
const nsACString& aType, nsIContentPermissionRequest* aRequest,
|
||||
nsIPrincipal** aResult) {
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
if (!StaticPrefs::permissions_delegation_enabled()) {
|
||||
return aRequest->GetPrincipal(aResult);
|
||||
}
|
||||
|
||||
const DelegateInfo* info =
|
||||
GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(aType));
|
||||
if (!info) {
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (info->mPolicy == DelegatePolicy::eDelegateUseTopOrigin ||
|
||||
(info->mPolicy == DelegatePolicy::eDelegateUseFeaturePolicy &&
|
||||
StaticPrefs::dom_security_featurePolicy_enabled())) {
|
||||
return aRequest->GetTopLevelPrincipal(aResult);
|
||||
}
|
||||
|
||||
return aRequest->GetPrincipal(aResult);
|
||||
}
|
||||
|
||||
bool PermissionDelegateHandler::Initialize() {
|
||||
MOZ_ASSERT(mDocument);
|
||||
|
||||
|
@ -144,21 +86,14 @@ static bool IsTopWindowContent(Document* aDocument) {
|
|||
return browsingContext && browsingContext->IsTopContent();
|
||||
}
|
||||
|
||||
bool PermissionDelegateHandler::HasFeaturePolicyAllowed(
|
||||
const DelegateInfo* info) const {
|
||||
if (info->mPolicy != DelegatePolicy::eDelegateUseFeaturePolicy ||
|
||||
!info->mFeatureName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoString featureName(info->mFeatureName);
|
||||
return FeaturePolicyUtils::IsFeatureAllowed(mDocument, featureName);
|
||||
}
|
||||
|
||||
bool PermissionDelegateHandler::HasPermissionDelegated(
|
||||
const nsACString& aType) {
|
||||
MOZ_ASSERT(mDocument);
|
||||
|
||||
if (!StaticPrefs::permissions_delegation_enable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// System principal should have right to make permission request
|
||||
if (mPrincipal->IsSystemPrincipal()) {
|
||||
return true;
|
||||
|
@ -166,12 +101,21 @@ bool PermissionDelegateHandler::HasPermissionDelegated(
|
|||
|
||||
const DelegateInfo* info =
|
||||
GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(aType));
|
||||
if (!info || !HasFeaturePolicyAllowed(info)) {
|
||||
|
||||
// If the type is not in the supported list, auto denied
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StaticPrefs::permissions_delegation_enabled()) {
|
||||
return true;
|
||||
if (info->mPolicy == DelegatePolicy::eDelegateUseFeaturePolicy &&
|
||||
info->mFeatureName) {
|
||||
nsAutoString featureName(info->mFeatureName);
|
||||
// Default allowlist for a feature used in permissions delegate should be
|
||||
// set to eSelf, to ensure that permission is denied by default and only
|
||||
// have the opportunity to request permission with allow attribute.
|
||||
if (!FeaturePolicyUtils::IsFeatureAllowed(mDocument, featureName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->mPolicy == DelegatePolicy::ePersistDeniedCrossOrigin &&
|
||||
|
@ -193,23 +137,37 @@ nsresult PermissionDelegateHandler::GetPermission(const nsACString& aType,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
const DelegateInfo* info =
|
||||
GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(aType));
|
||||
if (!info || !HasFeaturePolicyAllowed(info)) {
|
||||
*aPermission = nsIPermissionManager::DENY_ACTION;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult (NS_STDCALL nsIPermissionManager::*testPermission)(
|
||||
nsIPrincipal*, const nsACString&, uint32_t*) =
|
||||
aExactHostMatch ? &nsIPermissionManager::TestExactPermissionFromPrincipal
|
||||
: &nsIPermissionManager::TestPermissionFromPrincipal;
|
||||
|
||||
if (!StaticPrefs::permissions_delegation_enabled()) {
|
||||
if (!StaticPrefs::permissions_delegation_enable()) {
|
||||
return (mPermissionManager->*testPermission)(mPrincipal, aType,
|
||||
aPermission);
|
||||
}
|
||||
|
||||
const DelegateInfo* info =
|
||||
GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(aType));
|
||||
|
||||
// If the type is not in the supported list, auto denied
|
||||
if (!info) {
|
||||
*aPermission = nsIPermissionManager::DENY_ACTION;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (info->mPolicy == DelegatePolicy::eDelegateUseFeaturePolicy &&
|
||||
info->mFeatureName) {
|
||||
nsAutoString featureName(info->mFeatureName);
|
||||
// Default allowlist for a feature used in permissions delegate should be
|
||||
// set to eSelf, to ensure that permission is denied by default and only
|
||||
// have the opportunity to request permission with allow attribute.
|
||||
if (!FeaturePolicyUtils::IsFeatureAllowed(mDocument, featureName)) {
|
||||
*aPermission = nsIPermissionManager::DENY_ACTION;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->mPolicy == DelegatePolicy::ePersistDeniedCrossOrigin &&
|
||||
!IsTopWindowContent(mDocument) &&
|
||||
!mPrincipal->Subsumes(mTopLevelPrincipal)) {
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#define PermissionDelegateHandler_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIPermissionDelegateHandler.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIContentPermissionRequest;
|
||||
|
@ -38,16 +37,13 @@ class Document;
|
|||
}
|
||||
} // namespace mozilla
|
||||
|
||||
class PermissionDelegateHandler final : public nsIPermissionDelegateHandler {
|
||||
class PermissionDelegateHandler final : nsISupports {
|
||||
public:
|
||||
explicit PermissionDelegateHandler(mozilla::dom::Document* aDocument);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(PermissionDelegateHandler)
|
||||
|
||||
NS_DECL_NSIPERMISSIONDELEGATEHANDLER
|
||||
|
||||
explicit PermissionDelegateHandler() = default;
|
||||
explicit PermissionDelegateHandler(mozilla::dom::Document* aDocument);
|
||||
|
||||
bool Initialize();
|
||||
|
||||
/*
|
||||
|
@ -119,40 +115,15 @@ class PermissionDelegateHandler final : public nsIPermissionDelegateHandler {
|
|||
*/
|
||||
void DropDocumentReference() { mDocument = nullptr; }
|
||||
|
||||
private:
|
||||
virtual ~PermissionDelegateHandler() = default;
|
||||
|
||||
/*
|
||||
* Helper function to return the delegate info value for aPermissionName.
|
||||
* @param aPermissionName the permission name to get
|
||||
*/
|
||||
static const PermissionDelegateInfo* GetPermissionDelegateInfo(
|
||||
const nsAString& aPermissionName);
|
||||
|
||||
/*
|
||||
* Helper function to return the delegate principal. This will return nullptr,
|
||||
* or request's principal or top level principal based on the delegate policy
|
||||
* will be applied for a given type.
|
||||
* We use this function when prompting, no need to perform permission check
|
||||
* (deny/allow).
|
||||
*
|
||||
* @param aType the permission type to get
|
||||
* @param aRequest The request which the principal is get from.
|
||||
* @param aResult out argument which will be a principal that we
|
||||
* will return from this function.
|
||||
*/
|
||||
static nsresult GetDelegatePrincipal(const nsACString& aType,
|
||||
nsIContentPermissionRequest* aRequest,
|
||||
nsIPrincipal** aResult);
|
||||
|
||||
private:
|
||||
~PermissionDelegateHandler() = default;
|
||||
|
||||
/*
|
||||
* Check whether the permission is blocked by FeaturePolicy directive.
|
||||
* Default allowlist for a featureName of permission used in permissions
|
||||
* delegate should be set to eSelf, to ensure that permission is denied by
|
||||
* default and only have the opportunity to request permission with allow
|
||||
* attribute.
|
||||
*/
|
||||
bool HasFeaturePolicyAllowed(const PermissionDelegateInfo* info) const;
|
||||
const PermissionDelegateInfo* GetPermissionDelegateInfo(
|
||||
const nsAString& aPermissionName) const;
|
||||
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
mozilla::dom::Document* mDocument;
|
||||
|
|
|
@ -21,10 +21,4 @@ Classes = [
|
|||
'constructor': 'nsPermissionManager::GetXPCOMSingleton',
|
||||
'headers': ['/extensions/permissions/nsPermissionManager.h'],
|
||||
},
|
||||
{
|
||||
'cid': '{07611dc6-bf4d-4d8a-a64b-f3a5904dddc7}',
|
||||
'contract_ids': ['@mozilla.org/permissiondelegatehandler;1'],
|
||||
'type': 'PermissionDelegateHandler',
|
||||
'headers': ['/extensions/permissions/PermissionDelegateHandler.h'],
|
||||
},
|
||||
]
|
||||
|
|
|
@ -7002,7 +7002,7 @@
|
|||
# Prefs starting with "permissions."
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
- name: permissions.delegation.enabled
|
||||
- name: permissions.delegation.enable
|
||||
type: bool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
|
|
|
@ -1 +1 @@
|
|||
prefs: [permissions.delegation.enabled:true, dom.security.featurePolicy.enabled:true, dom.security.featurePolicy.header.enabled:true, dom.security.featurePolicy.webidl.enabled:true]
|
||||
prefs: [permissions.delegation.enable:true, dom.security.featurePolicy.enabled:true, dom.security.featurePolicy.header.enabled:true, dom.security.featurePolicy.webidl.enabled:true]
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
".popup-notification-description > b:last-of-type":
|
||||
"text=secondname,popupid",
|
||||
".popup-notification-description > span:last-of-type":
|
||||
"text=secondendlabel,popupid",
|
||||
"secondendlabel,popupid",
|
||||
".popup-notification-closebutton":
|
||||
"oncommand=closebuttoncommand,hidden=closebuttonhidden",
|
||||
".popup-notification-learnmore-link":
|
||||
|
|
|
@ -978,9 +978,6 @@ PopupNotifications.prototype = {
|
|||
if ("secondName" in desc && "secondEnd" in desc) {
|
||||
popupnotification.setAttribute("secondname", desc.secondName);
|
||||
popupnotification.setAttribute("secondendlabel", desc.secondEnd);
|
||||
} else {
|
||||
popupnotification.removeAttribute("secondname");
|
||||
popupnotification.removeAttribute("secondendlabel");
|
||||
}
|
||||
|
||||
popupnotification.setAttribute("id", popupnotificationID);
|
||||
|
|
Загрузка…
Ссылка в новой задаче