blob: 8af9381691776fd7968cab890e32546c285979e4 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2018 The Chromium Authors
Andrey Lushnikovebff0442018-07-12 20:02:582// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Andrey Lushnikovebff0442018-07-12 20:02:585#include "content/browser/permissions/permission_controller_impl.h"
Thomas Nguyen5fe19272022-12-15 10:38:006
jalonthomasb3f862a2025-07-22 16:02:237#include <optional>
Peter Kasting472500482024-11-21 18:36:258#include <string>
9
Avi Drissmanadac21992023-01-11 23:46:3910#include "base/functional/bind.h"
Illia Klimove406ecc12022-11-22 15:53:2911#include "content/browser/permissions/permission_service_context.h"
Illia Klimov7709f0ce2021-07-05 09:42:3912#include "content/browser/permissions/permission_util.h"
danakj22c9ee22020-09-16 16:37:2813#include "content/browser/renderer_host/render_frame_host_impl.h"
Andrey Lushnikovebff0442018-07-12 20:02:5814#include "content/public/browser/browser_context.h"
Illia Klimov9777bbb2022-10-11 11:02:0115#include "content/public/browser/disallow_activation_reason.h"
Sonja Laurilae9208bfe2022-08-22 13:38:4616#include "content/public/browser/permission_controller.h"
Andrey Lushnikovf3500102018-07-16 19:55:2217#include "content/public/browser/permission_controller_delegate.h"
Florian Jackya857d582025-04-10 10:13:3318#include "content/public/browser/permission_descriptor_util.h"
Illia Klimov15550f752022-08-11 19:33:1019#include "content/public/browser/permission_result.h"
Andrey Lushnikov36299bc2018-08-23 22:09:5420#include "content/public/browser/render_frame_host.h"
21#include "content/public/browser/render_process_host.h"
Illia Klimov9777bbb2022-10-11 11:02:0122#include "content/public/browser/web_contents.h"
Andy Paicua6d6d852022-04-28 18:08:3623#include "third_party/blink/public/common/permissions/permission_utils.h"
Illia Klimov9777bbb2022-10-11 11:02:0124#include "third_party/blink/public/common/web_preferences/web_preferences.h"
25#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
Julie Jeongeun Kim162c2d282019-03-13 07:23:5226#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
Matt Reichhoff56f62282022-09-12 20:36:0027#include "url/origin.h"
Andrey Lushnikovebff0442018-07-12 20:02:5828
Elias Klim1e5178a32023-12-12 21:15:2929#if !BUILDFLAG(IS_ANDROID)
30#include "content/common/features.h"
31#endif
32
Andrey Lushnikovebff0442018-07-12 20:02:5833namespace content {
34
Andrey Lushnikov36299bc2018-08-23 22:09:5435namespace {
36
Arthur Sonzognic686e8f2024-01-11 08:36:3737std::optional<blink::scheduler::WebSchedulerTrackedFeature>
Alexander Timin5afc73e2019-06-24 01:03:1038PermissionToSchedulingFeature(PermissionType permission_name) {
39 switch (permission_name) {
Alexander Timin5afc73e2019-06-24 01:03:1040 case PermissionType::MIDI:
41 case PermissionType::MIDI_SYSEX:
42 return blink::scheduler::WebSchedulerTrackedFeature::
43 kRequestedMIDIPermission;
44 case PermissionType::AUDIO_CAPTURE:
45 return blink::scheduler::WebSchedulerTrackedFeature::
46 kRequestedAudioCapturePermission;
47 case PermissionType::VIDEO_CAPTURE:
48 return blink::scheduler::WebSchedulerTrackedFeature::
49 kRequestedVideoCapturePermission;
Alexander Timin5afc73e2019-06-24 01:03:1050 case PermissionType::BACKGROUND_SYNC:
51 case PermissionType::BACKGROUND_FETCH:
52 case PermissionType::PERIODIC_BACKGROUND_SYNC:
53 return blink::scheduler::WebSchedulerTrackedFeature::
54 kRequestedBackgroundWorkPermission;
Brandon Maslen68e89bd2020-02-19 01:28:4555 case PermissionType::STORAGE_ACCESS_GRANT:
Matt Reichhoff2dbcfbd2023-01-03 17:48:3356 // These two permissions are in the process of being split; they share logic
Alison Gale47d1537d2024-04-19 21:31:4657 // for now. TODO(crbug.com/40246640): split and consolidate as much as
Matt Reichhoff2dbcfbd2023-01-03 17:48:3358 // possible.
59 case PermissionType::TOP_LEVEL_STORAGE_ACCESS:
Brandon Maslen68e89bd2020-02-19 01:28:4560 return blink::scheduler::WebSchedulerTrackedFeature::
61 kRequestedStorageAccessGrant;
Alexander Timin5afc73e2019-06-24 01:03:1062 case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
63 case PermissionType::DURABLE_STORAGE:
Darwin Huangf6661742019-12-06 23:31:3164 case PermissionType::CLIPBOARD_READ_WRITE:
65 case PermissionType::CLIPBOARD_SANITIZED_WRITE:
Alexander Timin5afc73e2019-06-24 01:03:1066 case PermissionType::PAYMENT_HANDLER:
67 case PermissionType::IDLE_DETECTION:
68 case PermissionType::WAKE_LOCK_SCREEN:
69 case PermissionType::WAKE_LOCK_SYSTEM:
Francois Beaufort51f9ee32019-11-05 06:48:1670 case PermissionType::NFC:
Alexander Timin5afc73e2019-06-24 01:03:1071 case PermissionType::NUM:
Fergal Daly4289f932019-11-27 03:09:3072 case PermissionType::SENSORS:
Alex Cooper530cfbb92019-12-19 03:19:5473 case PermissionType::AR:
74 case PermissionType::VR:
Alexander Cooperedef12b2024-08-22 18:42:3675 case PermissionType::HAND_TRACKING:
François Beaufort087e32112020-04-15 06:01:1276 case PermissionType::CAMERA_PAN_TILT_ZOOM:
Brad Triebwasser334d00e2022-10-17 18:47:5777 case PermissionType::WINDOW_MANAGEMENT:
Daseul Lee5ff70482022-04-08 19:02:5078 case PermissionType::LOCAL_FONTS:
Elad Alonc0f52c92020-12-10 11:38:0279 case PermissionType::DISPLAY_CAPTURE:
Darren W154cf342021-07-13 05:27:1980 case PermissionType::GEOLOCATION:
Mingyu Leia989b8962022-10-28 09:54:4681 case PermissionType::NOTIFICATIONS:
Elad Alondac5de9d2023-12-11 15:54:0682 case PermissionType::CAPTURED_SURFACE_CONTROL:
Daniel d'Andradad6cd88f52023-12-12 14:35:5183 case PermissionType::SMART_CARD:
Andrew Rayskiy890ffd112024-01-08 17:51:4484 case PermissionType::WEB_PRINTING:
Sunggook Chue3d430a42024-02-16 21:27:4285 case PermissionType::SPEAKER_SELECTION:
Takumi Fujimotofd7005c2024-03-11 02:57:2986 case PermissionType::KEYBOARD_LOCK:
87 case PermissionType::POINTER_LOCK:
Mike Wasserman740e8732024-06-19 19:39:1988 case PermissionType::AUTOMATIC_FULLSCREEN:
Kristin Leecf6612512024-08-23 19:12:1289 case PermissionType::WEB_APP_INSTALLATION:
Chris Thompsona9d45802025-03-12 21:59:5790 case PermissionType::LOCAL_NETWORK_ACCESS:
Arthur Sonzognic686e8f2024-01-11 08:36:3791 return std::nullopt;
Alexander Timin5afc73e2019-06-24 01:03:1092 }
93}
94
Elias Klim1e5178a32023-12-12 21:15:2995#if !BUILDFLAG(IS_ANDROID)
96bool PermissionAllowedByPermissionsPolicy(PermissionType permission_type,
97 RenderFrameHost* rfh) {
98 const auto permission_policy =
99 blink::PermissionTypeToPermissionsPolicyFeature(permission_type);
100 // Some features don't have an associated permissions policy yet. Allow those.
101 if (!permission_policy.has_value()) {
102 return true;
103 }
104
105 return rfh->IsFeatureEnabled(permission_policy.value());
106}
107#endif
108
Andy Paicu0a6d4b502023-08-29 15:13:09109PermissionResult VerifyContextOfCurrentDocument(
Illia Klimov9777bbb2022-10-11 11:02:01110 PermissionType permission,
Andy Paicu0a6d4b502023-08-29 15:13:09111 RenderFrameHost* render_frame_host) {
112 WebContents* web_contents =
113 WebContents::FromRenderFrameHost(render_frame_host);
Illia Klimov9777bbb2022-10-11 11:02:01114
115 DCHECK(web_contents);
116
Illia Klimov9777bbb2022-10-11 11:02:01117 // Permissions are denied for fenced frames.
118 if (render_frame_host->IsNestedWithinFencedFrame()) {
Illia Klimov2c6138b2023-08-14 09:39:25119 return PermissionResult(PermissionStatus::DENIED,
Illia Klimov9777bbb2022-10-11 11:02:01120 PermissionStatusSource::FENCED_FRAME);
121 }
122
Elias Klim1e5178a32023-12-12 21:15:29123#if !BUILDFLAG(IS_ANDROID)
124 if (base::FeatureList::IsEnabled(
125 features::kPermissionsPolicyVerificationInContent)) {
126 // Check whether the feature is enabled for the frame by permissions policy.
127 if (!PermissionAllowedByPermissionsPolicy(permission, render_frame_host)) {
128 return PermissionResult(PermissionStatus::DENIED,
129 PermissionStatusSource::FEATURE_POLICY);
130 }
131 }
132#endif
133
Illia Klimov2c6138b2023-08-14 09:39:25134 return PermissionResult(PermissionStatus::ASK,
Illia Klimov9777bbb2022-10-11 11:02:01135 PermissionStatusSource::UNSPECIFIED);
136}
137
138bool IsRequestAllowed(
Florian Jacky65b7d102025-04-07 10:02:52139 const std::vector<blink::mojom::PermissionDescriptorPtr>& permissions,
Illia Klimov9777bbb2022-10-11 11:02:01140 RenderFrameHost* render_frame_host,
Florian Jackyaaf42832025-08-19 04:03:26141 base::OnceCallback<void(const std::vector<PermissionResult>&)>& callback) {
Illia Klimov9777bbb2022-10-11 11:02:01142 if (!render_frame_host) {
143 // Permission request is not allowed without a valid RenderFrameHost.
Florian Jackyaaf42832025-08-19 04:03:26144 std::move(callback).Run(std::vector<PermissionResult>(
145 permissions.size(),
146 PermissionResult(PermissionStatus::ASK,
147 PermissionStatusSource::UNSPECIFIED)));
Illia Klimov9777bbb2022-10-11 11:02:01148 return false;
149 }
150
151 // Verifies and evicts `render_frame_host` from BFcache. Returns true if
152 // render_frame_host was evicted, returns false otherwise.
153 if (render_frame_host->IsInactiveAndDisallowActivation(
Andy Paicu0a6d4b502023-08-29 15:13:09154 DisallowActivationReasonId::kRequestPermission)) {
Florian Jackyaaf42832025-08-19 04:03:26155 std::move(callback).Run(std::vector<PermissionResult>(
156 permissions.size(),
157 PermissionResult(PermissionStatus::ASK,
158 PermissionStatusSource::UNSPECIFIED)));
Illia Klimov9777bbb2022-10-11 11:02:01159 return false;
160 }
161
Florian Jackyaaf42832025-08-19 04:03:26162 auto permission_results = std::vector<PermissionResult>();
163
Illia Klimov9777bbb2022-10-11 11:02:01164 // Verify each permission independently to generate proper warning messages.
165 bool is_permission_allowed = true;
Florian Jacky65b7d102025-04-07 10:02:52166 for (const auto& permission : permissions) {
167 PermissionType permission_type =
168 blink::PermissionDescriptorToPermissionType(permission);
Illia Klimov9777bbb2022-10-11 11:02:01169 PermissionResult result =
Florian Jacky65b7d102025-04-07 10:02:52170 VerifyContextOfCurrentDocument(permission_type, render_frame_host);
Florian Jackyaaf42832025-08-19 04:03:26171 permission_results.push_back(result);
Illia Klimov9777bbb2022-10-11 11:02:01172
Illia Klimov2c6138b2023-08-14 09:39:25173 if (result.status == PermissionStatus::DENIED) {
Illia Klimov9777bbb2022-10-11 11:02:01174 switch (result.source) {
Illia Klimov9777bbb2022-10-11 11:02:01175 case PermissionStatusSource::FENCED_FRAME:
Peter Kasting472500482024-11-21 18:36:25176 render_frame_host->GetOutermostMainFrame()->AddMessageToConsole(
177 blink::mojom::ConsoleMessageLevel::kWarning,
Florian Jacky65b7d102025-04-07 10:02:52178 blink::GetPermissionString(permission_type) +
Peter Kasting472500482024-11-21 18:36:25179 " permission has been blocked because it was requested "
180 "inside a fenced frame. Fenced frames don't currently "
181 "support permission requests.");
Illia Klimov9777bbb2022-10-11 11:02:01182 break;
Elias Klim1e5178a32023-12-12 21:15:29183#if !BUILDFLAG(IS_ANDROID)
184 case PermissionStatusSource::FEATURE_POLICY:
Peter Kasting472500482024-11-21 18:36:25185 render_frame_host->GetOutermostMainFrame()->AddMessageToConsole(
186 blink::mojom::ConsoleMessageLevel::kWarning,
Florian Jacky65b7d102025-04-07 10:02:52187 blink::GetPermissionString(permission_type) +
Peter Kasting472500482024-11-21 18:36:25188 " permission has been blocked because of a permissions "
189 "policy applied to the current document. See "
Elias Klim8897d612025-04-29 11:06:10190 "https://crbug.com/414348233 for more details.");
Elias Klim1e5178a32023-12-12 21:15:29191 break;
192#endif
Illia Klimov9777bbb2022-10-11 11:02:01193 default:
194 break;
195 }
196
197 is_permission_allowed = false;
198 }
199 }
200
201 if (!is_permission_allowed) {
Florian Jackyaaf42832025-08-19 04:03:26202 std::move(callback).Run(permission_results);
Illia Klimov9777bbb2022-10-11 11:02:01203 return false;
204 }
205
206 return true;
207}
208
Alexander Timin5afc73e2019-06-24 01:03:10209void NotifySchedulerAboutPermissionRequest(RenderFrameHost* render_frame_host,
210 PermissionType permission_name) {
211 DCHECK(render_frame_host);
212
Arthur Sonzognic686e8f2024-01-11 08:36:37213 std::optional<blink::scheduler::WebSchedulerTrackedFeature> feature =
Alexander Timin5afc73e2019-06-24 01:03:10214 PermissionToSchedulingFeature(permission_name);
215
Elias Klim1e5178a32023-12-12 21:15:29216 if (!feature) {
Alexander Timin5afc73e2019-06-24 01:03:10217 return;
Elias Klim1e5178a32023-12-12 21:15:29218 }
Alexander Timin5afc73e2019-06-24 01:03:10219
220 static_cast<RenderFrameHostImpl*>(render_frame_host)
Yuzu Saijo08d13d42021-10-20 05:25:13221 ->OnBackForwardCacheDisablingStickyFeatureUsed(feature.value());
Alexander Timin5afc73e2019-06-24 01:03:10222}
223
Rohan Pavoneb4de95152019-08-07 22:26:01224// Calls |original_cb|, a callback expecting the PermissionStatus of a set of
225// permissions, after joining the results of overridden permissions and
226// non-overridden permissions.
227// |overridden_results| is an array of permissions that have already been
228// overridden by DevTools.
229// |delegated_results| contains results that did not have overrides - they
230// were delegated - their results need to be inserted in order.
231void MergeOverriddenAndDelegatedResults(
Florian Jackyaaf42832025-08-19 04:03:26232 base::OnceCallback<void(const std::vector<PermissionResult>&)> original_cb,
233 std::vector<std::optional<PermissionResult>> overridden_results,
234 const std::vector<PermissionResult>& delegated_results) {
235 std::vector<PermissionResult> full_results;
Rohan Pavoneb4de95152019-08-07 22:26:01236 full_results.reserve(overridden_results.size());
237 auto delegated_it = delegated_results.begin();
238 for (auto& status : overridden_results) {
Illia Klimovf2842842022-03-22 11:33:39239 if (!status) {
Rohan Pavoneb4de95152019-08-07 22:26:01240 CHECK(delegated_it != delegated_results.end());
241 status.emplace(*delegated_it++);
242 }
243 full_results.emplace_back(*status);
244 }
245 CHECK(delegated_it == delegated_results.end());
246
247 std::move(original_cb).Run(full_results);
248}
249
Illia Klimov27239edc2022-05-11 17:14:59250void PermissionStatusCallbackWrapper(
Florian Jackyaaf42832025-08-19 04:03:26251 base::OnceCallback<void(PermissionResult)> callback,
252 const std::vector<PermissionResult>& vector) {
Illia Klimov27239edc2022-05-11 17:14:59253 DCHECK_EQ(1ul, vector.size());
254 std::move(callback).Run(vector.at(0));
255}
256
Andy Paicu0a6d4b502023-08-29 15:13:09257// Removes from |description.permissions| the entries that have an override
258// status (as per the provided overrides). Returns a result vector that contains
259// all the statuses for permissions after applying overrides, using `nullopt`
260// for those permissions that do not have an override.
Florian Jackyaaf42832025-08-19 04:03:26261std::vector<std::optional<PermissionResult>> OverridePermissions(
Andy Paicu0a6d4b502023-08-29 15:13:09262 PermissionRequestDescription& description,
263 RenderFrameHost* render_frame_host,
264 const PermissionOverrides& permission_overrides) {
Florian Jacky65b7d102025-04-07 10:02:52265 std::vector<blink::mojom::PermissionDescriptorPtr>
266 permissions_without_overrides;
Florian Jackyaaf42832025-08-19 04:03:26267 std::vector<std::optional<PermissionResult>> results;
jalonthomasb3f862a2025-07-22 16:02:23268
Andy Paicu0a6d4b502023-08-29 15:13:09269 for (const auto& permission : description.permissions) {
Florian Jackyaaf42832025-08-19 04:03:26270 std::optional<PermissionResult> override_status = permission_overrides.Get(
271 render_frame_host->GetLastCommittedOrigin(),
272 render_frame_host->GetMainFrame()->GetLastCommittedOrigin(),
273 blink::PermissionDescriptorToPermissionType(permission));
Andy Paicu0a6d4b502023-08-29 15:13:09274 if (!override_status) {
Florian Jacky65b7d102025-04-07 10:02:52275 permissions_without_overrides.push_back(permission.Clone());
Andy Paicu0a6d4b502023-08-29 15:13:09276 }
277 results.push_back(override_status);
278 }
279
280 description.permissions = std::move(permissions_without_overrides);
281 return results;
282}
283
Andrey Lushnikov36299bc2018-08-23 22:09:54284} // namespace
285
Andrey Lushnikovebff0442018-07-12 20:02:58286PermissionControllerImpl::PermissionControllerImpl(
287 BrowserContext* browser_context)
288 : browser_context_(browser_context) {}
289
Thomas Nguyen5fe19272022-12-15 10:38:00290// static
Andrey Lushnikovebff0442018-07-12 20:02:58291PermissionControllerImpl* PermissionControllerImpl::FromBrowserContext(
292 BrowserContext* browser_context) {
293 return static_cast<PermissionControllerImpl*>(
Lukasz Anforowicz82061152021-05-14 02:14:26294 browser_context->GetPermissionController());
Andrey Lushnikovebff0442018-07-12 20:02:58295}
296
Andrey Lushnikov36299bc2018-08-23 22:09:54297PermissionControllerImpl::~PermissionControllerImpl() {
298 // Ideally we need to unsubscribe from delegate subscriptions here,
299 // but browser_context_ is already destroyed by this point, so
300 // we can't fetch our delegate.
301}
302
Illia Klimov2c6138b2023-08-14 09:39:25303PermissionStatus PermissionControllerImpl::GetSubscriptionCurrentValue(
Yifan Luo006519d92024-08-22 16:11:34304 const PermissionStatusSubscription& subscription) {
Andrey Lushnikov36299bc2018-08-23 22:09:54305 // The RFH may be null if the request is for a worker.
Andy Paicu0a6d4b502023-08-29 15:13:09306 RenderFrameHost* rfh = RenderFrameHost::FromID(subscription.render_process_id,
307 subscription.render_frame_id);
Florian Jackya857d582025-04-10 10:13:33308 // TODO(crbug.com/408965890): Add support for multi-state permissions. The
309 // following won't work for detecting changes in permission options.
310 const auto descriptor =
311 PermissionDescriptorUtil::CreatePermissionDescriptorForPermissionType(
312 subscription.permission);
Andrey Lushnikov36299bc2018-08-23 22:09:54313 if (rfh) {
Florian Jackya857d582025-04-10 10:13:33314 return GetPermissionStatusForCurrentDocument(descriptor, rfh);
Andrey Lushnikov36299bc2018-08-23 22:09:54315 }
Robbie McElrath8d5602a2022-04-01 17:39:18316
Andy Paicu0a6d4b502023-08-29 15:13:09317 RenderProcessHost* rph =
318 RenderProcessHost::FromID(subscription.render_process_id);
Robbie McElrath8d5602a2022-04-01 17:39:18319 if (rph) {
320 return GetPermissionStatusForWorker(
Florian Jackya857d582025-04-10 10:13:33321 descriptor, rph, url::Origin::Create(subscription.requesting_origin));
Robbie McElrath8d5602a2022-04-01 17:39:18322 }
323
Florian Jackya857d582025-04-10 10:13:33324 return GetPermissionStatusInternal(descriptor, subscription.requesting_origin,
Illia Klimov15550f752022-08-11 19:33:10325 subscription.embedding_origin);
Andrey Lushnikov36299bc2018-08-23 22:09:54326}
327
Rohan Pavonefaf64572019-07-30 17:50:20328PermissionControllerImpl::SubscriptionsStatusMap
329PermissionControllerImpl::GetSubscriptionsStatuses(
jalonthomas3a00d592025-07-28 14:16:53330 const std::optional<GURL>& requesting_origin,
331 const std::optional<GURL>& embedding_origin) {
Rohan Pavonefaf64572019-07-30 17:50:20332 SubscriptionsStatusMap statuses;
Andrey Lushnikov36299bc2018-08-23 22:09:54333 for (SubscriptionsMap::iterator iter(&subscriptions_); !iter.IsAtEnd();
334 iter.Advance()) {
Yifan Luo006519d92024-08-22 16:11:34335 PermissionStatusSubscription* subscription = iter.GetCurrentValue();
jalonthomas3a00d592025-07-28 14:16:53336 if (requesting_origin.has_value() && embedding_origin.has_value() &&
337 subscription->requesting_origin != *requesting_origin &&
338 subscription->embedding_origin != *embedding_origin) {
Andrey Lushnikov36299bc2018-08-23 22:09:54339 continue;
Illia Klimov7df05f22023-01-20 20:30:31340 }
Rohan Pavonefaf64572019-07-30 17:50:20341 statuses[iter.GetCurrentKey()] = GetSubscriptionCurrentValue(*subscription);
Andrey Lushnikov36299bc2018-08-23 22:09:54342 }
Rohan Pavonefaf64572019-07-30 17:50:20343 return statuses;
344}
345
346void PermissionControllerImpl::NotifyChangedSubscriptions(
347 const SubscriptionsStatusMap& old_statuses) {
Makoto Shimazu37225d762019-10-09 18:35:00348 std::vector<base::OnceClosure> callbacks;
Rohan Pavonefaf64572019-07-30 17:50:20349 for (const auto& it : old_statuses) {
350 auto key = it.first;
Yifan Luo006519d92024-08-22 16:11:34351 PermissionStatusSubscription* subscription = subscriptions_.Lookup(key);
Elias Klim1e5178a32023-12-12 21:15:29352 if (!subscription) {
Rohan Pavonefaf64572019-07-30 17:50:20353 continue;
Elias Klim1e5178a32023-12-12 21:15:29354 }
Illia Klimov2c6138b2023-08-14 09:39:25355 PermissionStatus old_status = it.second;
356 PermissionStatus new_status = GetSubscriptionCurrentValue(*subscription);
Elias Klim1e5178a32023-12-12 21:15:29357 if (new_status != old_status) {
Yifan Luo006519d92024-08-22 16:11:34358 // This is a private method that is called internally if a permission
359 // status was set by DevTools. Suppress permission status override
360 // verification and always notify listeners.
361 callbacks.push_back(base::BindOnce(subscription->callback, new_status,
362 /*ignore_status_override=*/true));
Elias Klim1e5178a32023-12-12 21:15:29363 }
Rohan Pavonefaf64572019-07-30 17:50:20364 }
Elias Klim8897d612025-04-29 11:06:10365 for (auto& callback : callbacks) {
Makoto Shimazu37225d762019-10-09 18:35:00366 std::move(callback).Run();
Elias Klim8897d612025-04-29 11:06:10367 }
Andrey Lushnikov36299bc2018-08-23 22:09:54368}
369
Rohan Pavone013c4002019-08-21 20:13:52370PermissionControllerImpl::OverrideStatus
Illia Klimov9af8089132022-10-07 16:42:30371PermissionControllerImpl::GrantOverridesForDevTools(
jalonthomas468c58a2025-08-06 16:47:46372 base::optional_ref<const url::Origin> requesting_origin,
373 base::optional_ref<const url::Origin> embedding_origin,
Illia Klimov9af8089132022-10-07 16:42:30374 const std::vector<PermissionType>& permissions) {
jalonthomas468c58a2025-08-06 16:47:46375 return GrantPermissionOverrides(requesting_origin, embedding_origin,
376 permissions);
Illia Klimov9af8089132022-10-07 16:42:30377}
378
379PermissionControllerImpl::OverrideStatus
Rohan Pavone013c4002019-08-21 20:13:52380PermissionControllerImpl::SetOverrideForDevTools(
jalonthomas468c58a2025-08-06 16:47:46381 base::optional_ref<const url::Origin> requesting_origin,
382 base::optional_ref<const url::Origin> embedding_origin,
Pavel Feldman446a91b2020-03-13 17:39:55383 PermissionType permission,
Illia Klimov2c6138b2023-08-14 09:39:25384 const PermissionStatus& status) {
jalonthomas468c58a2025-08-06 16:47:46385 return SetPermissionOverride(requesting_origin, embedding_origin, permission,
386 status);
Illia Klimov9af8089132022-10-07 16:42:30387}
388
389void PermissionControllerImpl::ResetOverridesForDevTools() {
390 ResetPermissionOverrides();
391}
392
393PermissionControllerImpl::OverrideStatus
394PermissionControllerImpl::SetPermissionOverride(
jalonthomas468c58a2025-08-06 16:47:46395 base::optional_ref<const url::Origin> requesting_origin,
396 base::optional_ref<const url::Origin> embedding_origin,
Illia Klimov9af8089132022-10-07 16:42:30397 PermissionType permission,
Illia Klimov2c6138b2023-08-14 09:39:25398 const PermissionStatus& status) {
jalonthomas468c58a2025-08-06 16:47:46399 CHECK_EQ(requesting_origin.has_value(), embedding_origin.has_value());
400
Rohan Pavone013c4002019-08-21 20:13:52401 PermissionControllerDelegate* delegate =
402 browser_context_->GetPermissionControllerDelegate();
jalonthomas468c58a2025-08-06 16:47:46403 if (delegate && !delegate->IsPermissionOverridable(
404 permission, requesting_origin, embedding_origin)) {
Rohan Pavone013c4002019-08-21 20:13:52405 return OverrideStatus::kOverrideNotSet;
406 }
jalonthomas3a00d592025-07-28 14:16:53407
jalonthomas468c58a2025-08-06 16:47:46408 const std::optional<GURL> requesting_origin_url =
409 requesting_origin.has_value()
410 ? std::make_optional(requesting_origin->GetURL())
411 : std::nullopt;
412 const std::optional<GURL> embedding_origin_url =
413 embedding_origin.has_value()
414 ? std::make_optional(embedding_origin->GetURL())
415 : std::nullopt;
416 const auto old_statuses =
417 GetSubscriptionsStatuses(requesting_origin_url, embedding_origin_url);
418
419 permission_overrides_.Set(requesting_origin, embedding_origin, permission,
420 status);
Rohan Pavoneb4de95152019-08-07 22:26:01421 NotifyChangedSubscriptions(old_statuses);
422
Rohan Pavone013c4002019-08-21 20:13:52423 return OverrideStatus::kOverrideSet;
Rohan Pavoneb4de95152019-08-07 22:26:01424}
425
Rohan Pavone013c4002019-08-21 20:13:52426PermissionControllerImpl::OverrideStatus
Illia Klimov9af8089132022-10-07 16:42:30427PermissionControllerImpl::GrantPermissionOverrides(
jalonthomas468c58a2025-08-06 16:47:46428 base::optional_ref<const url::Origin> requesting_origin,
429 base::optional_ref<const url::Origin> embedding_origin,
Rohan Pavonefaf64572019-07-30 17:50:20430 const std::vector<PermissionType>& permissions) {
jalonthomas468c58a2025-08-06 16:47:46431 CHECK_EQ(requesting_origin.has_value(), embedding_origin.has_value());
432
Rohan Pavone013c4002019-08-21 20:13:52433 PermissionControllerDelegate* delegate =
434 browser_context_->GetPermissionControllerDelegate();
Pavel Feldman446a91b2020-03-13 17:39:55435 if (delegate) {
436 for (const auto permission : permissions) {
jalonthomas468c58a2025-08-06 16:47:46437 if (!delegate->IsPermissionOverridable(permission, requesting_origin,
438 embedding_origin)) {
Rohan Pavone013c4002019-08-21 20:13:52439 return OverrideStatus::kOverrideNotSet;
Elias Klim1e5178a32023-12-12 21:15:29440 }
Pavel Feldman446a91b2020-03-13 17:39:55441 }
442 }
Rohan Pavone013c4002019-08-21 20:13:52443
jalonthomas468c58a2025-08-06 16:47:46444 const std::optional<GURL> requesting_origin_url =
445 requesting_origin.has_value()
446 ? std::make_optional(requesting_origin->GetURL())
447 : std::nullopt;
448 const std::optional<GURL> embedding_origin_url =
449 embedding_origin.has_value()
450 ? std::make_optional(embedding_origin->GetURL())
451 : std::nullopt;
452 const auto old_statuses =
453 GetSubscriptionsStatuses(requesting_origin_url, embedding_origin_url);
454
455 permission_overrides_.GrantPermissions(requesting_origin, embedding_origin,
456 permissions);
Rohan Pavonefaf64572019-07-30 17:50:20457 // If any statuses changed because they lose overrides or the new overrides
458 // modify their previous state (overridden or not), subscribers must be
459 // notified manually.
460 NotifyChangedSubscriptions(old_statuses);
461
Rohan Pavone013c4002019-08-21 20:13:52462 return OverrideStatus::kOverrideSet;
Rohan Pavonefaf64572019-07-30 17:50:20463}
464
Illia Klimov9af8089132022-10-07 16:42:30465void PermissionControllerImpl::ResetPermissionOverrides() {
Rohan Pavonefaf64572019-07-30 17:50:20466 const auto old_statuses = GetSubscriptionsStatuses();
Illia Klimov9af8089132022-10-07 16:42:30467 permission_overrides_ = PermissionOverrides();
Rohan Pavonefaf64572019-07-30 17:50:20468
Alex Rudenkoc728e632022-05-11 09:32:24469 // If any statuses changed because they lost their overrides, the subscribers
470 // must be notified manually.
471 NotifyChangedSubscriptions(old_statuses);
Rohan Pavonefaf64572019-07-30 17:50:20472}
473
Matt Reichhoff56f62282022-09-12 20:36:00474void PermissionControllerImpl::RequestPermissions(
Matt Reichhoff56f62282022-09-12 20:36:00475 RenderFrameHost* render_frame_host,
Andy Paicu0a6d4b502023-08-29 15:13:09476 PermissionRequestDescription request_description,
Florian Jackyaaf42832025-08-19 04:03:26477 base::OnceCallback<void(const std::vector<PermissionResult>&)> callback) {
Andy Paicu0a6d4b502023-08-29 15:13:09478 if (!IsRequestAllowed(request_description.permissions, render_frame_host,
479 callback)) {
Illia Klimov9777bbb2022-10-11 11:02:01480 return;
481 }
482
Florian Jacky65b7d102025-04-07 10:02:52483 for (const blink::mojom::PermissionDescriptorPtr& permission :
484 request_description.permissions) {
485 NotifySchedulerAboutPermissionRequest(
486 render_frame_host,
487 blink::PermissionDescriptorToPermissionType(permission));
Matt Reichhoff56f62282022-09-12 20:36:00488 }
489
Florian Jackyaaf42832025-08-19 04:03:26490 std::vector<std::optional<PermissionResult>> override_results =
Andy Paicu0a6d4b502023-08-29 15:13:09491 OverridePermissions(request_description, render_frame_host,
492 permission_overrides_);
493
Matt Reichhoff56f62282022-09-12 20:36:00494 auto wrapper = base::BindOnce(&MergeOverriddenAndDelegatedResults,
Andy Paicu0a6d4b502023-08-29 15:13:09495 std::move(callback), override_results);
496 if (request_description.permissions.empty()) {
Matt Reichhoff56f62282022-09-12 20:36:00497 std::move(wrapper).Run({});
498 return;
499 }
500
501 // Use delegate to find statuses of other permissions that have been requested
502 // but do not have overrides.
503 PermissionControllerDelegate* delegate =
504 browser_context_->GetPermissionControllerDelegate();
505 if (!delegate) {
Florian Jackyaaf42832025-08-19 04:03:26506 std::move(wrapper).Run(std::vector<PermissionResult>(
507 request_description.permissions.size(),
508 PermissionResult(PermissionStatus::DENIED,
509 PermissionStatusSource::UNSPECIFIED)));
Matt Reichhoff56f62282022-09-12 20:36:00510 return;
511 }
512
Andy Paicu0a6d4b502023-08-29 15:13:09513 delegate->RequestPermissions(render_frame_host, request_description,
Matt Reichhoff56f62282022-09-12 20:36:00514 std::move(wrapper));
515}
516
Illia Klimov27239edc2022-05-11 17:14:59517void PermissionControllerImpl::RequestPermissionFromCurrentDocument(
Andrey Lushnikovebff0442018-07-12 20:02:58518 RenderFrameHost* render_frame_host,
Andy Paicu0a6d4b502023-08-29 15:13:09519 PermissionRequestDescription request_description,
Florian Jackyaaf42832025-08-19 04:03:26520 base::OnceCallback<void(PermissionResult)> callback) {
Illia Klimov27239edc2022-05-11 17:14:59521 RequestPermissionsFromCurrentDocument(
Andy Paicu0a6d4b502023-08-29 15:13:09522 render_frame_host, std::move(request_description),
Illia Klimov27239edc2022-05-11 17:14:59523 base::BindOnce(&PermissionStatusCallbackWrapper, std::move(callback)));
Andrey Lushnikovebff0442018-07-12 20:02:58524}
525
Illia Klimov27239edc2022-05-11 17:14:59526void PermissionControllerImpl::RequestPermissionsFromCurrentDocument(
Andrey Lushnikovebff0442018-07-12 20:02:58527 RenderFrameHost* render_frame_host,
Andy Paicu0a6d4b502023-08-29 15:13:09528 PermissionRequestDescription request_description,
Florian Jackyaaf42832025-08-19 04:03:26529 base::OnceCallback<void(const std::vector<PermissionResult>&)> callback) {
Andy Paicu0a6d4b502023-08-29 15:13:09530 if (!IsRequestAllowed(request_description.permissions, render_frame_host,
531 callback)) {
Illia Klimov9777bbb2022-10-11 11:02:01532 return;
Rohan Pavoneb4de95152019-08-07 22:26:01533 }
Rohan Pavonefaf64572019-07-30 17:50:20534
Florian Jacky65b7d102025-04-07 10:02:52535 for (const auto& permission : request_description.permissions) {
536 NotifySchedulerAboutPermissionRequest(
537 render_frame_host,
538 blink::PermissionDescriptorToPermissionType(permission));
Andy Paicu0a6d4b502023-08-29 15:13:09539 }
540
541 request_description.requesting_origin =
542 render_frame_host->GetLastCommittedOrigin().GetURL();
Florian Jackyaaf42832025-08-19 04:03:26543 std::vector<std::optional<PermissionResult>> override_results =
Andy Paicu0a6d4b502023-08-29 15:13:09544 OverridePermissions(request_description, render_frame_host,
545 permission_overrides_);
546
Rohan Pavoneb4de95152019-08-07 22:26:01547 auto wrapper = base::BindOnce(&MergeOverriddenAndDelegatedResults,
Andy Paicu0a6d4b502023-08-29 15:13:09548 std::move(callback), override_results);
549 if (request_description.permissions.empty()) {
Rohan Pavoneb4de95152019-08-07 22:26:01550 std::move(wrapper).Run({});
Balazs Engedye30e9612021-04-02 10:37:29551 return;
Andrey Lushnikov36299bc2018-08-23 22:09:54552 }
553
Rohan Pavoneb4de95152019-08-07 22:26:01554 // Use delegate to find statuses of other permissions that have been requested
555 // but do not have overrides.
Andrey Lushnikovf3500102018-07-16 19:55:22556 PermissionControllerDelegate* delegate =
557 browser_context_->GetPermissionControllerDelegate();
Andrey Lushnikovebff0442018-07-12 20:02:58558 if (!delegate) {
Florian Jackyaaf42832025-08-19 04:03:26559 std::move(wrapper).Run(std::vector<PermissionResult>(
560 request_description.permissions.size(),
561 PermissionResult(PermissionStatus::DENIED,
562 PermissionStatusSource::UNSPECIFIED)));
Balazs Engedye30e9612021-04-02 10:37:29563 return;
Andrey Lushnikovebff0442018-07-12 20:02:58564 }
Andrey Lushnikovebff0442018-07-12 20:02:58565
Illia Klimov27239edc2022-05-11 17:14:59566 delegate->RequestPermissionsFromCurrentDocument(
Andy Paicu0a6d4b502023-08-29 15:13:09567 render_frame_host, request_description, std::move(wrapper));
Illia Klimova181b7d2022-03-15 08:17:47568}
569
Illia Klimov4b72378ed2022-07-18 13:46:57570void PermissionControllerImpl::ResetPermission(blink::PermissionType permission,
571 const url::Origin& origin) {
572 ResetPermission(permission, origin.GetURL(), origin.GetURL());
573}
574
Illia Klimov2c6138b2023-08-14 09:39:25575PermissionStatus PermissionControllerImpl::GetPermissionStatusInternal(
Florian Jackya857d582025-04-10 10:13:33576 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Andrey Lushnikovebff0442018-07-12 20:02:58577 const GURL& requesting_origin,
578 const GURL& embedding_origin) {
Florian Jackyaaf42832025-08-19 04:03:26579 std::optional<PermissionResult> prermission_result =
580 permission_overrides_.Get(
581 url::Origin::Create(requesting_origin),
582 url::Origin::Create(embedding_origin),
583 blink::PermissionDescriptorToPermissionType(permission_descriptor));
584 if (prermission_result) {
585 return prermission_result->status;
Elias Klim1e5178a32023-12-12 21:15:29586 }
Andrey Lushnikov36299bc2018-08-23 22:09:54587
Andrey Lushnikovf3500102018-07-16 19:55:22588 PermissionControllerDelegate* delegate =
589 browser_context_->GetPermissionControllerDelegate();
Elias Klim1e5178a32023-12-12 21:15:29590 if (!delegate) {
Illia Klimov2c6138b2023-08-14 09:39:25591 return PermissionStatus::DENIED;
Elias Klim1e5178a32023-12-12 21:15:29592 }
Florian Jacky8373f042025-04-16 14:20:53593 return delegate->GetPermissionStatus(permission_descriptor, requesting_origin,
594 embedding_origin);
Andrey Lushnikovebff0442018-07-12 20:02:58595}
596
Thomas Nguyen235933322024-05-27 14:52:11597PermissionStatus
598PermissionControllerImpl::GetPermissionStatusForCurrentDocumentInternal(
Florian Jackya857d582025-04-10 10:13:33599 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Thomas Nguyen235933322024-05-27 14:52:11600 RenderFrameHost* render_frame_host,
601 bool should_include_device_status) {
Florian Jackya857d582025-04-10 10:13:33602 auto permission_type =
603 blink::PermissionDescriptorToPermissionType(permission_descriptor);
Florian Jackyaaf42832025-08-19 04:03:26604 std::optional<PermissionResult> permission_result = permission_overrides_.Get(
jalonthomasb3f862a2025-07-22 16:02:23605 render_frame_host->GetLastCommittedOrigin(),
606 render_frame_host->GetMainFrame()->GetLastCommittedOrigin(),
607 permission_type);
Florian Jackyaaf42832025-08-19 04:03:26608 if (permission_result) {
609 return permission_result->status;
Thomas Nguyen235933322024-05-27 14:52:11610 }
611 PermissionControllerDelegate* delegate =
612 browser_context_->GetPermissionControllerDelegate();
613 if (!delegate) {
614 return PermissionStatus::DENIED;
615 }
Florian Jackya857d582025-04-10 10:13:33616 if (VerifyContextOfCurrentDocument(permission_type, render_frame_host)
617 .status == PermissionStatus::DENIED) {
Thomas Nguyen235933322024-05-27 14:52:11618 return PermissionStatus::DENIED;
619 }
620 return delegate->GetPermissionStatusForCurrentDocument(
Florian Jacky8373f042025-04-16 14:20:53621 permission_descriptor, render_frame_host, should_include_device_status);
Thomas Nguyen235933322024-05-27 14:52:11622}
623
Illia Klimov2c6138b2023-08-14 09:39:25624PermissionStatus PermissionControllerImpl::GetPermissionStatusForWorker(
Florian Jackya857d582025-04-10 10:13:33625 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Robbie McElrath8d5602a2022-04-01 17:39:18626 RenderProcessHost* render_process_host,
627 const url::Origin& worker_origin) {
Florian Jackya857d582025-04-10 10:13:33628 auto permission_type =
629 blink::PermissionDescriptorToPermissionType(permission_descriptor);
jalonthomasb3f862a2025-07-22 16:02:23630
631 // TODO(crbug.com/428178708): This is likely incorrect for partitioned
632 // contexts and requires impact evaluation before updating to use embedding
633 // and requesting origins.
Florian Jackyaaf42832025-08-19 04:03:26634 std::optional<PermissionResult> permission_result =
jalonthomasb3f862a2025-07-22 16:02:23635 permission_overrides_.Get(worker_origin, worker_origin, permission_type);
Florian Jackyaaf42832025-08-19 04:03:26636 if (permission_result) {
637 return permission_result->status;
Elias Klim1e5178a32023-12-12 21:15:29638 }
Robbie McElrath8d5602a2022-04-01 17:39:18639
640 PermissionControllerDelegate* delegate =
641 browser_context_->GetPermissionControllerDelegate();
Elias Klim1e5178a32023-12-12 21:15:29642 if (!delegate) {
Illia Klimov2c6138b2023-08-14 09:39:25643 return PermissionStatus::DENIED;
Elias Klim1e5178a32023-12-12 21:15:29644 }
645
Florian Jackya857d582025-04-10 10:13:33646 return delegate->GetPermissionStatusForWorker(
Florian Jacky8373f042025-04-16 14:20:53647 permission_descriptor, render_process_host, worker_origin.GetURL());
Illia Klimov4a2cb192022-03-15 06:31:35648}
649
Illia Klimov2c6138b2023-08-14 09:39:25650PermissionStatus
Illia Klimov4a2cb192022-03-15 06:31:35651PermissionControllerImpl::GetPermissionStatusForCurrentDocument(
Florian Jackya857d582025-04-10 10:13:33652 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Illia Klimov4a2cb192022-03-15 06:31:35653 RenderFrameHost* render_frame_host) {
Florian Jackya857d582025-04-10 10:13:33654 return GetPermissionStatusForCurrentDocumentInternal(permission_descriptor,
Thomas Nguyen235933322024-05-27 14:52:11655 render_frame_host);
Illia Klimov4a2cb192022-03-15 06:31:35656}
657
Illia Klimov15550f752022-08-11 19:33:10658PermissionResult
659PermissionControllerImpl::GetPermissionResultForCurrentDocument(
Florian Jackya857d582025-04-10 10:13:33660 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Illia Klimov15550f752022-08-11 19:33:10661 RenderFrameHost* render_frame_host) {
Florian Jackya857d582025-04-10 10:13:33662 auto permission_type =
663 blink::PermissionDescriptorToPermissionType(permission_descriptor);
Florian Jackyaaf42832025-08-19 04:03:26664 std::optional<PermissionResult> permission_result = permission_overrides_.Get(
jalonthomasb3f862a2025-07-22 16:02:23665 render_frame_host->GetLastCommittedOrigin(),
666 render_frame_host->GetMainFrame()->GetLastCommittedOrigin(),
667 permission_type);
Florian Jackyaaf42832025-08-19 04:03:26668 if (permission_result) {
669 return permission_result.value();
Elias Klim1e5178a32023-12-12 21:15:29670 }
Illia Klimov15550f752022-08-11 19:33:10671
672 PermissionControllerDelegate* delegate =
673 browser_context_->GetPermissionControllerDelegate();
Elias Klim1e5178a32023-12-12 21:15:29674 if (!delegate) {
Illia Klimov2c6138b2023-08-14 09:39:25675 return PermissionResult(PermissionStatus::DENIED,
Illia Klimov15550f752022-08-11 19:33:10676 PermissionStatusSource::UNSPECIFIED);
Elias Klim1e5178a32023-12-12 21:15:29677 }
Illia Klimov15550f752022-08-11 19:33:10678
Illia Klimov9777bbb2022-10-11 11:02:01679 PermissionResult result =
Florian Jackya857d582025-04-10 10:13:33680 VerifyContextOfCurrentDocument(permission_type, render_frame_host);
Illia Klimov2c6138b2023-08-14 09:39:25681 if (result.status == PermissionStatus::DENIED) {
Illia Klimov9777bbb2022-10-11 11:02:01682 return result;
Illia Klimov2c6138b2023-08-14 09:39:25683 }
Illia Klimov9777bbb2022-10-11 11:02:01684
Thomas Nguyen235933322024-05-27 14:52:11685 return delegate->GetPermissionResultForCurrentDocument(
Florian Jacky8373f042025-04-16 14:20:53686 permission_descriptor, render_frame_host,
Florian Jackya857d582025-04-10 10:13:33687 /*should_include_device_status=*/false);
Illia Klimov15550f752022-08-11 19:33:10688}
689
690PermissionResult
691PermissionControllerImpl::GetPermissionResultForOriginWithoutContext(
Florian Jackya857d582025-04-10 10:13:33692 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Illia Klimov15550f752022-08-11 19:33:10693 const url::Origin& origin) {
Florian Jackya857d582025-04-10 10:13:33694 return GetPermissionResultForOriginWithoutContext(permission_descriptor,
695 origin, origin);
Illia Klimov15550f752022-08-11 19:33:10696}
697
Christian Dullwebera475f4a2023-08-07 17:04:13698PermissionResult
699PermissionControllerImpl::GetPermissionResultForOriginWithoutContext(
Florian Jackya857d582025-04-10 10:13:33700 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Illia Klimov15550f752022-08-11 19:33:10701 const url::Origin& requesting_origin,
702 const url::Origin& embedding_origin) {
Florian Jackya857d582025-04-10 10:13:33703 auto permission_type =
704 blink::PermissionDescriptorToPermissionType(permission_descriptor);
Florian Jackyaaf42832025-08-19 04:03:26705 std::optional<PermissionResult> permission_result = permission_overrides_.Get(
jalonthomasb3f862a2025-07-22 16:02:23706 requesting_origin, embedding_origin, permission_type);
Florian Jackyaaf42832025-08-19 04:03:26707 if (permission_result) {
708 return permission_result.value();
Christian Dullwebera475f4a2023-08-07 17:04:13709 }
710
711 PermissionControllerDelegate* delegate =
712 browser_context_->GetPermissionControllerDelegate();
713 if (!delegate) {
Illia Klimov2c6138b2023-08-14 09:39:25714 return PermissionResult(PermissionStatus::DENIED,
Christian Dullwebera475f4a2023-08-07 17:04:13715 PermissionStatusSource::UNSPECIFIED);
716 }
717
718 return delegate->GetPermissionResultForOriginWithoutContext(
Florian Jacky8373f042025-04-16 14:20:53719 permission_descriptor, requesting_origin, embedding_origin);
Illia Klimov4a2cb192022-03-15 06:31:35720}
721
Illia Klimov2c6138b2023-08-14 09:39:25722PermissionStatus
Illia Klimov20badfdf2023-03-16 19:53:10723PermissionControllerImpl::GetPermissionStatusForEmbeddedRequester(
Florian Jacky8373f042025-04-16 14:20:53724 const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
Illia Klimov20badfdf2023-03-16 19:53:10725 RenderFrameHost* render_frame_host,
726 const url::Origin& requesting_origin) {
Florian Jackya857d582025-04-10 10:13:33727 auto permission_type =
Florian Jacky8373f042025-04-16 14:20:53728 blink::PermissionDescriptorToPermissionType(permission_descriptor);
Florian Jackya857d582025-04-10 10:13:33729
Illia Klimov20badfdf2023-03-16 19:53:10730 // This API is suited only for `TOP_LEVEL_STORAGE_ACCESS`. Do not use it for
731 // other permissions unless discussed with `permissions-core@`.
Florian Jackya857d582025-04-10 10:13:33732 DCHECK(permission_type == blink::PermissionType::TOP_LEVEL_STORAGE_ACCESS);
Illia Klimov20badfdf2023-03-16 19:53:10733
Florian Jackya857d582025-04-10 10:13:33734 if (permission_type != blink::PermissionType::TOP_LEVEL_STORAGE_ACCESS) {
Illia Klimov2c6138b2023-08-14 09:39:25735 return PermissionStatus::DENIED;
Illia Klimov20badfdf2023-03-16 19:53:10736 }
737
Florian Jackyaaf42832025-08-19 04:03:26738 std::optional<PermissionResult> permission_result = permission_overrides_.Get(
jalonthomasb3f862a2025-07-22 16:02:23739 requesting_origin,
740 render_frame_host->GetMainFrame()->GetLastCommittedOrigin(),
741 permission_type);
Florian Jackyaaf42832025-08-19 04:03:26742 if (permission_result) {
743 return permission_result->status;
Illia Klimov20badfdf2023-03-16 19:53:10744 }
745
746 PermissionControllerDelegate* delegate =
747 browser_context_->GetPermissionControllerDelegate();
748 if (!delegate) {
Illia Klimov2c6138b2023-08-14 09:39:25749 return PermissionStatus::DENIED;
Illia Klimov20badfdf2023-03-16 19:53:10750 }
751
Florian Jackya857d582025-04-10 10:13:33752 if (VerifyContextOfCurrentDocument(permission_type, render_frame_host)
753 .status == PermissionStatus::DENIED) {
Illia Klimov2c6138b2023-08-14 09:39:25754 return PermissionStatus::DENIED;
Illia Klimov20badfdf2023-03-16 19:53:10755 }
756
757 return delegate->GetPermissionStatusForEmbeddedRequester(
Florian Jacky8373f042025-04-16 14:20:53758 permission_descriptor, render_frame_host, requesting_origin);
Illia Klimov20badfdf2023-03-16 19:53:10759}
760
Thomas Nguyen235933322024-05-27 14:52:11761PermissionStatus PermissionControllerImpl::GetCombinedPermissionAndDeviceStatus(
Florian Jackya857d582025-04-10 10:13:33762 const blink::mojom::PermissionDescriptorPtr& permission,
Thomas Nguyen235933322024-05-27 14:52:11763 RenderFrameHost* render_frame_host) {
Mike Westdfbafc5a2025-06-23 09:56:57764 CHECK(PermissionUtil::IsDevicePermission(permission));
Thomas Nguyen235933322024-05-27 14:52:11765 return GetPermissionStatusForCurrentDocumentInternal(
766 permission, render_frame_host, /*should_include_device_status=*/true);
767}
768
Andrey Lushnikovebff0442018-07-12 20:02:58769void PermissionControllerImpl::ResetPermission(PermissionType permission,
770 const GURL& requesting_origin,
771 const GURL& embedding_origin) {
Andrey Lushnikovf3500102018-07-16 19:55:22772 PermissionControllerDelegate* delegate =
773 browser_context_->GetPermissionControllerDelegate();
Elias Klim1e5178a32023-12-12 21:15:29774 if (!delegate) {
Andrey Lushnikovebff0442018-07-12 20:02:58775 return;
Elias Klim1e5178a32023-12-12 21:15:29776 }
Andrey Lushnikovebff0442018-07-12 20:02:58777 delegate->ResetPermission(permission, requesting_origin, embedding_origin);
778}
779
Yifan Luo006519d92024-08-22 16:11:34780void PermissionControllerImpl::PermissionStatusChange(
781 const base::RepeatingCallback<void(PermissionStatus)>& callback,
Ravjit5f6183e2021-07-09 11:12:37782 SubscriptionId subscription_id,
Yifan Luo006519d92024-08-22 16:11:34783 PermissionStatus status,
784 bool ignore_status_override) {
785 // Check if the permission status override should be ignored. The verification
786 // is suppressed if a permission status change was initiated by DevTools. In
787 // all other cases permission status override is always checked.
788 if (ignore_status_override) {
789 callback.Run(status);
790 return;
791 }
792 PermissionStatusSubscription* subscription =
793 subscriptions_.Lookup(subscription_id);
Ravjit5f6183e2021-07-09 11:12:37794 DCHECK(subscription);
Alison Gale59c007a2024-04-20 03:05:40795 // TODO(crbug.com/40056329) Adding this block to prevent crashes while we
Ravjit5f6183e2021-07-09 11:12:37796 // investigate the root cause of the crash. This block will be removed as the
Yifan Luo006519d92024-08-22 16:11:34797 // DCHECK() above should be enough.
Elias Klim1e5178a32023-12-12 21:15:29798 if (!subscription) {
Ravjit5f6183e2021-07-09 11:12:37799 return;
Elias Klim1e5178a32023-12-12 21:15:29800 }
Florian Jackyaaf42832025-08-19 04:03:26801 std::optional<PermissionResult> permission_result = permission_overrides_.Get(
Illia Klimov2c6138b2023-08-14 09:39:25802 url::Origin::Create(subscription->requesting_origin),
jalonthomasb3f862a2025-07-22 16:02:23803 url::Origin::Create(subscription->embedding_origin),
Illia Klimov2c6138b2023-08-14 09:39:25804 subscription->permission);
Florian Jackyaaf42832025-08-19 04:03:26805 if (!permission_result.has_value()) {
Yifan Luo006519d92024-08-22 16:11:34806 callback.Run(status);
Elias Klim1e5178a32023-12-12 21:15:29807 }
Andrey Lushnikov36299bc2018-08-23 22:09:54808}
809
Yifan Luo006519d92024-08-22 16:11:34810PermissionController::SubscriptionId
Balazs Engedy33b441e2023-12-12 18:53:42811PermissionControllerImpl::SubscribeToPermissionStatusChange(
Andrey Lushnikovebff0442018-07-12 20:02:58812 PermissionType permission,
Robbie McElrath8d5602a2022-04-01 17:39:18813 RenderProcessHost* render_process_host,
Raymes Khoury3ef4f6e2018-08-09 09:34:48814 RenderFrameHost* render_frame_host,
Andrey Lushnikovebff0442018-07-12 20:02:58815 const GURL& requesting_origin,
Andy Paicu9d70da42024-05-10 22:24:39816 bool should_include_device_status,
Illia Klimov2c6138b2023-08-14 09:39:25817 const base::RepeatingCallback<void(PermissionStatus)>& callback) {
Robbie McElrath8d5602a2022-04-01 17:39:18818 DCHECK(!render_process_host || !render_frame_host);
Yifan Luo006519d92024-08-22 16:11:34819
820 auto id = subscription_id_generator_.GenerateNextId();
821 auto subscription = std::make_unique<PermissionStatusSubscription>();
Andrey Lushnikov36299bc2018-08-23 22:09:54822 subscription->permission = permission;
Yifan Luo006519d92024-08-22 16:11:34823 subscription->callback =
824 base::BindRepeating(&PermissionControllerImpl::PermissionStatusChange,
825 base::Unretained(this), callback, id);
Andrey Lushnikov36299bc2018-08-23 22:09:54826 subscription->requesting_origin = requesting_origin;
Yifan Luo006519d92024-08-22 16:11:34827 subscription->should_include_device_status = should_include_device_status;
Andrey Lushnikov36299bc2018-08-23 22:09:54828
829 // The RFH may be null if the request is for a worker.
830 if (render_frame_host) {
Andrey Lushnikov36299bc2018-08-23 22:09:54831 subscription->embedding_origin =
Henrique Ferreirof89870f2022-03-30 17:08:13832 PermissionUtil::GetLastCommittedOriginAsURL(
833 render_frame_host->GetMainFrame());
Andrey Lushnikov36299bc2018-08-23 22:09:54834 subscription->render_frame_id = render_frame_host->GetRoutingID();
Emily Andrewsd15fd762024-12-10 20:41:54835 subscription->render_process_id =
836 render_frame_host->GetProcess()->GetDeprecatedID();
Andrey Lushnikov36299bc2018-08-23 22:09:54837 } else {
838 subscription->embedding_origin = requesting_origin;
839 subscription->render_frame_id = -1;
Robbie McElrath8d5602a2022-04-01 17:39:18840 subscription->render_process_id =
Emily Andrewsd15fd762024-12-10 20:41:54841 render_process_host ? render_process_host->GetDeprecatedID() : -1;
Andrey Lushnikov36299bc2018-08-23 22:09:54842 }
Yifan Luo006519d92024-08-22 16:11:34843 subscriptions_.AddWithID(std::move(subscription), id);
Andrey Lushnikov36299bc2018-08-23 22:09:54844
Andrey Lushnikovf3500102018-07-16 19:55:22845 PermissionControllerDelegate* delegate =
846 browser_context_->GetPermissionControllerDelegate();
Andrey Lushnikov36299bc2018-08-23 22:09:54847 if (delegate) {
Yifan Luo006519d92024-08-22 16:11:34848 delegate->SetSubscriptions(&subscriptions_);
849 delegate->OnPermissionStatusChangeSubscriptionAdded(id);
Andrey Lushnikov36299bc2018-08-23 22:09:54850 }
Balazs Engedyad1489b2021-03-31 07:47:19851 return id;
Andrey Lushnikovebff0442018-07-12 20:02:58852}
853
Balazs Engedy33b441e2023-12-12 18:53:42854void PermissionControllerImpl::UnsubscribeFromPermissionStatusChange(
Balazs Engedyad1489b2021-03-31 07:47:19855 SubscriptionId subscription_id) {
Yifan Luo006519d92024-08-22 16:11:34856 PermissionStatusSubscription* subscription =
857 subscriptions_.Lookup(subscription_id);
Elias Klim1e5178a32023-12-12 21:15:29858 if (!subscription) {
Andrey Lushnikov36299bc2018-08-23 22:09:54859 return;
Elias Klim1e5178a32023-12-12 21:15:29860 }
Andrey Lushnikovf3500102018-07-16 19:55:22861 PermissionControllerDelegate* delegate =
862 browser_context_->GetPermissionControllerDelegate();
Balazs Engedyad1489b2021-03-31 07:47:19863 if (delegate) {
Yifan Luo006519d92024-08-22 16:11:34864 delegate->UnsubscribeFromPermissionStatusChange(subscription_id);
Andrey Lushnikov36299bc2018-08-23 22:09:54865 }
866 subscriptions_.Remove(subscription_id);
Andrey Lushnikovebff0442018-07-12 20:02:58867}
868
Illia Klimove406ecc12022-11-22 15:53:29869bool PermissionControllerImpl::IsSubscribedToPermissionChangeEvent(
870 blink::PermissionType permission,
871 RenderFrameHost* render_frame_host) {
872 PermissionServiceContext* permission_service_context =
873 PermissionServiceContext::GetForCurrentDocument(render_frame_host);
Thomas Nguyen1c300152023-02-02 09:56:11874 if (!permission_service_context) {
875 return false;
876 }
Illia Klimove406ecc12022-11-22 15:53:29877
878 return permission_service_context->GetOnchangeEventListeners().find(
879 permission) !=
880 permission_service_context->GetOnchangeEventListeners().end();
881}
882
Arthur Sonzognic686e8f2024-01-11 08:36:37883std::optional<gfx::Rect>
Thomas Nguyen583f07e2023-07-19 17:45:37884PermissionControllerImpl::GetExclusionAreaBoundsInScreen(
885 WebContents* web_contents) const {
886 if (exclusion_area_bounds_for_tests_.has_value()) {
887 return exclusion_area_bounds_for_tests_;
888 }
889 PermissionControllerDelegate* delegate =
890 browser_context_->GetPermissionControllerDelegate();
891 return delegate ? delegate->GetExclusionAreaBoundsInScreen(web_contents)
Arthur Sonzognic686e8f2024-01-11 08:36:37892 : std::nullopt;
Thomas Nguyen583f07e2023-07-19 17:45:37893}
894
Illia Klimove406ecc12022-11-22 15:53:29895void PermissionControllerImpl::NotifyEventListener() {
Arthur Sonzognifd1e08d2024-03-05 15:59:36896 if (onchange_listeners_callback_for_tests_) {
897 onchange_listeners_callback_for_tests_.Run();
Illia Klimove406ecc12022-11-22 15:53:29898 }
899}
900
Matt Reichhoff2dbcfbd2023-01-03 17:48:33901} // namespace content