1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_
6 #define COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_
10 #include "base/functional/callback.h"
11 #include "base/gtest_prod_util.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/observer_list_types.h"
14 #include "base/time/default_clock.h"
15 #include "components/content_settings/core/browser/host_content_settings_map.h"
16 #include "components/content_settings/core/common/content_settings_types.h"
17 #include "components/keyed_service/core/keyed_service.h"
18 #include "content/public/browser/permission_result.h"
19 #include "third_party/abseil-cpp/absl/types/optional.h"
25 FORWARD_DECLARE_TEST(SiteSettingsHandlerTest, GetAllSites);
26 FORWARD_DECLARE_TEST(SiteSettingsHandlerTest, GetRecentSitePermissions);
27 FORWARD_DECLARE_TEST(SiteSettingsHandlerTest,
28 StorageAccessExceptions_Description_Embargoed);
29 FORWARD_DECLARE_TEST(SiteSettingsHandlerTest,
30 StorageAccessExceptions_Description_EmbargoedTwoProfiles);
31 } // namespace settings
33 namespace site_settings {
34 FORWARD_DECLARE_TEST(RecentSiteSettingsHelperTest, CheckRecentSitePermissions);
35 } // namespace site_settings
37 namespace permissions {
39 // Mockable interface for PermissionDecisionAutoBlocker (see below), for those
40 // few instances where this is used outside of permissions and needs separate
42 class PermissionDecisionAutoBlockerBase {
44 PermissionDecisionAutoBlockerBase() = default;
45 virtual ~PermissionDecisionAutoBlockerBase() = default;
47 PermissionDecisionAutoBlockerBase(const PermissionDecisionAutoBlockerBase&) =
49 PermissionDecisionAutoBlockerBase& operator=(
50 const PermissionDecisionAutoBlockerBase&) = delete;
52 // Returns whether |request_origin| is under embargo for |permission|.
53 virtual bool IsEmbargoed(const GURL& request_origin,
54 ContentSettingsType permission) = 0;
56 // Records that a dismissal of a prompt for |permission| was made. If the
57 // total number of dismissals exceeds a threshhold and
58 // features::kBlockPromptsIfDismissedOften is enabled, it will place |url|
59 // under embargo for |permission|. |dismissed_prompt_was_quiet| will inform
60 // the decision of which threshold to pick, depending on whether the prompt
61 // that was presented to the user was quiet or not.
62 virtual bool RecordDismissAndEmbargo(const GURL& url,
63 ContentSettingsType permission,
64 bool dismissed_prompt_was_quiet) = 0;
66 // Records that an ignore of a prompt for |permission| was made. If the
67 // total number of ignores exceeds a threshold and
68 // features::kBlockPromptsIfIgnoredOften is enabled, it will place |url|
69 // under embargo for |permission|. |ignored_prompt_was_quiet| will inform
70 // the decision of which threshold to pick, depending on whether the prompt
71 // that was presented to the user was quiet or not.
72 virtual bool RecordIgnoreAndEmbargo(const GURL& url,
73 ContentSettingsType permission,
74 bool ignored_prompt_was_quiet) = 0;
77 // The PermissionDecisionAutoBlocker decides whether or not a given origin
78 // should be automatically blocked from requesting a permission. When an origin
79 // is blocked, it is placed under an "embargo". Until the embargo expires, any
80 // requests made by the origin are automatically blocked. Once the embargo is
81 // lifted, the origin will be permitted to request a permission again, which may
82 // result in it being placed under embargo again. Currently, an origin can be
83 // placed under embargo if it has a number of prior dismissals greater than a
85 class PermissionDecisionAutoBlocker : public PermissionDecisionAutoBlockerBase,
88 class Observer : public base::CheckedObserver {
90 virtual void OnEmbargoStarted(const GURL& origin,
91 ContentSettingsType content_setting) = 0;
94 PermissionDecisionAutoBlocker() = delete;
96 explicit PermissionDecisionAutoBlocker(HostContentSettingsMap* settings_map);
98 ~PermissionDecisionAutoBlocker() override;
100 // PermissionDecisionAutoBlockerBase
101 bool IsEmbargoed(const GURL& request_origin,
102 ContentSettingsType permission) override;
103 bool RecordDismissAndEmbargo(const GURL& url,
104 ContentSettingsType permission,
105 bool dismissed_prompt_was_quiet) override;
106 bool RecordIgnoreAndEmbargo(const GURL& url,
107 ContentSettingsType permission,
108 bool ignored_prompt_was_quiet) override;
110 // Returns whether the permission auto blocker is enabled for the passed-in
112 static bool IsEnabledForContentSetting(ContentSettingsType content_setting);
114 // Checks the status of the content setting to determine if |request_origin|
115 // is under embargo for |permission|. This checks all types of embargo.
116 // Prefer to use PermissionManager::GetPermissionStatus when possible. This
117 // method is only exposed to facilitate permission checks from threads other
118 // than the UI thread. See https://crbug.com/658020.
119 static absl::optional<content::PermissionResult> GetEmbargoResult(
120 HostContentSettingsMap* settings_map,
121 const GURL& request_origin,
122 ContentSettingsType permission,
123 base::Time current_time);
125 // Updates the threshold to start blocking prompts from the field trial.
126 static void UpdateFromVariations();
128 // Checks the status of the content setting to determine if |request_origin|
129 // is under embargo for |permission|. This checks all types of embargo.
130 absl::optional<content::PermissionResult> GetEmbargoResult(
131 const GURL& request_origin,
132 ContentSettingsType permission);
134 // Returns the most recent recorded time either an ignore or dismiss embargo
135 // was started. Records of embargo start times persist beyond the duration
136 // of the embargo, but are removed along with embargoes when
137 // RemoveEmbargoAndResetCounts is used. Returns base::Time() if no record is
139 base::Time GetEmbargoStartTime(const GURL& request_origin,
140 ContentSettingsType permission);
142 // Returns the current number of dismisses recorded for |permission| type at
144 int GetDismissCount(const GURL& url, ContentSettingsType permission);
146 // Returns the current number of ignores recorded for |permission|
148 int GetIgnoreCount(const GURL& url, ContentSettingsType permission);
150 // Returns a set of urls currently under embargo for |content_type|.
151 std::set<GURL> GetEmbargoedOrigins(ContentSettingsType content_type);
153 // Returns a set of urls currently under embargo for the provided
154 // |content_type| types.
155 std::set<GURL> GetEmbargoedOrigins(
156 std::vector<ContentSettingsType> content_types);
158 // Records that a prompt was displayed for |permission|. If
159 // features::kBlockRepeatedAutoReauthnPrompts is enabled, it will place |url|
160 // under embargo for |permission|.
161 bool RecordDisplayAndEmbargo(const GURL& url, ContentSettingsType permission);
163 // Clears any existing embargo status for |url|, |permission|. For
164 // permissions embargoed under repeated dismissals, this means a prompt will
165 // be shown to the user on next permission request. Clears dismiss and
167 void RemoveEmbargoAndResetCounts(const GURL& url,
168 ContentSettingsType permission);
170 // Same as above, but cleans the slate for all permissions and for all URLs
171 // matching |filter|.
172 void RemoveEmbargoAndResetCounts(
173 base::RepeatingCallback<bool(const GURL& url)> filter);
175 // Add and remove observers that want to receive embargo status updates.
176 void AddObserver(Observer* obs);
177 void RemoveObserver(Observer* obs);
179 static const char* GetPromptDismissCountKeyForTesting();
182 friend class PermissionDecisionAutoBlockerUnitTest;
183 FRIEND_TEST_ALL_PREFIXES(site_settings::RecentSiteSettingsHelperTest,
184 CheckRecentSitePermissions);
185 FRIEND_TEST_ALL_PREFIXES(settings::SiteSettingsHandlerTest, GetAllSites);
186 FRIEND_TEST_ALL_PREFIXES(settings::SiteSettingsHandlerTest,
187 GetRecentSitePermissions);
188 FRIEND_TEST_ALL_PREFIXES(settings::SiteSettingsHandlerTest,
189 StorageAccessExceptions_Description_Embargoed);
190 FRIEND_TEST_ALL_PREFIXES(
191 settings::SiteSettingsHandlerTest,
192 StorageAccessExceptions_Description_EmbargoedTwoProfiles);
194 void PlaceUnderEmbargo(const GURL& request_origin,
195 ContentSettingsType permission,
198 void NotifyEmbargoStarted(const GURL& origin,
199 ContentSettingsType content_setting);
201 void SetClockForTesting(base::Clock* clock);
203 // Keys used for storing count data in a website setting.
204 static const char kPromptDismissCountKey[];
205 static const char kPromptIgnoreCountKey[];
206 static const char kPromptDismissCountWithQuietUiKey[];
207 static const char kPromptIgnoreCountWithQuietUiKey[];
208 static const char kPermissionDismissalEmbargoKey[];
209 static const char kPermissionIgnoreEmbargoKey[];
210 static const char kPermissionDisplayEmbargoKey[];
212 raw_ptr<HostContentSettingsMap> settings_map_;
214 raw_ptr<base::Clock> clock_;
216 base::ObserverList<Observer> observers_;
219 } // namespace permissions
221 #endif // COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_