Avi Drissman | 8ba1bad | 2022-09-13 19:22:36 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 5 | #include "components/permissions/permission_context_base.h" |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 6 | |
avi | b896c71 | 2015-12-26 02:10:43 | [diff] [blame] | 7 | #include <stddef.h> |
meredithl | 62b8c3d | 2017-01-10 05:47:53 | [diff] [blame] | 8 | |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 9 | #include <memory> |
Zelin Liu | 2046c842 | 2024-08-27 20:25:05 | [diff] [blame] | 10 | #include <optional> |
meredithl | 62b8c3d | 2017-01-10 05:47:53 | [diff] [blame] | 11 | #include <string> |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 12 | #include <string_view> |
dcheng | e73d8520c | 2015-12-27 01:19:09 | [diff] [blame] | 13 | #include <utility> |
avi | b896c71 | 2015-12-26 02:10:43 | [diff] [blame] | 14 | |
Avi Drissman | 12be031 | 2023-01-11 09:16:09 | [diff] [blame] | 15 | #include "base/functional/bind.h" |
| 16 | #include "base/functional/callback.h" |
Florian Jacky | 11f9810 | 2025-05-20 15:57:18 | [diff] [blame] | 17 | #include "base/functional/callback_forward.h" |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 18 | #include "base/logging.h" |
Florian Jacky | 11f9810 | 2025-05-20 15:57:18 | [diff] [blame] | 19 | #include "base/memory/weak_ptr.h" |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 20 | #include "base/metrics/field_trial_params.h" |
David Sanders | 88b2443 | 2022-02-28 01:10:02 | [diff] [blame] | 21 | #include "base/observer_list.h" |
meredithl | 03b1285 | 2017-01-25 05:08:01 | [diff] [blame] | 22 | #include "base/time/time.h" |
avi | b896c71 | 2015-12-26 02:10:43 | [diff] [blame] | 23 | #include "build/build_config.h" |
Raymes Khoury | 47df4b2 | 2018-05-10 04:30:17 | [diff] [blame] | 24 | #include "components/content_settings/core/browser/content_settings_registry.h" |
Christian Dullweber | a68ee8d | 2022-09-09 12:47:31 | [diff] [blame] | 25 | #include "components/content_settings/core/browser/content_settings_utils.h" |
mukai | 8eaec82 | 2014-10-25 17:53:16 | [diff] [blame] | 26 | #include "components/content_settings/core/browser/host_content_settings_map.h" |
Andy Paicu | 24b02bb | 2023-09-06 14:49:08 | [diff] [blame] | 27 | #include "components/content_settings/core/common/content_settings.h" |
Andy Paicu | 72b4edf | 2023-09-15 09:52:43 | [diff] [blame] | 28 | #include "components/content_settings/core/common/content_settings_pattern.h" |
Matt Reichhoff | dae0bfb | 2023-01-06 19:55:31 | [diff] [blame] | 29 | #include "components/content_settings/core/common/content_settings_types.h" |
Florian Jacky | 989b41b | 2023-07-31 16:33:42 | [diff] [blame] | 30 | #include "components/content_settings/core/common/features.h" |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 31 | #include "components/permissions/features.h" |
Florian Jacky | 989b41b | 2023-07-31 16:33:42 | [diff] [blame] | 32 | #include "components/permissions/permission_context_base.h" |
Clark DuVall | 03628dedc | 2020-01-30 22:25:52 | [diff] [blame] | 33 | #include "components/permissions/permission_decision_auto_blocker.h" |
Clark DuVall | 484c256 | 2020-01-23 22:05:09 | [diff] [blame] | 34 | #include "components/permissions/permission_request.h" |
| 35 | #include "components/permissions/permission_request_id.h" |
Clark DuVall | 5ca4ae1 | 2020-02-19 22:25:27 | [diff] [blame] | 36 | #include "components/permissions/permission_request_manager.h" |
Clark DuVall | 38189ee | 2020-02-14 02:30:28 | [diff] [blame] | 37 | #include "components/permissions/permission_uma_util.h" |
Clark DuVall | 732778e | 2020-01-27 18:13:58 | [diff] [blame] | 38 | #include "components/permissions/permission_util.h" |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 39 | #include "components/permissions/permissions_client.h" |
Bret Sepulveda | 5327d8b5 | 2021-07-21 17:44:23 | [diff] [blame] | 40 | #include "components/permissions/request_type.h" |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 41 | #include "components/permissions/resolvers/content_setting_permission_resolver.h" |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 42 | #include "content/public/browser/browser_thread.h" |
Carlos Caballero | b6b46648 | 2019-11-29 13:33:18 | [diff] [blame] | 43 | #include "content/public/browser/global_routing_id.h" |
Robert Ogden | 2437524 | 2018-10-05 21:16:26 | [diff] [blame] | 44 | #include "content/public/browser/navigation_entry.h" |
kcarattini | 5d97c63 | 2015-11-05 00:38:29 | [diff] [blame] | 45 | #include "content/public/browser/render_frame_host.h" |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 46 | #include "content/public/browser/web_contents.h" |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 47 | #include "content/public/common/content_features.h" |
Frédéric Wang | 073e74a | 2020-12-16 17:43:32 | [diff] [blame] | 48 | #include "services/network/public/cpp/is_potentially_trustworthy.h" |
Sandor «Alex» Major | e9545a7 | 2025-01-31 20:40:46 | [diff] [blame] | 49 | #include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom.h" |
dominickn | 6947d75 | 2016-08-10 02:00:06 | [diff] [blame] | 50 | #include "url/gurl.h" |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 51 | |
Dave Tapuska | 28e05eda | 2023-08-28 19:52:21 | [diff] [blame] | 52 | #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) |
Kevin McNee | 0340384 | 2023-08-28 14:48:36 | [diff] [blame] | 53 | #include "components/guest_view/browser/guest_view_base.h" |
| 54 | #endif |
| 55 | |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 56 | #if BUILDFLAG(IS_ANDROID) |
| 57 | #include "components/permissions/android/android_permission_util.h" |
| 58 | #include "ui/android/window_android.h" |
| 59 | #endif |
| 60 | |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 61 | namespace permissions { |
dominickn | d9fb73c1 | 2017-03-01 03:34:18 | [diff] [blame] | 62 | namespace { |
| 63 | |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 64 | using PermissionStatus = blink::mojom::PermissionStatus; |
| 65 | |
Julie Jeongeun Kim | a50467b | 2021-12-24 02:40:34 | [diff] [blame] | 66 | void LogPermissionBlockedMessage(content::RenderFrameHost* rfh, |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 67 | std::string_view reason, |
dominickn | d9fb73c1 | 2017-03-01 03:34:18 | [diff] [blame] | 68 | ContentSettingsType type) { |
Julie Jeongeun Kim | a50467b | 2021-12-24 02:40:34 | [diff] [blame] | 69 | rfh->GetOutermostMainFrame()->AddMessageToConsole( |
Abhijeet Kandalkar | a5928a0a | 2019-03-13 05:04:42 | [diff] [blame] | 70 | blink::mojom::ConsoleMessageLevel::kWarning, |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 71 | base::StrCat({PermissionUtil::GetPermissionString(type), |
| 72 | " permission has been blocked", reason})); |
dominickn | d9fb73c1 | 2017-03-01 03:34:18 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | } // namespace |
| 76 | |
kcarattini | 2ee48ad5 | 2015-10-26 23:45:31 | [diff] [blame] | 77 | // static |
| 78 | const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] = |
| 79 | "PermissionsKillSwitch"; |
| 80 | // static |
| 81 | const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] = |
| 82 | "blocked"; |
meredithl | 62b8c3d | 2017-01-10 05:47:53 | [diff] [blame] | 83 | |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 84 | PermissionContextBase::PermissionContextBase( |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 85 | content::BrowserContext* browser_context, |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 86 | ContentSettingsType content_settings_type, |
Sandor «Alex» Major | e9545a7 | 2025-01-31 20:40:46 | [diff] [blame] | 87 | network::mojom::PermissionsPolicyFeature permissions_policy_feature) |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 88 | : browser_context_(browser_context), |
lshang | 88ec36a | 2015-12-09 04:50:17 | [diff] [blame] | 89 | content_settings_type_(content_settings_type), |
Charlie Hu | e20fe2f | 2021-03-07 03:39:59 | [diff] [blame] | 90 | permissions_policy_feature_(permissions_policy_feature) { |
Kevin McNee | 0340384 | 2023-08-28 14:48:36 | [diff] [blame] | 91 | CHECK(permissions::PermissionUtil::IsPermission(content_settings_type_)); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | PermissionContextBase::~PermissionContextBase() { |
James Hollyer | d281a731 | 2021-04-29 21:07:59 | [diff] [blame] | 95 | DCHECK(permission_observers_.empty()); |
miguelg | fa05207 | 2014-09-29 15:31:38 | [diff] [blame] | 96 | DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | void PermissionContextBase::RequestPermission( |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 100 | std::unique_ptr<PermissionRequestData> request_data, |
danakj | 47c8fb5 | 2019-05-02 16:34:36 | [diff] [blame] | 101 | BrowserPermissionCallback callback) { |
miguelg | fa05207 | 2014-09-29 15:31:38 | [diff] [blame] | 102 | DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 103 | |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 104 | content::RenderFrameHost* const rfh = content::RenderFrameHost::FromID( |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 105 | request_data->id.global_render_frame_host_id()); |
Illia Klimov | ba5d976 | 2022-05-27 14:10:40 | [diff] [blame] | 106 | |
| 107 | if (!rfh) { |
| 108 | // Permission request is not allowed without a valid RenderFrameHost. |
| 109 | std::move(callback).Run(CONTENT_SETTING_ASK); |
| 110 | return; |
| 111 | } |
| 112 | |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 113 | request_data |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 114 | ->WithRequestingOrigin( |
| 115 | request_data->requesting_origin.DeprecatedGetOriginAsURL()) |
Ari Chivukula | f6f09ba | 2025-03-04 20:01:34 | [diff] [blame] | 116 | .WithEmbeddingOrigin(GetEffectiveEmbedderOrigin(rfh)); |
johnme | c36a56c | 2015-12-02 15:56:42 | [diff] [blame] | 117 | |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 118 | if (!request_data->requesting_origin.is_valid() || |
| 119 | !request_data->embedding_origin.is_valid()) { |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 120 | std::string type_name = |
| 121 | PermissionUtil::GetPermissionString(content_settings_type_); |
johnme | c36a56c | 2015-12-02 15:56:42 | [diff] [blame] | 122 | |
| 123 | DVLOG(1) << "Attempt to use " << type_name |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 124 | << " from an invalid URL: " << request_data->requesting_origin |
| 125 | << "," << request_data->embedding_origin << " (" << type_name |
johnme | c36a56c | 2015-12-02 15:56:42 | [diff] [blame] | 126 | << " is not supported in popups)"; |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 127 | NotifyPermissionSet(*request_data, std::move(callback), |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 128 | /*persist=*/false, CONTENT_SETTING_BLOCK, |
| 129 | /*is_one_time=*/false, |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 130 | /*is_final_decision=*/true); |
johnme | c36a56c | 2015-12-02 15:56:42 | [diff] [blame] | 131 | return; |
| 132 | } |
| 133 | |
Timothy Loh | 8fbdac5 | 2018-03-15 03:34:30 | [diff] [blame] | 134 | // Check the content setting to see if the user has already made a decision, |
| 135 | // or if the origin is under embargo. If so, respect that decision. |
Henrique Ferreiro | f89870f | 2022-03-30 17:08:13 | [diff] [blame] | 136 | DCHECK(rfh); |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 137 | content::PermissionResult result = GetPermissionStatus( |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 138 | *request_data->resolver, rfh, request_data->requesting_origin, |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 139 | request_data->embedding_origin); |
meredithl | cda94daf | 2017-01-19 03:03:35 | [diff] [blame] | 140 | |
Andy Paicu | 0e16f858 | 2023-09-28 08:34:34 | [diff] [blame] | 141 | bool status_ignorable = PermissionUtil::CanPermissionRequestIgnoreStatus( |
| 142 | request_data, result.source); |
| 143 | |
| 144 | if (!status_ignorable && (result.status == PermissionStatus::GRANTED || |
| 145 | result.status == PermissionStatus::DENIED)) { |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 146 | static constexpr char kResetInstructions[] = |
| 147 | " This can be reset in " |
| 148 | #if BUILDFLAG(IS_ANDROID) |
| 149 | "Site Settings" |
| 150 | #else |
| 151 | "Page Info which can be accessed by clicking the tune icon next to " |
| 152 | "the URL" |
| 153 | #endif |
| 154 | ". See https://www.chromestatus.com/feature/6443143280984064 for " |
| 155 | "more information."; |
dominickn | 728c502 | 2017-04-04 09:14:15 | [diff] [blame] | 156 | switch (result.source) { |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 157 | case content::PermissionStatusSource::KILL_SWITCH: |
dominickn | 728c502 | 2017-04-04 09:14:15 | [diff] [blame] | 158 | // Block the request and log to the developer console. |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 159 | static constexpr char kPermissionBlockedKillSwitchReason[] = "."; |
| 160 | LogPermissionBlockedMessage(rfh, kPermissionBlockedKillSwitchReason, |
dominickn | 728c502 | 2017-04-04 09:14:15 | [diff] [blame] | 161 | content_settings_type_); |
Illia Klimov | b5f70f1 | 2023-03-06 13:13:00 | [diff] [blame] | 162 | PermissionUmaUtil::RecordPermissionRequestedFromFrame( |
| 163 | content_settings_type_, rfh); |
danakj | 47c8fb5 | 2019-05-02 16:34:36 | [diff] [blame] | 164 | std::move(callback).Run(CONTENT_SETTING_BLOCK); |
dominickn | 728c502 | 2017-04-04 09:14:15 | [diff] [blame] | 165 | return; |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 166 | case content::PermissionStatusSource::MULTIPLE_DISMISSALS: |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 167 | static constexpr char kPermissionBlockedRepeatedDismissalsReason[] = |
| 168 | " as the user has dismissed the permission prompt several times."; |
| 169 | LogPermissionBlockedMessage( |
| 170 | rfh, |
| 171 | base::StrCat({kPermissionBlockedRepeatedDismissalsReason, |
| 172 | kResetInstructions}), |
| 173 | content_settings_type_); |
Illia Klimov | b5f70f1 | 2023-03-06 13:13:00 | [diff] [blame] | 174 | PermissionUmaUtil::RecordPermissionRequestedFromFrame( |
| 175 | content_settings_type_, rfh); |
dominickn | 728c502 | 2017-04-04 09:14:15 | [diff] [blame] | 176 | break; |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 177 | case content::PermissionStatusSource::MULTIPLE_IGNORES: |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 178 | static constexpr char kPermissionBlockedRepeatedIgnoresReason[] = |
| 179 | " as the user has ignored the permission prompt several times."; |
| 180 | LogPermissionBlockedMessage( |
| 181 | rfh, |
| 182 | base::StrCat( |
| 183 | {kPermissionBlockedRepeatedIgnoresReason, kResetInstructions}), |
| 184 | content_settings_type_); |
Illia Klimov | b5f70f1 | 2023-03-06 13:13:00 | [diff] [blame] | 185 | PermissionUmaUtil::RecordPermissionRequestedFromFrame( |
| 186 | content_settings_type_, rfh); |
dominickn | 728c502 | 2017-04-04 09:14:15 | [diff] [blame] | 187 | break; |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 188 | case content::PermissionStatusSource::FEATURE_POLICY: |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 189 | static constexpr char kPermissionBlockedPermissionsPolicyReason[] = |
| 190 | " because of a permissions policy applied to the current document. " |
Elias Klim | 8897d61 | 2025-04-29 11:06:10 | [diff] [blame] | 191 | "See https://crbug.com/414348233 for more details."; |
Julie Jeongeun Kim | a50467b | 2021-12-24 02:40:34 | [diff] [blame] | 192 | LogPermissionBlockedMessage(rfh, |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 193 | kPermissionBlockedPermissionsPolicyReason, |
Raymes Khoury | 42aff11 | 2017-10-18 06:47:06 | [diff] [blame] | 194 | content_settings_type_); |
| 195 | break; |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 196 | case content::PermissionStatusSource::RECENT_DISPLAY: |
Peter Kasting | c70def2 | 2025-01-06 22:49:48 | [diff] [blame] | 197 | static constexpr char kPermissionBlockedRecentDisplayReason[] = |
| 198 | " as the prompt has already been displayed to the user recently."; |
| 199 | LogPermissionBlockedMessage(rfh, kPermissionBlockedRecentDisplayReason, |
Zachary Tan | 11b28b1 | 2023-02-09 13:53:36 | [diff] [blame] | 200 | content_settings_type_); |
| 201 | break; |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 202 | case content::PermissionStatusSource::UNSPECIFIED: |
Illia Klimov | b5f70f1 | 2023-03-06 13:13:00 | [diff] [blame] | 203 | PermissionUmaUtil::RecordPermissionRequestedFromFrame( |
| 204 | content_settings_type_, rfh); |
| 205 | break; |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 206 | case content::PermissionStatusSource::FENCED_FRAME: |
| 207 | case content::PermissionStatusSource::INSECURE_ORIGIN: |
| 208 | case content::PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN: |
dominickn | 728c502 | 2017-04-04 09:14:15 | [diff] [blame] | 209 | break; |
dominickn | 2391315 | 2017-02-23 12:04:02 | [diff] [blame] | 210 | } |
| 211 | |
| 212 | // If we are under embargo, record the embargo reason for which we have |
| 213 | // suppressed the prompt. |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 214 | PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(result.source); |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 215 | NotifyPermissionSet( |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 216 | *request_data, std::move(callback), |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 217 | /*persist=*/false, |
| 218 | PermissionUtil::PermissionStatusToContentSetting(result.status), |
| 219 | /*is_one_time=*/false, |
| 220 | /*is_final_decision=*/true); |
meredithl | cda94daf | 2017-01-19 03:03:35 | [diff] [blame] | 221 | return; |
| 222 | } |
| 223 | |
Illia Klimov | b5f70f1 | 2023-03-06 13:13:00 | [diff] [blame] | 224 | PermissionUmaUtil::RecordPermissionRequestedFromFrame(content_settings_type_, |
| 225 | rfh); |
| 226 | |
dominickn | 2391315 | 2017-02-23 12:04:02 | [diff] [blame] | 227 | // We are going to show a prompt now. |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 228 | PermissionUmaUtil::PermissionRequested(content_settings_type_); |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 229 | PermissionUmaUtil::RecordEmbargoPromptSuppression( |
| 230 | PermissionEmbargoStatus::NOT_EMBARGOED); |
johnme | c36a56c | 2015-12-02 15:56:42 | [diff] [blame] | 231 | |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 232 | DecidePermission(std::move(request_data), std::move(callback)); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 233 | } |
| 234 | |
Illia Klimov | 0e1f7e00 | 2022-10-13 15:13:52 | [diff] [blame] | 235 | bool PermissionContextBase::IsRestrictedToSecureOrigins() const { |
| 236 | return true; |
| 237 | } |
| 238 | |
benwells | 0b3748a | 2017-03-21 06:28:40 | [diff] [blame] | 239 | void PermissionContextBase::UserMadePermissionDecision( |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 240 | const PermissionRequestID& id, |
benwells | 0b3748a | 2017-03-21 06:28:40 | [diff] [blame] | 241 | const GURL& requesting_origin, |
| 242 | const GURL& embedding_origin, |
| 243 | ContentSetting content_setting) {} |
| 244 | |
Darwin Huang | 2aedfd56 | 2021-04-30 01:39:17 | [diff] [blame] | 245 | std::unique_ptr<PermissionRequest> |
| 246 | PermissionContextBase::CreatePermissionRequest( |
Darwin Huang | 2aedfd56 | 2021-04-30 01:39:17 | [diff] [blame] | 247 | content::WebContents* web_contents, |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 248 | std::unique_ptr<PermissionRequestData> request_data, |
Bret Sepulveda | 5327d8b5 | 2021-07-21 17:44:23 | [diff] [blame] | 249 | PermissionRequest::PermissionDecidedCallback permission_decided_callback, |
Florian Jacky | 11f9810 | 2025-05-20 15:57:18 | [diff] [blame] | 250 | base::OnceClosure request_finished_callback) const { |
Bret Sepulveda | 5327d8b5 | 2021-07-21 17:44:23 | [diff] [blame] | 251 | return std::make_unique<PermissionRequest>( |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 252 | std::move(request_data), std::move(permission_decided_callback), |
Florian Jacky | 11f9810 | 2025-05-20 15:57:18 | [diff] [blame] | 253 | std::move(request_finished_callback), UsesAutomaticEmbargo()); |
Elad Alon | b333180 | 2024-01-24 22:29:36 | [diff] [blame] | 254 | } |
| 255 | |
| 256 | bool PermissionContextBase::UsesAutomaticEmbargo() const { |
| 257 | return true; |
Darwin Huang | 2aedfd56 | 2021-04-30 01:39:17 | [diff] [blame] | 258 | } |
| 259 | |
Andy Paicu | a0693aac | 2025-02-12 18:42:32 | [diff] [blame] | 260 | const PermissionRequest* PermissionContextBase::FindPermissionRequest( |
| 261 | const PermissionRequestID& id) const { |
| 262 | const auto request = pending_requests_.find(id.ToString()); |
| 263 | |
| 264 | if (request == pending_requests_.end()) { |
| 265 | return nullptr; |
| 266 | } |
| 267 | |
| 268 | return request->second.first.get(); |
| 269 | } |
| 270 | |
Ari Chivukula | f6f09ba | 2025-03-04 20:01:34 | [diff] [blame] | 271 | GURL PermissionContextBase::GetEffectiveEmbedderOrigin( |
| 272 | content::RenderFrameHost* rfh) const { |
| 273 | return PermissionUtil::GetLastCommittedOriginAsURL(rfh->GetMainFrame()); |
| 274 | } |
| 275 | |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 276 | content::PermissionResult PermissionContextBase::GetPermissionStatus( |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 277 | const PermissionResolver& resolver, |
raymes | f6104d49 | 2017-03-09 01:20:18 | [diff] [blame] | 278 | content::RenderFrameHost* render_frame_host, |
miguelg | 7e9a98d | 2014-10-31 14:21:37 | [diff] [blame] | 279 | const GURL& requesting_origin, |
| 280 | const GURL& embedding_origin) const { |
kcarattini | 2ee48ad5 | 2015-10-26 23:45:31 | [diff] [blame] | 281 | // If the permission has been disabled through Finch, block all requests. |
raymes | ab35971 | 2017-02-15 06:23:25 | [diff] [blame] | 282 | if (IsPermissionKillSwitchOn()) { |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 283 | return content::PermissionResult( |
| 284 | PermissionStatus::DENIED, content::PermissionStatusSource::KILL_SWITCH); |
raymes | ab35971 | 2017-02-15 06:23:25 | [diff] [blame] | 285 | } |
kcarattini | 2ee48ad5 | 2015-10-26 23:45:31 | [diff] [blame] | 286 | |
Rohan Pavone | 013c400 | 2019-08-21 20:13:52 | [diff] [blame] | 287 | if (!IsPermissionAvailableToOrigins(requesting_origin, embedding_origin)) { |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 288 | return content::PermissionResult( |
| 289 | PermissionStatus::DENIED, |
| 290 | content::PermissionStatusSource::INSECURE_ORIGIN); |
mlamouri | a31c6ff1 | 2015-06-01 15:40:52 | [diff] [blame] | 291 | } |
| 292 | |
Charlie Hu | 5130d25e | 2021-03-05 21:53:39 | [diff] [blame] | 293 | // Check whether the feature is enabled for the frame by permissions policy. |
| 294 | // We can only do this when a RenderFrameHost has been provided. |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 295 | if (render_frame_host && |
Charlie Hu | bb5943d | 2021-03-09 19:46:12 | [diff] [blame] | 296 | !PermissionAllowedByPermissionsPolicy(render_frame_host)) { |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 297 | return content::PermissionResult( |
| 298 | PermissionStatus::DENIED, |
| 299 | content::PermissionStatusSource::FEATURE_POLICY); |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 300 | } |
| 301 | |
Robert Ogden | 2437524 | 2018-10-05 21:16:26 | [diff] [blame] | 302 | if (render_frame_host) { |
| 303 | content::WebContents* web_contents = |
| 304 | content::WebContents::FromRenderFrameHost(render_frame_host); |
| 305 | |
| 306 | // Automatically deny all HTTP or HTTPS requests where the virtual URL and |
| 307 | // the loaded URL are for different origins. The loaded URL is the one |
| 308 | // actually in the renderer, but the virtual URL is the one |
| 309 | // seen by the user. This may be very confusing for a user to see in a |
| 310 | // permissions request. |
Lucas Furukawa Gadani | 5553a15 | 2019-01-08 18:55:57 | [diff] [blame] | 311 | content::NavigationEntry* entry = |
Robert Ogden | 2437524 | 2018-10-05 21:16:26 | [diff] [blame] | 312 | web_contents->GetController().GetLastCommittedEntry(); |
| 313 | if (entry) { |
| 314 | const GURL virtual_url = entry->GetVirtualURL(); |
| 315 | const GURL loaded_url = entry->GetURL(); |
| 316 | if (virtual_url.SchemeIsHTTPOrHTTPS() && |
| 317 | loaded_url.SchemeIsHTTPOrHTTPS() && |
Lukasz Anforowicz | d00c1ed | 2022-01-13 05:25:10 | [diff] [blame] | 318 | !url::IsSameOriginWith(virtual_url, loaded_url)) { |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 319 | return content::PermissionResult( |
| 320 | PermissionStatus::DENIED, |
| 321 | content::PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN); |
Robert Ogden | 2437524 | 2018-10-05 21:16:26 | [diff] [blame] | 322 | } |
| 323 | } |
| 324 | } |
| 325 | |
Dave Tapuska | 28e05eda | 2023-08-28 19:52:21 | [diff] [blame] | 326 | #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) |
Zelin Liu | 2046c842 | 2024-08-27 20:25:05 | [diff] [blame] | 327 | guest_view::GuestViewBase* guest = |
| 328 | guest_view::GuestViewBase::FromRenderFrameHost(render_frame_host); |
| 329 | if (guest) { |
| 330 | // Content inside GuestView instances may have different permission |
| 331 | // behavior. |
| 332 | std::optional<content::PermissionResult> maybe_result = |
| 333 | guest->OverridePermissionResult(content_settings_type_); |
| 334 | if (maybe_result.has_value()) { |
| 335 | return maybe_result.value(); |
| 336 | } |
| 337 | // Some GuestViews are loaded in a separate StoragePartition. Given that |
| 338 | // permissions are scoped to a BrowserContext, not a StoragePartition, we |
| 339 | // may have a situation where a user has granted a permission to an origin |
| 340 | // in a tab and then visits the same origin in a guest. This would lead to |
| 341 | // inappropriate sharing of the permission with the guest. To mitigate this, |
| 342 | // we drop permission requests from guests for cases where it's not possible |
| 343 | // for the guest to have been granted the permission. Note that sharing of |
| 344 | // permissions that the guest could legitimately be granted is still |
| 345 | // possible. |
| 346 | // TODO(crbug.com/40068594): Scope granted permissions to a |
| 347 | // StoragePartition. |
| 348 | if (base::FeatureList::IsEnabled( |
| 349 | features::kMitigateUnpartitionedWebviewPermissions) && |
| 350 | !guest->IsPermissionRequestable(content_settings_type_)) { |
Kevin McNee | 0340384 | 2023-08-28 14:48:36 | [diff] [blame] | 351 | return content::PermissionResult( |
| 352 | PermissionStatus::DENIED, |
| 353 | content::PermissionStatusSource::UNSPECIFIED); |
| 354 | } |
| 355 | } |
| 356 | #endif |
| 357 | |
raymes | f6104d49 | 2017-03-09 01:20:18 | [diff] [blame] | 358 | ContentSetting content_setting = GetPermissionStatusInternal( |
| 359 | render_frame_host, requesting_origin, embedding_origin); |
raymes | ab35971 | 2017-02-15 06:23:25 | [diff] [blame] | 360 | |
Anatoliy Potapchuk | 57f8309 | 2019-11-15 13:42:22 | [diff] [blame] | 361 | if (content_setting != CONTENT_SETTING_ASK) { |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 362 | return content::PermissionResult( |
| 363 | PermissionUtil::ContentSettingToPermissionStatus(content_setting), |
| 364 | content::PermissionStatusSource::UNSPECIFIED); |
Anatoliy Potapchuk | 57f8309 | 2019-11-15 13:42:22 | [diff] [blame] | 365 | } |
Anatoliy Potapchuk | 57f8309 | 2019-11-15 13:42:22 | [diff] [blame] | 366 | |
Elad Alon | b333180 | 2024-01-24 22:29:36 | [diff] [blame] | 367 | if (UsesAutomaticEmbargo()) { |
Arthur Sonzogni | c571efb | 2024-01-26 20:26:18 | [diff] [blame] | 368 | std::optional<content::PermissionResult> result = |
Elad Alon | b333180 | 2024-01-24 22:29:36 | [diff] [blame] | 369 | PermissionsClient::Get() |
| 370 | ->GetPermissionDecisionAutoBlocker(browser_context_) |
| 371 | ->GetEmbargoResult(requesting_origin, content_settings_type_); |
| 372 | if (result) { |
| 373 | DCHECK(result->status == PermissionStatus::DENIED); |
| 374 | return result.value(); |
| 375 | } |
Peter Kotwicz | 63559a8 | 2022-06-07 03:46:35 | [diff] [blame] | 376 | } |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 377 | return content::PermissionResult( |
| 378 | PermissionStatus::ASK, content::PermissionStatusSource::UNSPECIFIED); |
miguelg | 7e9a98d | 2014-10-31 14:21:37 | [diff] [blame] | 379 | } |
| 380 | |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 381 | content::PermissionResult PermissionContextBase::GetPermissionStatus( |
| 382 | const blink::mojom::PermissionDescriptorPtr& permission_descriptor, |
| 383 | content::RenderFrameHost* render_frame_host, |
| 384 | const GURL& requesting_origin, |
| 385 | const GURL& embedding_origin) const { |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 386 | return GetPermissionStatus(*CreatePermissionResolver(permission_descriptor), |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 387 | render_frame_host, requesting_origin, |
| 388 | embedding_origin); |
| 389 | } |
| 390 | |
Rohan Pavone | 013c400 | 2019-08-21 20:13:52 | [diff] [blame] | 391 | bool PermissionContextBase::IsPermissionAvailableToOrigins( |
| 392 | const GURL& requesting_origin, |
| 393 | const GURL& embedding_origin) const { |
| 394 | if (IsRestrictedToSecureOrigins()) { |
Frédéric Wang | 073e74a | 2020-12-16 17:43:32 | [diff] [blame] | 395 | if (!network::IsUrlPotentiallyTrustworthy(requesting_origin)) |
Rohan Pavone | 013c400 | 2019-08-21 20:13:52 | [diff] [blame] | 396 | return false; |
| 397 | |
| 398 | // TODO(raymes): We should check the entire chain of embedders here whenever |
| 399 | // possible as this corresponds to the requirements of the secure contexts |
| 400 | // spec and matches what is implemented in blink. Right now we just check |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 401 | // the top level and requesting origins. |
| 402 | if (!PermissionsClient::Get()->CanBypassEmbeddingOriginCheck( |
| 403 | requesting_origin, embedding_origin) && |
Frédéric Wang | 073e74a | 2020-12-16 17:43:32 | [diff] [blame] | 404 | !network::IsUrlPotentiallyTrustworthy(embedding_origin)) { |
Rohan Pavone | 013c400 | 2019-08-21 20:13:52 | [diff] [blame] | 405 | return false; |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 406 | } |
Rohan Pavone | 013c400 | 2019-08-21 20:13:52 | [diff] [blame] | 407 | } |
| 408 | return true; |
| 409 | } |
| 410 | |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 411 | content::PermissionResult |
| 412 | PermissionContextBase::UpdatePermissionStatusWithDeviceStatus( |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 413 | content::WebContents* web_contents, |
Illia Klimov | 2c6138b | 2023-08-14 09:39:25 | [diff] [blame] | 414 | content::PermissionResult result, |
benwells | 5954752 | 2017-03-10 05:30:00 | [diff] [blame] | 415 | const GURL& requesting_origin, |
Andy Paicu | 9d70da4 | 2024-05-10 22:24:39 | [diff] [blame] | 416 | const GURL& embedding_origin) { |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 417 | MaybeUpdateCachedHasDevicePermission(web_contents); |
Andy Paicu | 72b4edf | 2023-09-15 09:52:43 | [diff] [blame] | 418 | |
| 419 | // If the site content setting is ASK/BLOCKED the device-level permission |
| 420 | // won't affect it. |
| 421 | if (result.status != blink::mojom::PermissionStatus::GRANTED) { |
Andy Paicu | 24b02bb | 2023-09-06 14:49:08 | [diff] [blame] | 422 | return result; |
| 423 | } |
| 424 | |
| 425 | // If the device-level permission is granted, it has no effect on the result. |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 426 | if (last_has_device_permission_result_.has_value() && |
| 427 | last_has_device_permission_result_.value()) { |
Andy Paicu | 24b02bb | 2023-09-06 14:49:08 | [diff] [blame] | 428 | return result; |
| 429 | } |
| 430 | |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 431 | #if BUILDFLAG(IS_ANDROID) |
| 432 | if (!web_contents || !web_contents->GetNativeView() || |
| 433 | !web_contents->GetNativeView()->GetWindowAndroid()) { |
| 434 | return result; |
| 435 | } |
| 436 | result.status = |
| 437 | CanRequestSystemPermission(content_settings_type(), web_contents) |
| 438 | ? blink::mojom::PermissionStatus::ASK |
| 439 | : blink::mojom::PermissionStatus::DENIED; |
| 440 | #else |
Andy Paicu | 24b02bb | 2023-09-06 14:49:08 | [diff] [blame] | 441 | // Otherwise the result will be "ASK" if the browser can ask for the |
Andy Paicu | 72b4edf | 2023-09-15 09:52:43 | [diff] [blame] | 442 | // device-level permission, and "BLOCKED" otherwise. |
Andy Paicu | 24b02bb | 2023-09-06 14:49:08 | [diff] [blame] | 443 | result.status = PermissionsClient::Get()->CanRequestDevicePermission( |
| 444 | content_settings_type()) |
Andy Paicu | 72b4edf | 2023-09-15 09:52:43 | [diff] [blame] | 445 | ? blink::mojom::PermissionStatus::ASK |
| 446 | : blink::mojom::PermissionStatus::DENIED; |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 447 | #endif |
benwells | 5954752 | 2017-03-10 05:30:00 | [diff] [blame] | 448 | return result; |
| 449 | } |
| 450 | |
dominickn | 2391315 | 2017-02-23 12:04:02 | [diff] [blame] | 451 | void PermissionContextBase::ResetPermission(const GURL& requesting_origin, |
| 452 | const GURL& embedding_origin) { |
Raymes Khoury | 47df4b2 | 2018-05-10 04:30:17 | [diff] [blame] | 453 | if (!content_settings::ContentSettingsRegistry::GetInstance()->Get( |
| 454 | content_settings_type_)) { |
| 455 | return; |
| 456 | } |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 457 | PermissionsClient::Get() |
| 458 | ->GetSettingsMap(browser_context_) |
lshang | 3812611 | 2016-03-22 03:19:58 | [diff] [blame] | 459 | ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, |
Illia Klimov | 48f643c | 2020-11-05 20:06:14 | [diff] [blame] | 460 | content_settings_type_, |
cm.sanchi | 761e67a | 2017-11-16 08:23:28 | [diff] [blame] | 461 | CONTENT_SETTING_DEFAULT); |
timvolodine | 16be520 | 2015-02-02 17:44:54 | [diff] [blame] | 462 | } |
| 463 | |
Andy Paicu | 9d70da4 | 2024-05-10 22:24:39 | [diff] [blame] | 464 | bool PermissionContextBase::AlwaysIncludeDeviceStatus() const { |
| 465 | return false; |
| 466 | } |
| 467 | |
raymes | 0f93a58 | 2016-12-20 04:08:42 | [diff] [blame] | 468 | bool PermissionContextBase::IsPermissionKillSwitchOn() const { |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 469 | const std::string param = base::GetFieldTrialParamValue( |
raymes | 0f93a58 | 2016-12-20 04:08:42 | [diff] [blame] | 470 | kPermissionsKillSwitchFieldStudy, |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 471 | PermissionUtil::GetPermissionString(content_settings_type_)); |
raymes | 0f93a58 | 2016-12-20 04:08:42 | [diff] [blame] | 472 | |
| 473 | return param == kPermissionsKillSwitchBlockedValue; |
| 474 | } |
| 475 | |
| 476 | ContentSetting PermissionContextBase::GetPermissionStatusInternal( |
raymes | f6104d49 | 2017-03-09 01:20:18 | [diff] [blame] | 477 | content::RenderFrameHost* render_frame_host, |
raymes | 0f93a58 | 2016-12-20 04:08:42 | [diff] [blame] | 478 | const GURL& requesting_origin, |
| 479 | const GURL& embedding_origin) const { |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 480 | return PermissionsClient::Get() |
| 481 | ->GetSettingsMap(browser_context_) |
raymes | 0f93a58 | 2016-12-20 04:08:42 | [diff] [blame] | 482 | ->GetContentSetting(requesting_origin, embedding_origin, |
Illia Klimov | 48f643c | 2020-11-05 20:06:14 | [diff] [blame] | 483 | content_settings_type_); |
raymes | 0f93a58 | 2016-12-20 04:08:42 | [diff] [blame] | 484 | } |
| 485 | |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 486 | void PermissionContextBase::DecidePermission( |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 487 | std::unique_ptr<PermissionRequestData> request_data, |
danakj | 47c8fb5 | 2019-05-02 16:34:36 | [diff] [blame] | 488 | BrowserPermissionCallback callback) { |
thestig | 00844cea | 2015-09-08 21:44:52 | [diff] [blame] | 489 | DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 490 | |
Raymes Khoury | b474c64 | 2018-02-28 06:16:28 | [diff] [blame] | 491 | // Under permission delegation, when we display a permission prompt, the |
| 492 | // origin displayed in the prompt should never differ from the top-level |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 493 | // origin. Storage access API requests are excluded as they are expected to |
Matt Reichhoff | 4c85cb3 | 2023-01-20 16:49:16 | [diff] [blame] | 494 | // request permissions from the frame origin needing access. |
Andy Paicu | 93e63ac8 | 2020-08-18 14:52:17 | [diff] [blame] | 495 | DCHECK(PermissionsClient::Get()->CanBypassEmbeddingOriginCheck( |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 496 | request_data->requesting_origin, request_data->embedding_origin) || |
| 497 | request_data->requesting_origin == request_data->embedding_origin || |
Matt Reichhoff | 4c85cb3 | 2023-01-20 16:49:16 | [diff] [blame] | 498 | content_settings_type_ == ContentSettingsType::STORAGE_ACCESS); |
Raymes Khoury | b474c64 | 2018-02-28 06:16:28 | [diff] [blame] | 499 | |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 500 | content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 501 | request_data->id.global_render_frame_host_id()); |
Illia Klimov | ba5d976 | 2022-05-27 14:10:40 | [diff] [blame] | 502 | DCHECK(rfh); |
| 503 | |
| 504 | content::WebContents* web_contents = |
| 505 | content::WebContents::FromRenderFrameHost(rfh); |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 506 | PermissionRequestManager* permission_request_manager = |
| 507 | PermissionRequestManager::FromWebContents(web_contents); |
Timothy Loh | 8786fb3 | 2017-09-06 03:04:05 | [diff] [blame] | 508 | // TODO(felt): sometimes |permission_request_manager| is null. This check is |
| 509 | // meant to prevent crashes. See crbug.com/457091. |
Kevin McNee | 0340384 | 2023-08-28 14:48:36 | [diff] [blame] | 510 | if (!permission_request_manager) { |
| 511 | std::move(callback).Run(CONTENT_SETTING_ASK); |
Timothy Loh | 8786fb3 | 2017-09-06 03:04:05 | [diff] [blame] | 512 | return; |
Kevin McNee | 0340384 | 2023-08-28 14:48:36 | [diff] [blame] | 513 | } |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 514 | |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 515 | auto decided_cb = base::BindRepeating( |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 516 | &PermissionContextBase::PermissionDecided, weak_factory_.GetWeakPtr()); |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 517 | auto cleanup_cb = |
| 518 | base::BindOnce(&PermissionContextBase::CleanUpRequest, |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 519 | weak_factory_.GetWeakPtr(), web_contents, request_data->id, |
| 520 | request_data->embedded_permission_element_initiated); |
| 521 | PermissionRequestID permission_request_id = request_data->id; |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 522 | |
Florian Jacky | 11f9810 | 2025-05-20 15:57:18 | [diff] [blame] | 523 | std::unique_ptr<PermissionRequest> request = |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 524 | CreatePermissionRequest(web_contents, std::move(request_data), |
| 525 | std::move(decided_cb), std::move(cleanup_cb)); |
lshang | c4089c7 | 2016-10-26 06:54:30 | [diff] [blame] | 526 | |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 527 | bool inserted = |
| 528 | pending_requests_ |
| 529 | .insert(std::make_pair( |
| 530 | permission_request_id.ToString(), |
Florian Jacky | 11f9810 | 2025-05-20 15:57:18 | [diff] [blame] | 531 | std::make_pair(request->GetWeakPtr(), std::move(callback)))) |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 532 | .second; |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 533 | |
Andy Paicu | 0a6d4b50 | 2023-08-29 15:13:09 | [diff] [blame] | 534 | DCHECK(inserted) << "Duplicate id " << permission_request_id.ToString(); |
Carlos Caballero | 8a6c6b7 | 2020-07-20 16:56:22 | [diff] [blame] | 535 | |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 536 | permission_request_manager->AddRequest(rfh, std::move(request)); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 537 | } |
| 538 | |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 539 | void PermissionContextBase::PermissionDecided( |
| 540 | ContentSetting content_setting, |
| 541 | bool is_one_time, |
| 542 | bool is_final_decision, |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 543 | const PermissionRequestData& request_data) { |
Timothy Loh | 8786fb3 | 2017-09-06 03:04:05 | [diff] [blame] | 544 | DCHECK(content_setting == CONTENT_SETTING_ALLOW || |
| 545 | content_setting == CONTENT_SETTING_BLOCK || |
| 546 | content_setting == CONTENT_SETTING_DEFAULT); |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 547 | UserMadePermissionDecision(request_data.id, request_data.requesting_origin, |
| 548 | request_data.embedding_origin, content_setting); |
Timothy Loh | 92a6b8c | 2018-01-12 06:49:54 | [diff] [blame] | 549 | |
| 550 | bool persist = content_setting != CONTENT_SETTING_DEFAULT; |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 551 | |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 552 | auto request = pending_requests_.find(request_data.id.ToString()); |
Florian Jacky | 11f9810 | 2025-05-20 15:57:18 | [diff] [blame] | 553 | CHECK(request->second.first); |
Daniel Cheng | 4d54f0a | 2025-05-26 22:59:12 | [diff] [blame] | 554 | CHECK(request != pending_requests_.end()); |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 555 | // Check if `request` has `BrowserPermissionCallback`. The call back might be |
| 556 | // missing if a permission prompt was preignored and we already notified an |
| 557 | // origin about it. |
| 558 | if (request->second.second) { |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 559 | NotifyPermissionSet(request_data, std::move(request->second.second), |
| 560 | persist, content_setting, is_one_time, |
| 561 | is_final_decision); |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 562 | } else { |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 563 | NotifyPermissionSet(request_data, base::DoNothing(), persist, |
| 564 | content_setting, is_one_time, is_final_decision); |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 565 | } |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 566 | } |
| 567 | |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 568 | content::BrowserContext* PermissionContextBase::browser_context() const { |
| 569 | return browser_context_; |
timvolodine | 1baa3886 | 2014-12-12 16:33:12 | [diff] [blame] | 570 | } |
| 571 | |
James Hollyer | d281a731 | 2021-04-29 21:07:59 | [diff] [blame] | 572 | void PermissionContextBase::OnContentSettingChanged( |
| 573 | const ContentSettingsPattern& primary_pattern, |
| 574 | const ContentSettingsPattern& secondary_pattern, |
Christian Dullweber | 2c4c71d | 2021-10-14 15:07:43 | [diff] [blame] | 575 | ContentSettingsTypeSet content_type_set) { |
Andy Paicu | 72b4edf | 2023-09-15 09:52:43 | [diff] [blame] | 576 | NotifyObservers(primary_pattern, secondary_pattern, content_type_set); |
James Hollyer | d281a731 | 2021-04-29 21:07:59 | [diff] [blame] | 577 | } |
| 578 | |
| 579 | void PermissionContextBase::AddObserver( |
| 580 | permissions::Observer* permission_observer) { |
| 581 | if (permission_observers_.empty() && |
| 582 | !content_setting_observer_registered_by_subclass_) { |
| 583 | PermissionsClient::Get() |
| 584 | ->GetSettingsMap(browser_context_) |
| 585 | ->AddObserver(this); |
| 586 | } |
| 587 | permission_observers_.AddObserver(permission_observer); |
| 588 | } |
| 589 | |
| 590 | void PermissionContextBase::RemoveObserver( |
| 591 | permissions::Observer* permission_observer) { |
| 592 | permission_observers_.RemoveObserver(permission_observer); |
| 593 | if (permission_observers_.empty() && |
| 594 | !content_setting_observer_registered_by_subclass_) { |
| 595 | PermissionsClient::Get() |
| 596 | ->GetSettingsMap(browser_context_) |
| 597 | ->RemoveObserver(this); |
| 598 | } |
| 599 | } |
| 600 | |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 601 | std::unique_ptr<PermissionResolver> |
| 602 | PermissionContextBase::CreatePermissionResolver( |
| 603 | const blink::mojom::PermissionDescriptorPtr& permission_descriptor) const { |
| 604 | return CreateRequestIndependentPermissionResolver(); |
| 605 | } |
| 606 | |
| 607 | std::unique_ptr<PermissionResolver> |
| 608 | PermissionContextBase::CreateRequestIndependentPermissionResolver() const { |
| 609 | return std::make_unique<ContentSettingPermissionResolver>( |
| 610 | content_settings_type_); |
| 611 | } |
| 612 | |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 613 | void PermissionContextBase::MaybeUpdateCachedHasDevicePermission( |
| 614 | content::WebContents* web_contents) { |
| 615 | #if BUILDFLAG(IS_ANDROID) |
| 616 | if (!web_contents || !web_contents->GetNativeView() || |
| 617 | !web_contents->GetNativeView()->GetWindowAndroid()) { |
| 618 | return; |
| 619 | } |
| 620 | const bool has_device_permission = |
| 621 | has_device_permission_for_test_.has_value() |
| 622 | ? has_device_permission_for_test_.value() |
| 623 | : HasSystemPermission(content_settings_type(), web_contents); |
| 624 | #else |
Andy Paicu | 9d70da4 | 2024-05-10 22:24:39 | [diff] [blame] | 625 | const bool has_device_permission = |
Thomas Nguyen | d9d3307 | 2024-06-06 15:15:27 | [diff] [blame] | 626 | has_device_permission_for_test_.has_value() |
| 627 | ? has_device_permission_for_test_.value() |
| 628 | : PermissionsClient::Get()->HasDevicePermission( |
| 629 | content_settings_type()); |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 630 | #endif |
| 631 | |
Andy Paicu | 9d70da4 | 2024-05-10 22:24:39 | [diff] [blame] | 632 | const bool should_notify_observers = |
| 633 | last_has_device_permission_result_.has_value() && |
| 634 | has_device_permission != last_has_device_permission_result_; |
| 635 | |
| 636 | // We need to update |last_has_device_permission_result_| before calling |
| 637 | // |OnContentSettingChanged| to avoid causing a re-entrancy issue since the |
| 638 | // |OnContentSettingChanged| will likely end up calling |GetPermissionStatus|. |
| 639 | last_has_device_permission_result_ = has_device_permission; |
| 640 | |
| 641 | if (should_notify_observers) { |
| 642 | NotifyObservers(ContentSettingsPattern::Wildcard(), |
| 643 | ContentSettingsPattern::Wildcard(), |
| 644 | ContentSettingsTypeSet(content_settings_type())); |
| 645 | } |
| 646 | } |
| 647 | |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 648 | void PermissionContextBase::NotifyPermissionSet( |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 649 | const PermissionRequestData& request_data, |
danakj | 47c8fb5 | 2019-05-02 16:34:36 | [diff] [blame] | 650 | BrowserPermissionCallback callback, |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 651 | bool persist, |
Ravjit Singh Uppal | c73b5a6 | 2020-11-13 01:38:52 | [diff] [blame] | 652 | ContentSetting content_setting, |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 653 | bool is_one_time, |
| 654 | bool is_final_decision) { |
thestig | 00844cea | 2015-09-08 21:44:52 | [diff] [blame] | 655 | DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 656 | |
Ravjit Singh Uppal | c73b5a6 | 2020-11-13 01:38:52 | [diff] [blame] | 657 | if (persist) { |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 658 | UpdateContentSetting(request_data, content_setting, is_one_time); |
Ravjit Singh Uppal | c73b5a6 | 2020-11-13 01:38:52 | [diff] [blame] | 659 | } |
mlamouri | df357a31 | 2015-03-03 17:34:05 | [diff] [blame] | 660 | |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 661 | if (is_final_decision) { |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 662 | UpdateTabContext(request_data.id, request_data.requesting_origin, |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 663 | content_setting == CONTENT_SETTING_ALLOW); |
Thomas Nguyen | 88df73a | 2023-02-28 20:50:46 | [diff] [blame] | 664 | if (content_setting == CONTENT_SETTING_ALLOW) { |
| 665 | if (auto* rfh = content::RenderFrameHost::FromID( |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 666 | request_data.id.global_render_frame_host_id())) { |
Thomas Nguyen | 88df73a | 2023-02-28 20:50:46 | [diff] [blame] | 667 | PermissionUmaUtil::RecordPermissionsUsageSourceAndPolicyConfiguration( |
| 668 | content_settings_type_, rfh); |
| 669 | } |
| 670 | } |
Illia Klimov | e406ecc1 | 2022-11-22 15:53:29 | [diff] [blame] | 671 | } |
mlamouri | df357a31 | 2015-03-03 17:34:05 | [diff] [blame] | 672 | |
raymes | 423d965f | 2016-09-29 00:46:25 | [diff] [blame] | 673 | if (content_setting == CONTENT_SETTING_DEFAULT) |
| 674 | content_setting = CONTENT_SETTING_ASK; |
mlamouri | df357a31 | 2015-03-03 17:34:05 | [diff] [blame] | 675 | |
danakj | 47c8fb5 | 2019-05-02 16:34:36 | [diff] [blame] | 676 | std::move(callback).Run(content_setting); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 677 | } |
| 678 | |
Thomas Nguyen | d9d3307 | 2024-06-06 15:15:27 | [diff] [blame] | 679 | void PermissionContextBase::CleanUpRequest( |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 680 | content::WebContents* web_contents, |
Thomas Nguyen | d9d3307 | 2024-06-06 15:15:27 | [diff] [blame] | 681 | const PermissionRequestID& id, |
| 682 | bool embedded_permission_element_initiated) { |
tsergeant | 58defcfb | 2016-07-19 23:47:28 | [diff] [blame] | 683 | size_t success = pending_requests_.erase(id.ToString()); |
Thomas Nguyen | d9d3307 | 2024-06-06 15:15:27 | [diff] [blame] | 684 | // A request from an embedded permission element requires a notification |
| 685 | // `OnPermissionChanged` when changing the device status, which is currently |
| 686 | // unavailable. We compare the device status with the cached status and notify |
| 687 | // `OnPermissionChanged` here. We should remove this line once the device |
| 688 | // status change observer is implemented. |
| 689 | if (embedded_permission_element_initiated) { |
Thomas Nguyen | 781e135 | 2025-01-27 18:07:19 | [diff] [blame] | 690 | MaybeUpdateCachedHasDevicePermission(web_contents); |
Thomas Nguyen | d9d3307 | 2024-06-06 15:15:27 | [diff] [blame] | 691 | } |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 692 | DCHECK(success == 1) << "Missing request " << id.ToString(); |
| 693 | } |
| 694 | |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 695 | void PermissionContextBase::UpdateContentSetting( |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 696 | const PermissionRequestData& request_data, |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 697 | ContentSetting content_setting, |
| 698 | bool is_one_time) { |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 699 | DCHECK_EQ(request_data.requesting_origin, |
| 700 | request_data.requesting_origin.DeprecatedGetOriginAsURL()); |
| 701 | DCHECK_EQ(request_data.embedding_origin, |
| 702 | request_data.embedding_origin.DeprecatedGetOriginAsURL()); |
mlamouri | df357a31 | 2015-03-03 17:34:05 | [diff] [blame] | 703 | DCHECK(content_setting == CONTENT_SETTING_ALLOW || |
| 704 | content_setting == CONTENT_SETTING_BLOCK); |
| 705 | |
Chris Fredrickson | 4486fdd | 2023-06-12 18:18:27 | [diff] [blame] | 706 | content_settings::ContentSettingConstraints constraints; |
Jonathan Njeunje | dc5bc010 | 2024-02-23 16:54:06 | [diff] [blame] | 707 | constraints.set_session_model( |
| 708 | is_one_time ? content_settings::mojom::SessionModel::ONE_TIME |
| 709 | : content_settings::mojom::SessionModel::DURABLE); |
Martin Šrámek | 83594ca | 2022-08-03 19:25:58 | [diff] [blame] | 710 | |
Zaina Al-Mashni | 1901101 | 2025-01-09 12:28:22 | [diff] [blame] | 711 | // The Permissions module in Safety check will revoke permissions after |
| 712 | // a finite amount of time if the permission can be revoked. |
| 713 | if (content_settings::CanBeAutoRevoked(content_settings_type_, |
| 714 | content_setting, is_one_time)) { |
| 715 | // For #2, by definition, that should be all of them. If that changes in |
| 716 | // the future, consider whether revocation for such permission makes |
| 717 | // sense, and/or change this to an early return so that we don't |
| 718 | // unnecessarily record timestamps where we don't need them. |
| 719 | constraints.set_track_last_visit_for_autoexpiration(true); |
Martin Šrámek | 83594ca | 2022-08-03 19:25:58 | [diff] [blame] | 720 | } |
Martin Šrámek | 83594ca | 2022-08-03 19:25:58 | [diff] [blame] | 721 | |
Florian Jacky | 8425f92 | 2024-05-08 20:57:47 | [diff] [blame] | 722 | if (is_one_time) { |
Florian Jacky | 41742ec6 | 2024-12-05 09:48:29 | [diff] [blame] | 723 | if (content_settings::ShouldTypeExpireActively(content_settings_type_)) { |
Florian Jacky | 989b41b | 2023-07-31 16:33:42 | [diff] [blame] | 724 | constraints.set_lifetime(kOneTimePermissionMaximumLifetime); |
| 725 | } |
| 726 | } |
| 727 | |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 728 | PermissionsClient::Get() |
| 729 | ->GetSettingsMap(browser_context_) |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 730 | ->SetContentSettingDefaultScope( |
Chris Fredrickson | 173060c86 | 2025-05-14 14:23:01 | [diff] [blame] | 731 | request_data.requesting_origin, request_data.embedding_origin, |
Florian Jacky | 7f3e3ca1b | 2025-05-05 16:19:20 | [diff] [blame] | 732 | content_settings_type_, content_setting, constraints); |
[email protected] | bb32605 | 2014-07-09 10:55:49 | [diff] [blame] | 733 | } |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 734 | |
Charlie Hu | bb5943d | 2021-03-09 19:46:12 | [diff] [blame] | 735 | bool PermissionContextBase::PermissionAllowedByPermissionsPolicy( |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 736 | content::RenderFrameHost* rfh) const { |
Charlie Hu | 5130d25e | 2021-03-05 21:53:39 | [diff] [blame] | 737 | // Some features don't have an associated permissions policy yet. Allow those. |
Charlie Hu | e20fe2f | 2021-03-07 03:39:59 | [diff] [blame] | 738 | if (permissions_policy_feature_ == |
Sandor «Alex» Major | e9545a7 | 2025-01-31 20:40:46 | [diff] [blame] | 739 | network::mojom::PermissionsPolicyFeature::kNotFound) { |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 740 | return true; |
Sandor «Alex» Major | e9545a7 | 2025-01-31 20:40:46 | [diff] [blame] | 741 | } |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 742 | |
Charlie Hu | e20fe2f | 2021-03-07 03:39:59 | [diff] [blame] | 743 | return rfh->IsFeatureEnabled(permissions_policy_feature_); |
raymes | 21b9affc | 2017-05-31 06:15:26 | [diff] [blame] | 744 | } |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 745 | |
Andy Paicu | 72b4edf | 2023-09-15 09:52:43 | [diff] [blame] | 746 | void PermissionContextBase::NotifyObservers( |
| 747 | const ContentSettingsPattern& primary_pattern, |
| 748 | const ContentSettingsPattern& secondary_pattern, |
| 749 | ContentSettingsTypeSet content_type_set) const { |
| 750 | if (!content_type_set.Contains(content_settings_type_)) { |
| 751 | return; |
| 752 | } |
| 753 | |
| 754 | for (permissions::Observer& obs : permission_observers_) { |
| 755 | obs.OnPermissionChanged(primary_pattern, secondary_pattern, |
| 756 | content_type_set); |
| 757 | } |
| 758 | } |
| 759 | |
Clark DuVall | a11361ad3 | 2020-02-20 22:14:27 | [diff] [blame] | 760 | } // namespace permissions |