Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit cf86719

Browse files
author
Thomas Nguyen
committed
Bug 1560570- FeaturePolicy should be considered when permissions.query() is called r=baku,johannh
Differential Revision: https://phabricator.services.mozilla.com/D44210 --HG-- extra : moz-landing-system : lando
1 parent ced8047 commit cf86719

13 files changed

Lines changed: 597 additions & 6 deletions

dom/base/Document.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
#include "nsINSSErrorsService.h"
8484
#include "nsISocketProvider.h"
8585
#include "nsISiteSecurityService.h"
86+
#include "PermissionDelegateHandler.h"
8687

8788
#include "mozilla/AsyncEventDispatcher.h"
8889
#include "mozilla/BasicEvents.h"
@@ -1906,6 +1907,10 @@ Document::~Document() {
19061907
mXULPersist->DropDocumentReference();
19071908
}
19081909

1910+
if (mPermissionDelegateHandler) {
1911+
mPermissionDelegateHandler->DropDocumentReference();
1912+
}
1913+
19091914
delete mHeaderData;
19101915

19111916
mPendingTitleChangeEvent.Revoke();
@@ -15366,6 +15371,14 @@ void Document::AddResizeObserver(ResizeObserver* aResizeObserver) {
1536615371
mResizeObserverController->AddResizeObserver(aResizeObserver);
1536715372
}
1536815373

