File: permission_context_base.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (299 lines) | stat: -rw-r--r-- 13,264 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_PERMISSIONS_PERMISSION_CONTEXT_BASE_H_
#define COMPONENTS_PERMISSIONS_PERMISSION_CONTEXT_BASE_H_

#include <memory>
#include <unordered_map>

#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/permissions/permission_decision.h"
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_request_data.h"
#include "components/permissions/resolvers/permission_resolver.h"
#include "content/public/browser/permission_result.h"
#include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom-forward.h"

class GURL;

namespace permissions {
class PermissionRequestID;
}

namespace content {
class BrowserContext;
class RenderFrameHost;
class WebContents;
}  // namespace content

namespace permissions {

class Observer : public base::CheckedObserver {
 public:
  // Called whenever there is a potential permission status change for the
  // specified patterns. This function being called does not necessarily mean
  // that the result of |GetPermissionStatus| has changed for any particular
  // origin.
  virtual void OnPermissionChanged(
      const ContentSettingsPattern& primary_pattern,
      const ContentSettingsPattern& secondary_pattern,
      ContentSettingsTypeSet content_type_set) = 0;
};

// Default one time permission expiration time.
static constexpr base::TimeDelta kOneTimePermissionTimeout = base::Minutes(5);

// A one time grant will never last longer than this value.
static constexpr base::TimeDelta kOneTimePermissionMaximumLifetime =
    base::Hours(16);

using BrowserPermissionCallback =
    base::OnceCallback<void(blink::mojom::PermissionStatus)>;

// This base class contains common operations for granting permissions.
// It offers the following functionality:
//   - Creates a permission request when needed.
//   - If accepted/denied the permission is saved in content settings for
//     future uses (for the domain that requested it).
//   - If dismissed the permission is not saved but it's considered denied for
//     this one request
//   - In any case the BrowserPermissionCallback is executed once a decision
//     about the permission is made by the user.
// The bare minimum you need to create a new permission request is
//   - Define your new permission in the ContentSettingsType enum.
//   - Create a class that inherits from PermissionContextBase and passes the
//     new permission.
//   - Edit the PermissionRequest methods to add the new text.
//   - Make sure to update
//     third_party/blink/public/devtools_protocol/browser_protocol.pdl
//     even if you don't intend to do anything DevTools-specific; you will
//     run into problems with generated code otherwise.
//   - Hit several asserts for the missing plumbing and fix them :)
// After this you can override several other methods to customize behavior,
// in particular it is advised to override UpdateTabContext in order to manage
// the permission from the omnibox.
// See midi_permission_context.h/cc or push_permission_context.cc/h for some
// examples.

class PermissionContextBase : public content_settings::Observer {
 public:
  PermissionContextBase(
      content::BrowserContext* browser_context,
      ContentSettingsType content_settings_type,
      network::mojom::PermissionsPolicyFeature permissions_policy_feature);
  ~PermissionContextBase() override;

  // A field trial used to enable the global permissions kill switch.
  // This is public so permissions that don't yet inherit from
  // PermissionContextBase can use it.
  static const char kPermissionsKillSwitchFieldStudy[];

  // The field trial param to enable the global permissions kill switch.
  // This is public so permissions that don't yet inherit from
  // PermissionContextBase can use it.
  static const char kPermissionsKillSwitchBlockedValue[];

  // |callback| is called upon resolution of the request, but not if a prompt
  // is shown and ignored.
  virtual void RequestPermission(
      std::unique_ptr<PermissionRequestData> request_data,
      BrowserPermissionCallback callback);

  // Returns whether the permission has been granted, denied etc. given a
  // PermissionResolver. |render_frame_host| may be nullptr if the call is
  // coming from a context other than a specific frame.
  content::PermissionResult GetPermissionStatus(
      const PermissionResolver& resolver,
      content::RenderFrameHost* render_frame_host,
      const GURL& requesting_origin,
      const GURL& embedding_origin) const;

  // Returns whether the permission has been granted, denied etc. given a
  // PermissionDescriptorPtr. |render_frame_host| may be nullptr if the call is
  // coming from a context other than a specific frame.
  content::PermissionResult GetPermissionStatus(
      const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
      content::RenderFrameHost* render_frame_host,
      const GURL& requesting_origin,
      const GURL& embedding_origin) const;

  // Returns whether the permission is usable by requesting/embedding origins.
  bool IsPermissionAvailableToOrigins(const GURL& requesting_origin,
                                      const GURL& embedding_origin) const;

  // Update |result| with any modifications based on the device state. For
  // example, if |result| is ALLOW but Chrome does not have the relevant
  // permission at the device level, but will prompt the user, return ASK.
  // This function updates the cached device permission status which can result
  // in the permission status changing and observers being notified.
  virtual content::PermissionResult UpdatePermissionStatusWithDeviceStatus(
      content::WebContents* web_contents,
      content::PermissionResult result,
      const GURL& requesting_origin,
      const GURL& embedding_origin);

  // Resets the permission.
  virtual void ResetPermission(const GURL& requesting_origin,
                               const GURL& embedding_origin);

  // Whether the permission status should take into account the device status
  // which can be provided by |UpdatePermissionStatusWithDeviceStatus|.
  virtual bool AlwaysIncludeDeviceStatus() const;

  // Whether the kill switch has been enabled for this permission.
  // public for permissions that do not use RequestPermission, like
  // camera and microphone, and for testing.
  bool IsPermissionKillSwitchOn() const;

