1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/permissions/permission_util.h"
7 #include "base/check.h"
8 #include "base/feature_list.h"
9 #include "base/notreached.h"
10 #include "build/build_config.h"
11 #include "build/chromeos_buildflags.h"
12 #include "components/content_settings/core/common/content_settings_types.h"
13 #include "components/permissions/features.h"
14 #include "components/permissions/permission_request.h"
15 #include "components/permissions/permissions_client.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/permission_result.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "third_party/blink/public/common/permissions/permission_utils.h"
22 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
23 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
25 #include "url/origin.h"
27 using blink::PermissionType;
29 namespace permissions {
32 // Represents the possible methods of delegating permissions from main frames
34 enum class PermissionDelegationMode {
35 // Permissions from the main frame are delegated to child frames.
36 // This is the default delegation mode for permissions. If a main frame was
37 // granted a permission that is delegated, its child frames will inherit that
38 // permission if allowed by the permissions policy.
40 // Permissions from the main frame are not delegated to child frames.
41 // An undelegated permission will only be granted to a child frame if the
42 // child frame's origin was previously granted access to the permission when
45 // Permission access is a function of both the requesting and embedding
50 PermissionDelegationMode GetPermissionDelegationMode(
51 ContentSettingsType permission) {
52 // TODO(crbug.com/987654): Generalize this to other "background permissions",
53 // that is, permissions that can be used by a service worker. This includes
54 // durable storage, background sync, etc.
55 if (permission == ContentSettingsType::NOTIFICATIONS)
56 return PermissionDelegationMode::kUndelegated;
57 if (permission == ContentSettingsType::STORAGE_ACCESS ||
58 permission == ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS) {
59 return PermissionDelegationMode::kDoubleKeyed;
61 return PermissionDelegationMode::kDelegated;
65 // The returned strings must match any Field Trial configs for the Permissions
66 // kill switch e.g. Permissions.Action.Geolocation etc..
67 std::string PermissionUtil::GetPermissionString(
68 ContentSettingsType content_type) {
69 PermissionType permission;
70 bool success = PermissionUtil::GetPermissionType(content_type, &permission);
73 return blink::GetPermissionString(permission);
76 PermissionRequestGestureType PermissionUtil::GetGestureType(bool user_gesture) {
77 return user_gesture ? PermissionRequestGestureType::GESTURE
78 : PermissionRequestGestureType::NO_GESTURE;
81 absl::optional<blink::mojom::PermissionsPolicyFeature>
82 PermissionUtil::GetPermissionsPolicyFeature(ContentSettingsType permission) {
83 PermissionType permission_type;
85 PermissionUtil::GetPermissionType(permission, &permission_type);
88 ? blink::PermissionTypeToPermissionsPolicyFeature(permission_type)
92 bool PermissionUtil::GetPermissionType(ContentSettingsType type,
93 PermissionType* out) {
95 case ContentSettingsType::GEOLOCATION:
96 *out = PermissionType::GEOLOCATION;
98 case ContentSettingsType::NOTIFICATIONS:
99 *out = PermissionType::NOTIFICATIONS;
101 case ContentSettingsType::MIDI:
102 *out = PermissionType::MIDI;
104 case ContentSettingsType::MIDI_SYSEX:
105 *out = PermissionType::MIDI_SYSEX;
107 case ContentSettingsType::DURABLE_STORAGE:
108 *out = PermissionType::DURABLE_STORAGE;
110 case ContentSettingsType::MEDIASTREAM_CAMERA:
111 *out = PermissionType::VIDEO_CAPTURE;
113 case ContentSettingsType::MEDIASTREAM_MIC:
114 *out = PermissionType::AUDIO_CAPTURE;
116 case ContentSettingsType::BACKGROUND_SYNC:
117 *out = PermissionType::BACKGROUND_SYNC;
119 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || \
120 BUILDFLAG(IS_FUCHSIA)
121 case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER:
122 *out = PermissionType::PROTECTED_MEDIA_IDENTIFIER;
125 case ContentSettingsType::SENSORS:
126 *out = PermissionType::SENSORS;
128 case ContentSettingsType::ACCESSIBILITY_EVENTS:
129 *out = PermissionType::ACCESSIBILITY_EVENTS;
131 case ContentSettingsType::CLIPBOARD_READ_WRITE:
132 *out = PermissionType::CLIPBOARD_READ_WRITE;
134 case ContentSettingsType::CLIPBOARD_SANITIZED_WRITE:
135 *out = PermissionType::CLIPBOARD_SANITIZED_WRITE;
137 case ContentSettingsType::PAYMENT_HANDLER:
138 *out = PermissionType::PAYMENT_HANDLER;
140 case ContentSettingsType::BACKGROUND_FETCH:
141 *out = PermissionType::BACKGROUND_FETCH;
143 case ContentSettingsType::PERIODIC_BACKGROUND_SYNC:
144 *out = PermissionType::PERIODIC_BACKGROUND_SYNC;
146 case ContentSettingsType::WAKE_LOCK_SCREEN:
147 *out = PermissionType::WAKE_LOCK_SCREEN;
149 case ContentSettingsType::WAKE_LOCK_SYSTEM:
150 *out = PermissionType::WAKE_LOCK_SYSTEM;
152 case ContentSettingsType::NFC:
153 *out = PermissionType::NFC;
155 case ContentSettingsType::VR:
156 *out = PermissionType::VR;
158 case ContentSettingsType::AR:
159 *out = PermissionType::AR;
161 case ContentSettingsType::STORAGE_ACCESS:
162 *out = PermissionType::STORAGE_ACCESS_GRANT;
164 case ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS:
165 *out = PermissionType::TOP_LEVEL_STORAGE_ACCESS;
167 case ContentSettingsType::CAMERA_PAN_TILT_ZOOM:
168 *out = PermissionType::CAMERA_PAN_TILT_ZOOM;
170 case ContentSettingsType::WINDOW_MANAGEMENT:
171 *out = PermissionType::WINDOW_MANAGEMENT;
173 case ContentSettingsType::LOCAL_FONTS:
174 *out = PermissionType::LOCAL_FONTS;
176 case ContentSettingsType::IDLE_DETECTION:
177 *out = PermissionType::IDLE_DETECTION;
179 case ContentSettingsType::DISPLAY_CAPTURE:
180 *out = PermissionType::DISPLAY_CAPTURE;
188 bool PermissionUtil::IsPermission(ContentSettingsType type) {
189 PermissionType permission;
190 return PermissionUtil::GetPermissionType(type, &permission);
193 bool PermissionUtil::IsLowPriorityPermissionRequest(
194 const PermissionRequest* request) {
195 return request->request_type() == RequestType::kNotifications ||
196 request->request_type() == RequestType::kGeolocation;
199 bool PermissionUtil::IsGuardContentSetting(ContentSettingsType type) {
201 case ContentSettingsType::USB_GUARD:
202 case ContentSettingsType::SERIAL_GUARD:
203 case ContentSettingsType::BLUETOOTH_GUARD:
204 case ContentSettingsType::BLUETOOTH_SCANNING:
205 case ContentSettingsType::FILE_SYSTEM_WRITE_GUARD:
206 case ContentSettingsType::HID_GUARD:
213 bool PermissionUtil::CanPermissionBeAllowedOnce(ContentSettingsType type) {
215 case ContentSettingsType::GEOLOCATION:
216 case ContentSettingsType::MEDIASTREAM_MIC:
217 case ContentSettingsType::MEDIASTREAM_CAMERA:
218 return base::FeatureList::IsEnabled(
219 permissions::features::kOneTimePermission);
225 // Due to dependency issues, this method is duplicated in
226 // content/browser/permissions/permission_util.cc.
227 GURL PermissionUtil::GetLastCommittedOriginAsURL(
228 content::RenderFrameHost* render_frame_host) {
229 DCHECK(render_frame_host);
231 #if BUILDFLAG(IS_ANDROID)
232 content::WebContents* web_contents =
233 content::WebContents::FromRenderFrameHost(render_frame_host);
234 // If `allow_universal_access_from_file_urls` flag is enabled, a file:/// can
235 // change its url via history.pushState/replaceState to any other url,
236 // including about:blank. To avoid user confusion we should always use a
237 // visible url, in other words `GetLastCommittedURL`.
238 if (web_contents->GetOrCreateWebPreferences()
239 .allow_universal_access_from_file_urls &&
240 render_frame_host->GetLastCommittedOrigin().GetURL().SchemeIsFile()) {
241 return render_frame_host->GetLastCommittedURL().DeprecatedGetOriginAsURL();
245 return render_frame_host->GetLastCommittedOrigin().GetURL();
248 ContentSettingsType PermissionUtil::PermissionTypeToContentSettingTypeSafe(
249 PermissionType permission) {
250 switch (permission) {
251 case PermissionType::MIDI:
252 return ContentSettingsType::MIDI;
253 case PermissionType::MIDI_SYSEX:
254 return ContentSettingsType::MIDI_SYSEX;
255 case PermissionType::NOTIFICATIONS:
256 return ContentSettingsType::NOTIFICATIONS;
257 case PermissionType::GEOLOCATION:
258 return ContentSettingsType::GEOLOCATION;
259 case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
260 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || \
261 BUILDFLAG(IS_FUCHSIA)
262 return ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER;
266 case PermissionType::DURABLE_STORAGE:
267 return ContentSettingsType::DURABLE_STORAGE;
268 case PermissionType::AUDIO_CAPTURE:
269 return ContentSettingsType::MEDIASTREAM_MIC;
270 case PermissionType::VIDEO_CAPTURE:
271 return ContentSettingsType::MEDIASTREAM_CAMERA;
272 case PermissionType::BACKGROUND_SYNC:
273 return ContentSettingsType::BACKGROUND_SYNC;
274 case PermissionType::SENSORS:
275 return ContentSettingsType::SENSORS;
276 case PermissionType::ACCESSIBILITY_EVENTS:
277 return ContentSettingsType::ACCESSIBILITY_EVENTS;
278 case PermissionType::CLIPBOARD_READ_WRITE:
279 return ContentSettingsType::CLIPBOARD_READ_WRITE;
280 case PermissionType::CLIPBOARD_SANITIZED_WRITE:
281 return ContentSettingsType::CLIPBOARD_SANITIZED_WRITE;
282 case PermissionType::PAYMENT_HANDLER:
283 return ContentSettingsType::PAYMENT_HANDLER;
284 case PermissionType::BACKGROUND_FETCH:
285 return ContentSettingsType::BACKGROUND_FETCH;
286 case PermissionType::IDLE_DETECTION:
287 return ContentSettingsType::IDLE_DETECTION;
288 case PermissionType::PERIODIC_BACKGROUND_SYNC:
289 return ContentSettingsType::PERIODIC_BACKGROUND_SYNC;
290 case PermissionType::WAKE_LOCK_SCREEN:
291 return ContentSettingsType::WAKE_LOCK_SCREEN;
292 case PermissionType::WAKE_LOCK_SYSTEM:
293 return ContentSettingsType::WAKE_LOCK_SYSTEM;
294 case PermissionType::NFC:
295 return ContentSettingsType::NFC;
296 case PermissionType::VR:
297 return ContentSettingsType::VR;
298 case PermissionType::AR:
299 return ContentSettingsType::AR;
300 case PermissionType::STORAGE_ACCESS_GRANT:
301 return ContentSettingsType::STORAGE_ACCESS;
302 case PermissionType::TOP_LEVEL_STORAGE_ACCESS:
303 return ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS;
304 case PermissionType::CAMERA_PAN_TILT_ZOOM:
305 return ContentSettingsType::CAMERA_PAN_TILT_ZOOM;
306 case PermissionType::WINDOW_MANAGEMENT:
307 return ContentSettingsType::WINDOW_MANAGEMENT;
308 case PermissionType::LOCAL_FONTS:
309 return ContentSettingsType::LOCAL_FONTS;
310 case PermissionType::DISPLAY_CAPTURE:
311 return ContentSettingsType::DISPLAY_CAPTURE;
312 case PermissionType::NUM:
316 return ContentSettingsType::DEFAULT;
319 ContentSettingsType PermissionUtil::PermissionTypeToContentSettingType(
320 PermissionType permission) {
321 ContentSettingsType content_setting =
322 PermissionTypeToContentSettingTypeSafe(permission);
323 DCHECK_NE(content_setting, ContentSettingsType::DEFAULT)
324 << "Unknown content setting for permission "
325 << static_cast<int>(permission);
326 return content_setting;
329 PermissionType PermissionUtil::ContentSettingTypeToPermissionType(
330 ContentSettingsType permission) {
331 PermissionType permission_type;
333 PermissionUtil::GetPermissionType(permission, &permission_type);
336 return permission_type;
339 ContentSetting PermissionUtil::PermissionStatusToContentSetting(
340 blink::mojom::PermissionStatus status) {
342 case blink::mojom::PermissionStatus::GRANTED:
343 return CONTENT_SETTING_ALLOW;
344 case blink::mojom::PermissionStatus::ASK:
345 return CONTENT_SETTING_ASK;
346 case blink::mojom::PermissionStatus::DENIED:
348 return CONTENT_SETTING_BLOCK;
352 return CONTENT_SETTING_DEFAULT;
355 blink::mojom::PermissionStatus PermissionUtil::ContentSettingToPermissionStatus(
356 ContentSetting setting) {
358 case CONTENT_SETTING_ALLOW:
359 return blink::mojom::PermissionStatus::GRANTED;
360 case CONTENT_SETTING_BLOCK:
361 return blink::mojom::PermissionStatus::DENIED;
362 case CONTENT_SETTING_ASK:
363 return blink::mojom::PermissionStatus::ASK;
364 case CONTENT_SETTING_SESSION_ONLY:
365 case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT:
366 case CONTENT_SETTING_DEFAULT:
367 case CONTENT_SETTING_NUM_SETTINGS:
372 return blink::mojom::PermissionStatus::DENIED;
375 bool PermissionUtil::IsPermissionBlockedInPartition(
376 ContentSettingsType permission,
377 const GURL& requesting_origin,
378 content::RenderProcessHost* render_process_host) {
379 DCHECK(render_process_host);
380 switch (GetPermissionDelegationMode(permission)) {
381 case PermissionDelegationMode::kDelegated:
383 case PermissionDelegationMode::kDoubleKeyed:
385 case PermissionDelegationMode::kUndelegated:
386 // TODO(crbug.com/1312218): This will create |requesting_origin|'s home
387 // StoragePartition if it doesn't already exist. Given how
388 // StoragePartitions are used today, this shouldn't actually be a
389 // problem, but ideally we'd compare StoragePartitionConfigs.
390 content::StoragePartition* requesting_home_partition =
391 render_process_host->GetBrowserContext()->GetStoragePartitionForUrl(
393 return requesting_home_partition !=
394 render_process_host->GetStoragePartition();
398 GURL PermissionUtil::GetCanonicalOrigin(ContentSettingsType permission,
399 const GURL& requesting_origin,
400 const GURL& embedding_origin) {
401 absl::optional<GURL> override_origin =
402 PermissionsClient::Get()->OverrideCanonicalOrigin(requesting_origin,
405 return override_origin.value();
407 switch (GetPermissionDelegationMode(permission)) {
408 case PermissionDelegationMode::kDelegated:
409 return embedding_origin;
410 case PermissionDelegationMode::kDoubleKeyed:
411 case PermissionDelegationMode::kUndelegated:
412 return requesting_origin;
416 bool PermissionUtil::HasUserGesture(PermissionPrompt::Delegate* delegate) {
417 const std::vector<permissions::PermissionRequest*>& requests =
418 delegate->Requests();
420 requests.begin(), requests.end(),
421 [](permissions::PermissionRequest* request) {
422 return request->GetGestureType() ==
423 permissions::PermissionRequestGestureType::GESTURE;
427 bool PermissionUtil::CanPermissionRequestIgnoreStatus(
428 const PermissionRequestData& request,
429 content::PermissionStatusSource source) {
430 if (!request.embedded_permission_element_initiated) {
435 case content::PermissionStatusSource::KILL_SWITCH:
436 case content::PermissionStatusSource::FEATURE_POLICY:
437 case content::PermissionStatusSource::FENCED_FRAME:
438 case content::PermissionStatusSource::INSECURE_ORIGIN:
439 case content::PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN:
440 case content::PermissionStatusSource::PORTAL:
442 case content::PermissionStatusSource::MULTIPLE_DISMISSALS:
443 case content::PermissionStatusSource::MULTIPLE_IGNORES:
444 case content::PermissionStatusSource::RECENT_DISPLAY:
445 case content::PermissionStatusSource::UNSPECIFIED:
453 bool PermissionUtil::DoesPlatformSupportChip() {
454 #if BUILDFLAG(IS_ANDROID)
461 } // namespace permissions