Upload upstream chromium 114.0.5735.31
[platform/framework/web/chromium-efl.git] / components / permissions / permission_context_base.cc
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/permissions/permission_context_base.h"
6
7 #include <stddef.h>
8
9 #include <string>
10 #include <utility>
11
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/logging.h"
15 #include "base/metrics/field_trial_params.h"
16 #include "base/observer_list.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/time/time.h"
19 #include "build/build_config.h"
20 #include "components/content_settings/core/browser/content_settings_registry.h"
21 #include "components/content_settings/core/browser/content_settings_utils.h"
22 #include "components/content_settings/core/browser/host_content_settings_map.h"
23 #include "components/content_settings/core/common/content_settings_types.h"
24 #include "components/permissions/features.h"
25 #include "components/permissions/permission_decision_auto_blocker.h"
26 #include "components/permissions/permission_request.h"
27 #include "components/permissions/permission_request_id.h"
28 #include "components/permissions/permission_request_manager.h"
29 #include "components/permissions/permission_uma_util.h"
30 #include "components/permissions/permission_util.h"
31 #include "components/permissions/permissions_client.h"
32 #include "components/permissions/request_type.h"
33 #include "components/permissions/unused_site_permissions_service.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/global_routing_id.h"
36 #include "content/public/browser/navigation_entry.h"
37 #include "content/public/browser/render_frame_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/common/content_features.h"
40 #include "services/network/public/cpp/is_potentially_trustworthy.h"
41 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
42 #include "url/gurl.h"
43
44 namespace permissions {
45 namespace {
46
47 const char kPermissionBlockedKillSwitchMessage[] =
48     "%s permission has been blocked.";
49
50 #if BUILDFLAG(IS_ANDROID)
51 const char kPermissionBlockedRepeatedDismissalsMessage[] =
52     "%s permission has been blocked as the user has dismissed the permission "
53     "prompt several times. This can be reset in Site Settings. See "
54     "https://www.chromestatus.com/feature/6443143280984064 for more "
55     "information.";
56
57 const char kPermissionBlockedRepeatedIgnoresMessage[] =
58     "%s permission has been blocked as the user has ignored the permission "
59     "prompt several times. This can be reset in Site Settings. See "
60     "https://www.chromestatus.com/feature/6443143280984064 for more "
61     "information.";
62 #else
63 const char kPermissionBlockedRepeatedDismissalsMessage[] =
64     "%s permission has been blocked as the user has dismissed the permission "
65     "prompt several times. This can be reset in Page Info which can be "
66     "accessed by clicking the lock icon next to the URL. See "
67     "https://www.chromestatus.com/feature/6443143280984064 for more "
68     "information.";
69
70 const char kPermissionBlockedRepeatedIgnoresMessage[] =
71     "%s permission has been blocked as the user has ignored the permission "
72     "prompt several times. This can be reset in Page Info which can be "
73     "accessed by clicking the lock icon next to the URL. See "
74     "https://www.chromestatus.com/feature/6443143280984064 for more "
75     "information.";
76 #endif
77
78 const char kPermissionBlockedRecentDisplayMessage[] =
79     "%s permission has been blocked as the prompt has already been displayed "
80     "to the user recently.";
81
82 const char kPermissionBlockedPermissionsPolicyMessage[] =
83     "%s permission has been blocked because of a permissions policy applied to"
84     " the current document. See https://goo.gl/EuHzyv for more details.";
85
86 void LogPermissionBlockedMessage(content::RenderFrameHost* rfh,
87                                  const char* message,
88                                  ContentSettingsType type) {
89   rfh->GetOutermostMainFrame()->AddMessageToConsole(
90       blink::mojom::ConsoleMessageLevel::kWarning,
91       base::StringPrintf(message,
92                          PermissionUtil::GetPermissionString(type).c_str()));
93 }
94
95 }  // namespace
96
97 // static
98 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] =
99     "PermissionsKillSwitch";
100 // static
101 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] =
102     "blocked";
103
104 PermissionContextBase::PermissionContextBase(
105     content::BrowserContext* browser_context,
106     ContentSettingsType content_settings_type,
107     blink::mojom::PermissionsPolicyFeature permissions_policy_feature)
108     : browser_context_(browser_context),
109       content_settings_type_(content_settings_type),
110       permissions_policy_feature_(permissions_policy_feature) {
111   PermissionDecisionAutoBlocker::UpdateFromVariations();
112 }
113
114 PermissionContextBase::~PermissionContextBase() {
115   DCHECK(permission_observers_.empty());
116   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
117 }
118
119 void PermissionContextBase::RequestPermission(
120     const PermissionRequestID& id,
121     const GURL& requesting_frame,
122     bool user_gesture,
123     BrowserPermissionCallback callback) {
124   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
125
126   content::RenderFrameHost* const rfh =
127       content::RenderFrameHost::FromID(id.global_render_frame_host_id());
128
129   if (!rfh) {
130     // Permission request is not allowed without a valid RenderFrameHost.
131     std::move(callback).Run(CONTENT_SETTING_ASK);
132     return;
133   }
134
135   const GURL requesting_origin = requesting_frame.DeprecatedGetOriginAsURL();
136   const GURL embedding_origin =
137       PermissionUtil::GetLastCommittedOriginAsURL(rfh->GetMainFrame());
138
139   if (!requesting_origin.is_valid() || !embedding_origin.is_valid()) {
140     std::string type_name =
141         PermissionUtil::GetPermissionString(content_settings_type_);
142
143     DVLOG(1) << "Attempt to use " << type_name
144              << " from an invalid URL: " << requesting_origin << ","
145              << embedding_origin << " (" << type_name
146              << " is not supported in popups)";
147     NotifyPermissionSet(id, requesting_origin, embedding_origin,
148                         std::move(callback), /*persist=*/false,
149                         CONTENT_SETTING_BLOCK, /*is_one_time=*/false,
150                         /*is_final_decision=*/true);
151     return;
152   }
153
154   // Check the content setting to see if the user has already made a decision,
155   // or if the origin is under embargo. If so, respect that decision.
156   DCHECK(rfh);
157   PermissionResult result =
158       GetPermissionStatus(rfh, requesting_origin, embedding_origin);
159
160   if (result.content_setting == CONTENT_SETTING_ALLOW ||
161       result.content_setting == CONTENT_SETTING_BLOCK) {
162     switch (result.source) {
163       case PermissionStatusSource::KILL_SWITCH:
164         // Block the request and log to the developer console.
165         LogPermissionBlockedMessage(rfh, kPermissionBlockedKillSwitchMessage,
166                                     content_settings_type_);
167         PermissionUmaUtil::RecordPermissionRequestedFromFrame(
168             content_settings_type_, rfh);
169         std::move(callback).Run(CONTENT_SETTING_BLOCK);
170         return;
171       case PermissionStatusSource::MULTIPLE_DISMISSALS:
172         LogPermissionBlockedMessage(rfh,
173                                     kPermissionBlockedRepeatedDismissalsMessage,
174                                     content_settings_type_);
175         PermissionUmaUtil::RecordPermissionRequestedFromFrame(
176             content_settings_type_, rfh);
177         break;
178       case PermissionStatusSource::MULTIPLE_IGNORES:
179         LogPermissionBlockedMessage(rfh,
180                                     kPermissionBlockedRepeatedIgnoresMessage,
181                                     content_settings_type_);
182         PermissionUmaUtil::RecordPermissionRequestedFromFrame(
183             content_settings_type_, rfh);
184         break;
185       case PermissionStatusSource::FEATURE_POLICY:
186         LogPermissionBlockedMessage(rfh,
187                                     kPermissionBlockedPermissionsPolicyMessage,
188                                     content_settings_type_);
189         break;
190       case PermissionStatusSource::RECENT_DISPLAY:
191         LogPermissionBlockedMessage(rfh, kPermissionBlockedRecentDisplayMessage,
192                                     content_settings_type_);
193         break;
194       case PermissionStatusSource::UNSPECIFIED:
195         PermissionUmaUtil::RecordPermissionRequestedFromFrame(
196             content_settings_type_, rfh);
197         break;
198       case PermissionStatusSource::PORTAL:
199       case PermissionStatusSource::FENCED_FRAME:
200       case PermissionStatusSource::INSECURE_ORIGIN:
201       case PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN:
202         break;
203     }
204
205     // If we are under embargo, record the embargo reason for which we have
206     // suppressed the prompt.
207     PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(result.source);
208     NotifyPermissionSet(id, requesting_origin, embedding_origin,
209                         std::move(callback), /*persist=*/false,
210                         result.content_setting, /*is_one_time=*/false,
211                         /*is_final_decision=*/true);
212     return;
213   }
214
215   PermissionUmaUtil::RecordPermissionRequestedFromFrame(content_settings_type_,
216                                                         rfh);
217
218   // We are going to show a prompt now.
219   PermissionUmaUtil::PermissionRequested(content_settings_type_);
220   PermissionUmaUtil::RecordEmbargoPromptSuppression(
221       PermissionEmbargoStatus::NOT_EMBARGOED);
222
223   DecidePermission(id, requesting_origin, embedding_origin, user_gesture,
224                    std::move(callback));
225 }
226
227 bool PermissionContextBase::IsRestrictedToSecureOrigins() const {
228   return true;
229 }
230
231 void PermissionContextBase::UserMadePermissionDecision(
232     const PermissionRequestID& id,
233     const GURL& requesting_origin,
234     const GURL& embedding_origin,
235     ContentSetting content_setting) {}
236
237 std::unique_ptr<PermissionRequest>
238 PermissionContextBase::CreatePermissionRequest(
239     const GURL& request_origin,
240     ContentSettingsType content_settings_type,
241     bool has_gesture,
242     content::WebContents* web_contents,
243     PermissionRequest::PermissionDecidedCallback permission_decided_callback,
244     base::OnceClosure delete_callback) const {
245   return std::make_unique<PermissionRequest>(
246       request_origin, ContentSettingsTypeToRequestType(content_settings_type),
247       has_gesture, std::move(permission_decided_callback),
248       std::move(delete_callback));
249 }
250
251 PermissionResult PermissionContextBase::GetPermissionStatus(
252     content::RenderFrameHost* render_frame_host,
253     const GURL& requesting_origin,
254     const GURL& embedding_origin) const {
255   // If the permission has been disabled through Finch, block all requests.
256   if (IsPermissionKillSwitchOn()) {
257     return PermissionResult(CONTENT_SETTING_BLOCK,
258                             PermissionStatusSource::KILL_SWITCH);
259   }
260
261   if (!IsPermissionAvailableToOrigins(requesting_origin, embedding_origin)) {
262     return PermissionResult(CONTENT_SETTING_BLOCK,
263                             PermissionStatusSource::INSECURE_ORIGIN);
264   }
265
266   // Check whether the feature is enabled for the frame by permissions policy.
267   // We can only do this when a RenderFrameHost has been provided.
268   if (render_frame_host &&
269       !PermissionAllowedByPermissionsPolicy(render_frame_host)) {
270     return PermissionResult(CONTENT_SETTING_BLOCK,
271                             PermissionStatusSource::FEATURE_POLICY);
272   }
273
274   if (render_frame_host) {
275     content::WebContents* web_contents =
276         content::WebContents::FromRenderFrameHost(render_frame_host);
277
278     // Automatically deny all HTTP or HTTPS requests where the virtual URL and
279     // the loaded URL are for different origins. The loaded URL is the one
280     // actually in the renderer, but the virtual URL is the one
281     // seen by the user. This may be very confusing for a user to see in a
282     // permissions request.
283     content::NavigationEntry* entry =
284         web_contents->GetController().GetLastCommittedEntry();
285     if (entry) {
286       const GURL virtual_url = entry->GetVirtualURL();
287       const GURL loaded_url = entry->GetURL();
288       if (virtual_url.SchemeIsHTTPOrHTTPS() &&
289           loaded_url.SchemeIsHTTPOrHTTPS() &&
290           !url::IsSameOriginWith(virtual_url, loaded_url)) {
291         return PermissionResult(
292             CONTENT_SETTING_BLOCK,
293             PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN);
294       }
295     }
296   }
297
298   ContentSetting content_setting = GetPermissionStatusInternal(
299       render_frame_host, requesting_origin, embedding_origin);
300
301   if (content_setting != CONTENT_SETTING_ASK) {
302     return PermissionResult(content_setting,
303                             PermissionStatusSource::UNSPECIFIED);
304   }
305
306   absl::optional<PermissionResult> result =
307       PermissionsClient::Get()
308           ->GetPermissionDecisionAutoBlocker(browser_context_)
309           ->GetEmbargoResult(requesting_origin, content_settings_type_);
310   if (result) {
311     DCHECK(result->content_setting == CONTENT_SETTING_BLOCK);
312     return *result;
313   }
314   return PermissionResult(CONTENT_SETTING_ASK,
315                           PermissionStatusSource::UNSPECIFIED);
316 }
317
318 bool PermissionContextBase::IsPermissionAvailableToOrigins(
319     const GURL& requesting_origin,
320     const GURL& embedding_origin) const {
321   if (IsRestrictedToSecureOrigins()) {
322     if (!network::IsUrlPotentiallyTrustworthy(requesting_origin))
323       return false;
324
325     // TODO(raymes): We should check the entire chain of embedders here whenever
326     // possible as this corresponds to the requirements of the secure contexts
327     // spec and matches what is implemented in blink. Right now we just check
328     // the top level and requesting origins.
329     if (!PermissionsClient::Get()->CanBypassEmbeddingOriginCheck(
330             requesting_origin, embedding_origin) &&
331         !network::IsUrlPotentiallyTrustworthy(embedding_origin)) {
332       return false;
333     }
334   }
335   return true;
336 }
337
338 PermissionResult PermissionContextBase::UpdatePermissionStatusWithDeviceStatus(
339     PermissionResult result,
340     const GURL& requesting_origin,
341     const GURL& embedding_origin) const {
342   return result;
343 }
344
345 void PermissionContextBase::ResetPermission(const GURL& requesting_origin,
346                                             const GURL& embedding_origin) {
347   if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(
348           content_settings_type_)) {
349     return;
350   }
351   PermissionsClient::Get()
352       ->GetSettingsMap(browser_context_)
353       ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
354                                       content_settings_type_,
355                                       CONTENT_SETTING_DEFAULT);
356 }
357
358 bool PermissionContextBase::IsPermissionKillSwitchOn() const {
359   const std::string param = base::GetFieldTrialParamValue(
360       kPermissionsKillSwitchFieldStudy,
361       PermissionUtil::GetPermissionString(content_settings_type_));
362
363   return param == kPermissionsKillSwitchBlockedValue;
364 }
365
366 ContentSetting PermissionContextBase::GetPermissionStatusInternal(
367     content::RenderFrameHost* render_frame_host,
368     const GURL& requesting_origin,
369     const GURL& embedding_origin) const {
370   return PermissionsClient::Get()
371       ->GetSettingsMap(browser_context_)
372       ->GetContentSetting(requesting_origin, embedding_origin,
373                           content_settings_type_);
374 }
375
376 void PermissionContextBase::DecidePermission(
377     const PermissionRequestID& id,
378     const GURL& requesting_origin,
379     const GURL& embedding_origin,
380     bool user_gesture,
381     BrowserPermissionCallback callback) {
382   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
383
384   // Under permission delegation, when we display a permission prompt, the
385   // origin displayed in the prompt should never differ from the top-level
386   // origin. Storage access API requests are excluded as they are expected to
387   // request permissions from the frame origin needing access.
388   DCHECK(PermissionsClient::Get()->CanBypassEmbeddingOriginCheck(
389              requesting_origin, embedding_origin) ||
390          requesting_origin == embedding_origin ||
391          content_settings_type_ == ContentSettingsType::STORAGE_ACCESS);
392
393   content::RenderFrameHost* rfh =
394       content::RenderFrameHost::FromID(id.global_render_frame_host_id());
395   DCHECK(rfh);
396
397   content::WebContents* web_contents =
398       content::WebContents::FromRenderFrameHost(rfh);
399   PermissionRequestManager* permission_request_manager =
400       PermissionRequestManager::FromWebContents(web_contents);
401   // TODO(felt): sometimes |permission_request_manager| is null. This check is
402   // meant to prevent crashes. See crbug.com/457091.
403   if (!permission_request_manager)
404     return;
405
406   std::unique_ptr<PermissionRequest> request_ptr = CreatePermissionRequest(
407       requesting_origin, content_settings_type_, user_gesture, web_contents,
408       base::BindRepeating(&PermissionContextBase::PermissionDecided,
409                           weak_factory_.GetWeakPtr(), id, requesting_origin,
410                           embedding_origin),
411       base::BindOnce(&PermissionContextBase::CleanUpRequest,
412                      weak_factory_.GetWeakPtr(), id));
413   PermissionRequest* request = request_ptr.get();
414
415   bool inserted = pending_requests_
416                       .insert(std::make_pair(
417                           id.ToString(), std::make_pair(std::move(request_ptr),
418                                                         std::move(callback))))
419                       .second;
420   DCHECK(inserted) << "Duplicate id " << id.ToString();
421
422   permission_request_manager->AddRequest(rfh, request);
423 }
424
425 void PermissionContextBase::PermissionDecided(const PermissionRequestID& id,
426                                               const GURL& requesting_origin,
427                                               const GURL& embedding_origin,
428                                               ContentSetting content_setting,
429                                               bool is_one_time,
430                                               bool is_final_decision) {
431   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
432          content_setting == CONTENT_SETTING_BLOCK ||
433          content_setting == CONTENT_SETTING_DEFAULT);
434   UserMadePermissionDecision(id, requesting_origin, embedding_origin,
435                              content_setting);
436
437   bool persist = content_setting != CONTENT_SETTING_DEFAULT;
438
439   auto request = pending_requests_.find(id.ToString());
440   DCHECK(request != pending_requests_.end());
441   // Check if `request` has `BrowserPermissionCallback`. The call back might be
442   // missing if a permission prompt was preignored and we already notified an
443   // origin about it.
444   if (request->second.second) {
445     NotifyPermissionSet(id, requesting_origin, embedding_origin,
446                         std::move(request->second.second), persist,
447                         content_setting, is_one_time, is_final_decision);
448   } else {
449     NotifyPermissionSet(id, requesting_origin, embedding_origin,
450                         base::DoNothing(), persist, content_setting,
451                         is_one_time, is_final_decision);
452   }
453 }
454
455 content::BrowserContext* PermissionContextBase::browser_context() const {
456   return browser_context_;
457 }
458
459 void PermissionContextBase::OnContentSettingChanged(
460     const ContentSettingsPattern& primary_pattern,
461     const ContentSettingsPattern& secondary_pattern,
462     ContentSettingsTypeSet content_type_set) {
463   if (!content_type_set.Contains(content_settings_type_))
464     return;
465
466   for (permissions::Observer& obs : permission_observers_) {
467     obs.OnPermissionChanged(primary_pattern, secondary_pattern,
468                             content_type_set);
469   }
470 }
471
472 void PermissionContextBase::AddObserver(
473     permissions::Observer* permission_observer) {
474   if (permission_observers_.empty() &&
475       !content_setting_observer_registered_by_subclass_) {
476     PermissionsClient::Get()
477         ->GetSettingsMap(browser_context_)
478         ->AddObserver(this);
479   }
480   permission_observers_.AddObserver(permission_observer);
481 }
482
483 void PermissionContextBase::RemoveObserver(
484     permissions::Observer* permission_observer) {
485   permission_observers_.RemoveObserver(permission_observer);
486   if (permission_observers_.empty() &&
487       !content_setting_observer_registered_by_subclass_) {
488     PermissionsClient::Get()
489         ->GetSettingsMap(browser_context_)
490         ->RemoveObserver(this);
491   }
492 }
493
494 void PermissionContextBase::NotifyPermissionSet(
495     const PermissionRequestID& id,
496     const GURL& requesting_origin,
497     const GURL& embedding_origin,
498     BrowserPermissionCallback callback,
499     bool persist,
500     ContentSetting content_setting,
501     bool is_one_time,
502     bool is_final_decision) {
503   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
504
505   if (persist) {
506     UpdateContentSetting(requesting_origin, embedding_origin, content_setting,
507                          is_one_time);
508   }
509
510   if (is_final_decision) {
511     UpdateTabContext(id, requesting_origin,
512                      content_setting == CONTENT_SETTING_ALLOW);
513     if (content_setting == CONTENT_SETTING_ALLOW) {
514       if (auto* rfh = content::RenderFrameHost::FromID(
515               id.global_render_frame_host_id())) {
516         PermissionUmaUtil::RecordPermissionsUsageSourceAndPolicyConfiguration(
517             content_settings_type_, rfh);
518       }
519     }
520   }
521
522   if (content_setting == CONTENT_SETTING_DEFAULT)
523     content_setting = CONTENT_SETTING_ASK;
524
525   std::move(callback).Run(content_setting);
526 }
527
528 void PermissionContextBase::CleanUpRequest(const PermissionRequestID& id) {
529   size_t success = pending_requests_.erase(id.ToString());
530   DCHECK(success == 1) << "Missing request " << id.ToString();
531 }
532
533 void PermissionContextBase::UpdateContentSetting(const GURL& requesting_origin,
534                                                  const GURL& embedding_origin,
535                                                  ContentSetting content_setting,
536                                                  bool is_one_time) {
537   DCHECK_EQ(requesting_origin, requesting_origin.DeprecatedGetOriginAsURL());
538   DCHECK_EQ(embedding_origin, embedding_origin.DeprecatedGetOriginAsURL());
539   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
540          content_setting == CONTENT_SETTING_BLOCK);
541
542   content_settings::ContentSettingConstraints constraints = {
543       base::Time(), is_one_time ? content_settings::SessionModel::OneTime
544                                 : content_settings::SessionModel::Durable};
545
546 #if !BUILDFLAG(IS_ANDROID)
547   if (base::FeatureList::IsEnabled(
548           features::kRecordPermissionExpirationTimestamps)) {
549     // The Permissions module in Safety check will revoke permissions after
550     // a finite amount of time if the permission can be revoked.
551     if (content_settings::CanBeAutoRevoked(content_settings_type_,
552                                            content_setting, is_one_time)) {
553       // For #2, by definition, that should be all of them. If that changes in
554       // the future, consider whether revocation for such permission makes
555       // sense, and/or change this to an early return so that we don't
556       // unnecessarily record timestamps where we don't need them.
557       constraints.track_last_visit_for_autoexpiration = true;
558     }
559   }
560 #endif  // !BUILDFLAG(IS_ANDROID)
561
562   PermissionsClient::Get()
563       ->GetSettingsMap(browser_context_)
564       ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
565                                       content_settings_type_, content_setting,
566                                       constraints);
567 }
568
569 bool PermissionContextBase::PermissionAllowedByPermissionsPolicy(
570     content::RenderFrameHost* rfh) const {
571   // Some features don't have an associated permissions policy yet. Allow those.
572   if (permissions_policy_feature_ ==
573       blink::mojom::PermissionsPolicyFeature::kNotFound)
574     return true;
575
576   return rfh->IsFeatureEnabled(permissions_policy_feature_);
577 }
578
579 }  // namespace permissions