  void AddObserver(permissions::Observer* permission_observer);
  void RemoveObserver(permissions::Observer* permission_observer);

  virtual std::unique_ptr<PermissionResolver> CreatePermissionResolver(
      const blink::mojom::PermissionDescriptorPtr& permission_descriptor) const;

  virtual std::unique_ptr<PermissionResolver>
  CreateRequestIndependentPermissionResolver() const;

  // Update the value of `last_has_device_permission_result_` and notify
  // observers if it changes.
  void MaybeUpdateCachedHasDevicePermission(content::WebContents* web_contents);

  ContentSettingsType content_settings_type() const {
    return content_settings_type_;
  }

  void set_has_device_permission_for_test(std::optional<bool> has_permission) {
    has_device_permission_for_test_ = has_permission;
  }

 protected:
  // Retrieves the current permission status. |render_frame_host| may be
  // nullptr.
  virtual base::Value GetPermissionStatusInternal(
      content::RenderFrameHost* render_frame_host,
      const GURL& requesting_origin,
      const GURL& embedding_origin) const;

  // Called if generic checks (existing content setting, embargo, etc.) fail to
  // resolve a permission request. The default implementation prompts the user.
  virtual void DecidePermission(
      std::unique_ptr<PermissionRequestData> request_data,
      BrowserPermissionCallback callback);

  // Updates stored setting if persist is set, updates tab indicators
  // and runs the callback to finish the request.
  virtual void NotifyPermissionSet(const PermissionRequestData& request_data,
                                   BrowserPermissionCallback callback,
                                   bool persist,
                                   PermissionDecision decision,
                                   bool is_final_decision);

  // Implementors can override this method to update the icons on the
  // url bar with the result of the new permission.
  virtual void UpdateTabContext(const PermissionRequestID& id,
                                const GURL& requesting_origin,
                                bool allowed) {}

  // Returns the browser context associated with this permission context.
  content::BrowserContext* browser_context() const;

  // Store the decided permission state. Virtual since the permission might be
  // stored with different restrictions (for example for desktop notifications).
  virtual void UpdateSetting(const PermissionRequestData& request_data,
                             base::Value setting,
                             bool is_one_time);

  // Whether the permission should be restricted to secure origins.
  virtual bool IsRestrictedToSecureOrigins() const;

  // Called by PermissionDecided when the user has made a permission decision.
  // Subclasses may override this method to perform context-specific logic
  // before the content setting is changed and the permission callback is run.
  virtual void UserMadePermissionDecision(const PermissionRequestID& id,
                                          const GURL& requesting_origin,
                                          const GURL& embedding_origin,
                                          PermissionDecision decision);

  // content_settings::Observer:
  void OnContentSettingChanged(
      const ContentSettingsPattern& primary_pattern,
      const ContentSettingsPattern& secondary_pattern,
      ContentSettingsTypeSet content_type_set) override;

  // Implementors can override this method to use a different PermissionRequest
  // implementation.
  virtual std::unique_ptr<PermissionRequest> CreatePermissionRequest(
      content::WebContents* web_contents,
      std::unique_ptr<PermissionRequestData> request_data,
      PermissionRequest::PermissionDecidedCallback permission_decided_callback,
      base::OnceClosure request_finished_callback) const;

  // Implementors can override this method to avoid using automatic embargo.
  virtual bool UsesAutomaticEmbargo() const;

  // Derived classes can use this function to find some particular permission
  // request.
  const PermissionRequest* FindPermissionRequest(
      const PermissionRequestID& id) const;

  // Implementors can override this method to use a different embedding origin.
  // TODO(crbug.com/40220500): This should return a url::Origin instead.
  virtual GURL GetEffectiveEmbedderOrigin(content::RenderFrameHost* rfh) const;

  base::ObserverList<permissions::Observer> permission_observers_;

  // Set by subclasses to inform the base class that they will handle adding
  // and removing themselves as observers to the HostContentSettingsMap.
  bool content_setting_observer_registered_by_subclass_ = false;

 private:
  friend class PermissionContextBaseTests;

  bool PermissionAllowedByPermissionsPolicy(
      content::RenderFrameHost* rfh) const;

  // Called when a request is no longer used so it can be cleaned up.
  void CleanUpRequest(content::WebContents* web_contents,
                      const PermissionRequestID& id,
                      bool embedded_permission_element_initiated);

  // This is the callback for PermissionRequest and is called once the user
  // allows/blocks/dismisses a permission prompt.
  void PermissionDecided(PermissionDecision decision,
                         bool is_final_decision,
                         const PermissionRequestData& request_data);

  void NotifyObservers(const ContentSettingsPattern& primary_pattern,
                       const ContentSettingsPattern& secondary_pattern,
                       ContentSettingsTypeSet content_type_set) const;

  raw_ptr<content::BrowserContext> browser_context_;
  const ContentSettingsType content_settings_type_;
  const network::mojom::PermissionsPolicyFeature permissions_policy_feature_;
  std::unordered_map<
      std::string,
      std::pair<base::WeakPtr<PermissionRequest>, BrowserPermissionCallback>>
      pending_requests_;

  mutable std::optional<bool> last_has_device_permission_result_ = std::nullopt;

  std::optional<bool> has_device_permission_for_test_;

  // Must be the last member, to ensure that it will be
  // destroyed first, which will invalidate weak pointers
  base::WeakPtrFactory<PermissionContextBase> weak_factory_{this};
};

}  // namespace permissions

#endif  // COMPONENTS_PERMISSIONS_PERMISSION_CONTEXT_BASE_H_