Backed out 4 changesets (bug 1483631) for failing at browser_temporary_permissions.js on a CLOSED TREE.

Backed out changeset f5bb5f6a148f (bug 1483631)
Backed out changeset c5e562c1d590 (bug 1483631)
Backed out changeset 7ef09193a7ef (bug 1483631)
Backed out changeset a909dcbbea2b (bug 1483631)
This commit is contained in:
Gurzau Raul 2019-12-03 21:57:55 +02:00
Родитель 2eee21b4c3
Коммит 4f21dcd081
66 изменённых файлов: 297 добавлений и 1775 удалений

Просмотреть файл

@ -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=Dont 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 tabs audio and see your screen?
getUserMedia.shareAudioCapture2.message = Will you allow %S to listen to this tabs 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 tabs 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 tabs 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);