15374+
PermissionDelegateHandler* Document::GetPermissionDelegateHandler() {
15375+
if (!mPermissionDelegateHandler) {
15376+
mPermissionDelegateHandler =
15377+
mozilla::MakeAndAddRef<PermissionDelegateHandler>(this);
15378+
}
15379+
return mPermissionDelegateHandler;
15380+
}
15381+
1536915382
void Document::ScheduleResizeObserversNotification() const {
1537015383
if (!mResizeObserverController) {
1537115384
return;

dom/base/Document.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class nsIGlobalObject;
134134
class nsIXULWindow;
135135
class nsXULPrototypeDocument;
136136
class nsXULPrototypeElement;
137+
class PermissionDelegateHandler;
137138
struct nsFont;
138139

139140
namespace mozilla {
@@ -3970,6 +3971,9 @@ class Document : public nsINode,
39703971
void AddResizeObserver(ResizeObserver* aResizeObserver);
39713972
void ScheduleResizeObserversNotification() const;
39723973

3974+
// Getter for PermissionDelegateHandler. Performs lazy initialization.
3975+
PermissionDelegateHandler* GetPermissionDelegateHandler();
3976+
39733977
/**
39743978
* Localization
39753979
*
@@ -4596,6 +4600,10 @@ class Document : public nsINode,
45964600

45974601
UniquePtr<ResizeObserverController> mResizeObserverController;
45984602

4603+
// Permission Delegate Handler, lazily-initialized in
4604+
// PermissionDelegateHandler
4605+
RefPtr<PermissionDelegateHandler> mPermissionDelegateHandler;
4606+
45994607
// True if BIDI is enabled.
46004608
bool mBidiEnabled : 1;
46014609
// True if we may need to recompute the language prefs for this document.

dom/permission/PermissionStatus.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "PermissionObserver.h"
1313
#include "PermissionUtils.h"
1414
#include "nsPermission.h"
15+
#include "PermissionDelegateHandler.h"
1516

1617
namespace mozilla {
1718
namespace dom {
@@ -64,19 +65,22 @@ JSObject* PermissionStatus::WrapObject(JSContext* aCx,
6465
}
6566

6667
nsresult PermissionStatus::UpdateState() {
67-
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
68-
if (NS_WARN_IF(!permMgr)) {
68+
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
69+
if (NS_WARN_IF(!window)) {
6970
return NS_ERROR_FAILURE;
7071
}
7172

72-
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
73-
if (NS_WARN_IF(!window)) {
73+
RefPtr<Document> document = window->GetExtantDoc();
74+
if (NS_WARN_IF(!document)) {
7475
return NS_ERROR_FAILURE;
7576
}
7677

7778
uint32_t action = nsIPermissionManager::DENY_ACTION;
78-
nsresult rv = permMgr->TestPermissionFromWindow(
79-
window, PermissionNameToType(mName), &action);
79+
80+
PermissionDelegateHandler* permissionHandler =
81+
document->GetPermissionDelegateHandler();
82+
nsresult rv = permissionHandler->GetPermissionForPermissionsAPI(
83+
PermissionNameToType(mName), &action);
8084
if (NS_WARN_IF(NS_FAILED(rv))) {
8185
return rv;
8286
}

dom/permission/tests/mochitest.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
[DEFAULT]
22
support-files =
33
file_empty.html
4+
prefs =
5+
dom.security.featurePolicy.enabled=true
6+
dom.security.featurePolicy.header.enabled=true
7+
dom.security.featurePolicy.webidl.enabled=true
48

9+
[test_cross_origin_iframe.html]
510
[test_permissions_api.html]
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
<!--
2+
Any copyright is dedicated to the Public Domain.
3+
http://creativecommons.org/publicdomain/zero/1.0/
4+
-->
5+
<!DOCTYPE HTML>
6+
<html>
7+
8+
<head>
9+
<meta charset="utf-8">
10+
<title>Test for Permissions API</title>
11+
<script src="/tests/SimpleTest/SimpleTest.js"></script>
12+
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
13+
</head>
14+
15+
<body>
16+
<pre id="test"></pre>
17+
<script type="application/javascript">
18+
/*globals SpecialPowers, SimpleTest, is, ok, */
19+
'use strict';
20+
21+
function setPermission(type, allow) {
22+
return new Promise(resolve => {
23+
SpecialPowers.popPermissions(() => {
24+
SpecialPowers.pushPermissions(
25+
[{ type, allow, context: document }],
26+
resolve
27+
);
28+
});
29+
});
30+
}
31+
32+
function checkPermission(aWindow, aExpectedState, aName) {
33+
return SpecialPowers.wrap(aWindow).navigator.permissions
34+
.query({ name: aName })
35+
.then(
36+
result => is(SpecialPowers.wrap(result).state, aExpectedState, `correct state for '${aName}'`),
37+
() => ok(false, `query should not have rejected for '${aName}'`)
38+
);
39+
}
40+
41+
function createIframe(aId, aAllow) {
42+
return new Promise((resolve) => {
43+
const iframe = document.createElement('iframe');
44+
iframe.id = aId;
45+
iframe.src = 'https://example.org/tests/dom/permission/tests/file_empty.html';
46+
if (aAllow) {
47+
iframe.allow = aAllow;
48+
}
49+
iframe.onload = () => resolve(iframe.contentWindow);
50+
document.body.appendChild(iframe);
51+
});
52+
}
53+
54+
function removeIframe(aId) {
55+
return new Promise((resolve) => {
56+
document.body.removeChild(document.getElementById(aId));
57+
resolve();
58+
});
59+
}
60+
61+
const {
62+
UNKNOWN_ACTION,
63+
PROMPT_ACTION,
64+
ALLOW_ACTION,
65+
DENY_ACTION
66+
} = SpecialPowers.Ci.nsIPermissionManager;
67+
68+
const tests = [
69+
{
70+
id: 'query navigation top unknown',
71+
top: UNKNOWN_ACTION,
72+
name: 'geolocation',
73+
type: 'geo',
74+
expected: 'denied',
75+
},
76+
{
77+
id: 'query notifications top unknown',
78+
top: UNKNOWN_ACTION,
79+
name: 'notifications',
80+
type: 'desktop-notification',
81+
expected: 'denied',
82+
},
83+
{
84+
id: 'query push top unknown',
85+
top: UNKNOWN_ACTION,
86+
name: 'push',
87+
type: 'desktop-notification',
88+
expected: 'denied',
89+
},
90+
{
91+
id: 'query persistent-storage unknown',
92+
top: UNKNOWN_ACTION,
93+
name: 'persistent-storage',
94+
type: 'persistent-storage',
95+
expected: 'prompt',
96+
},
97+
{
98+
id: 'query navigation top prompt',
99+
top: PROMPT_ACTION,
100+
name: 'geolocation',
101+
type: 'geo',
102+
expected: 'denied',
103+
},
104+
{
105+
id: 'query notifications top prompt',
106+
top: PROMPT_ACTION,
107+
name: 'notifications',
108+
type: 'desktop-notification',
109+
expected: 'denied',
110+
},
111+
{
112+
id: 'query push top prompt',
113+
top: PROMPT_ACTION,
114+
name: 'push',
115+
type: 'desktop-notification',
116+
expected: 'denied',
117+
},
118+
{
119+
id: 'query persistent-storage top prompt',
120+
top: PROMPT_ACTION,
121+
name: 'persistent-storage',
122+
type: 'persistent-storage',
123+
expected: 'prompt',
124+
},
125+
{
126+
id: 'query navigation top denied',
127+
top: DENY_ACTION,
128+
name: 'geolocation',
129+
type: 'geo',
130+
expected: 'denied',
131+
},
132+
{
133+
id: 'query notifications top denied',
134+
top: DENY_ACTION,
135+
name: 'notifications',
136+
type: 'desktop-notification',
137+
expected: 'denied',
138+
},
139+
{
140+
id: 'query push top denied',
141+
top: DENY_ACTION,
142+
name: 'push',
143+
type: 'desktop-notification',
144+
expected: 'denied',
145+
},
146+
{
147+
id: 'query persistent-storage top denied',
148+
top: DENY_ACTION,
149+
name: 'persistent-storage',
150+
type: 'persistent-storage',
151+
expected: 'prompt',
152+
},
153+
{
154+
id: 'query navigation top granted',
155+
top: ALLOW_ACTION,
156+
name: 'geolocation',
157+
type: 'geo',
158+
expected: 'denied',
159+
},
160+
{
161+
id: 'query notifications top granted',
162+
top: ALLOW_ACTION,
163+
name: 'notifications',
164+
type: 'desktop-notification',
165+
expected: 'denied',
166+
},
167+
{
168+
id: 'query push top granted',
169+
top: ALLOW_ACTION,
170+
name: 'push',
171+
type: 'desktop-notification',
172+
expected: 'denied',
173+
},
174+
{
175+
id: 'query persistent-storage top granted',
176+
top: ALLOW_ACTION,
177+
name: 'persistent-storage',
178+
type: 'persistent-storage',
179+
expected: 'prompt',
180+
},
181+
{
182+
id: 'query navigation top denied, iframe has allow attribute',
183+
top: DENY_ACTION,
184+
allow: 'geolocation',
185+
name: 'geolocation',
186+
type: 'geo',
187+
expected: 'denied',
188+
},
189+
{
190+
id: 'query navigation top granted, iframe has allow attribute',
191+
top: ALLOW_ACTION,
192+
allow: 'geolocation',
193+
name: 'geolocation',
194+
type: 'geo',
195+
expected: 'granted',
196+
},
197+
{
198+
id: 'query navigation top prompt, iframe has allow attribute',
199+
top: PROMPT_ACTION,
200+
allow: 'geolocation',
201+
name: 'geolocation',
202+
type: 'geo',
203+
expected: 'prompt',
204+
},
205+
{
206+
id: 'query navigation top unknown, iframe has allow attribute',
207+
top: UNKNOWN_ACTION,
208+
allow: 'geolocation',
209+
name: 'geolocation',
210+
type: 'geo',
211+
expected: 'prompt',
212+
},
213+
214+
];
215+
216+
SimpleTest.waitForExplicitFinish();
217+
218+
async function nextTest() {
219+
if (tests.length == 0) {
220+
SimpleTest.finish();
221+
return;
222+
}
223+
224+
let test = tests.shift();
225+
await setPermission(test.type, test.top)
226+
.then(() => createIframe(test.id, test.allow))
227+
.then(contentWindow => checkPermission(contentWindow, test.expected, test.name))
228+
.then(() => removeIframe(test.id));
229+
230+
SimpleTest.executeSoon(nextTest);
231+
}
232+
233+
SpecialPowers.pushPrefEnv({"set": [
234+
["permissions.delegation.enable", true],
235+
]}).then(nextTest);
236+
</script>
237+
</body>
238+
239+
</html>

0 commit comments

Comments
 (0)