| // Copyright 2016 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_DECISION_AUTO_BLOCKER_H_ |
| #define COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_ |
| |
| #include <optional> |
| #include <set> |
| |
| #include "base/functional/callback.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/observer_list_types.h" |
| #include "base/time/default_clock.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "components/content_settings/core/common/content_settings_types.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| #include "content/public/browser/permission_result.h" |
| #include "url/gurl.h" |
| |
| class GURL; |
| |
| namespace permissions { |
| |
| // Mockable interface for PermissionDecisionAutoBlocker (see below), for those |
| // few instances where this is used outside of permissions and needs separate |
| // unit tests. |
| class PermissionDecisionAutoBlockerBase { |
| public: |
| PermissionDecisionAutoBlockerBase() = default; |
| virtual ~PermissionDecisionAutoBlockerBase() = default; |
| |
| PermissionDecisionAutoBlockerBase(const PermissionDecisionAutoBlockerBase&) = |
| delete; |
| PermissionDecisionAutoBlockerBase& operator=( |
| const PermissionDecisionAutoBlockerBase&) = delete; |
| |
| // Returns whether |request_origin| is under embargo for |permission|. |
| virtual bool IsEmbargoed(const GURL& request_origin, |
| ContentSettingsType permission) = 0; |
| |
| // Records that a dismissal of a prompt for |permission| was made. If the |
| // total number of dismissals exceeds a threshold it will place |url| |
| // under embargo for |permission|. |dismissed_prompt_was_quiet| will inform |
| // the decision of which threshold to pick, depending on whether the prompt |
| // that was presented to the user was quiet or not. |
| virtual bool RecordDismissAndEmbargo(const GURL& url, |
| ContentSettingsType permission, |
| bool dismissed_prompt_was_quiet) = 0; |
| |
| // Records that an ignore of a prompt for |permission| was made. If the |
| // total number of ignores exceeds a threshold it will place |url| |
| // under embargo for |permission|. |ignored_prompt_was_quiet| will inform |
| // the decision of which threshold to pick, depending on whether the prompt |
| // that was presented to the user was quiet or not. |
| virtual bool RecordIgnoreAndEmbargo(const GURL& url, |
| ContentSettingsType permission, |
| bool ignored_prompt_was_quiet) = 0; |
| }; |
| |
| // The PermissionDecisionAutoBlocker decides whether or not a given origin |
| // should be automatically blocked from requesting a permission. When an origin |
| // is blocked, it is placed under an "embargo". Until the embargo expires, any |
| // requests made by the origin are automatically blocked. Once the embargo is |
| // lifted, the origin will be permitted to request a permission again, which may |
| // result in it being placed under embargo again. Currently, an origin can be |
| // placed under embargo if it has a number of prior dismissals greater than a |
| // threshold. |
| class PermissionDecisionAutoBlocker : public PermissionDecisionAutoBlockerBase, |
| public KeyedService { |
| public: |
| class Observer : public base::CheckedObserver { |
| public: |
| virtual void OnEmbargoStarted(const GURL& origin, |
| ContentSettingsType content_setting) = 0; |
| }; |
| |
| PermissionDecisionAutoBlocker() = delete; |
| |
| explicit PermissionDecisionAutoBlocker(HostContentSettingsMap* settings_map); |
| |
| ~PermissionDecisionAutoBlocker() override; |
| |
| // PermissionDecisionAutoBlockerBase |
| bool IsEmbargoed(const GURL& request_origin, |
| ContentSettingsType permission) override; |
| bool RecordDismissAndEmbargo(const GURL& url, |
| ContentSettingsType permission, |
| bool dismissed_prompt_was_quiet) override; |
| bool RecordIgnoreAndEmbargo(const GURL& url, |
| ContentSettingsType permission, |
| bool ignored_prompt_was_quiet) override; |
| |
| // Returns whether the permission auto blocker is enabled for the passed-in |
| // content setting. |
| static bool IsEnabledForContentSetting(ContentSettingsType content_setting); |
| |
| // Checks the status of the content setting to determine if |request_origin| |
| // is under embargo for |permission|. This checks all types of embargo. |
| // Prefer to use PermissionManager::GetPermissionStatus when possible. This |
| // method is only exposed to facilitate permission checks from threads other |
| // than the UI thread. See https://crbug.com/658020. |
| static std::optional<content::PermissionResult> GetEmbargoResult( |
| HostContentSettingsMap* settings_map, |
| const GURL& request_origin, |
| ContentSettingsType permission, |
| base::Time current_time); |
| |
| // Checks the status of the content setting to determine if |request_origin| |
| // is under embargo for |permission|. This checks all types of embargo. |
| std::optional<content::PermissionResult> GetEmbargoResult( |
| const GURL& request_origin, |
| ContentSettingsType permission); |
| |
| // Returns the most recent recorded time either an ignore or dismiss embargo |
| // was started. Records of embargo start times persist beyond the duration |
| // of the embargo, but are removed along with embargoes when |
| // RemoveEmbargoAndResetCounts is used. Returns base::Time() if no record is |
| // found. |
| base::Time GetEmbargoStartTime(const GURL& request_origin, |
| ContentSettingsType permission); |
| |
| // Returns the current number of dismisses recorded for |permission| type at |
| // |url|. |
| int GetDismissCount(const GURL& url, ContentSettingsType permission); |
| |
| // Returns the current number of ignores recorded for |permission| |
| // type at |url|. |
| int GetIgnoreCount(const GURL& url, ContentSettingsType permission); |
| |
| // Returns a set of urls currently under embargo for |content_type|. |
| std::set<GURL> GetEmbargoedOrigins(ContentSettingsType content_type); |
| |
| // Returns a set of urls currently under embargo for the provided |
| // |content_type| types. |
| std::set<GURL> GetEmbargoedOrigins( |
| std::vector<ContentSettingsType> content_types); |
| |
| // Records that a prompt was displayed for |permission| and places |url| |
| // under embargo for |permission|. |
| bool RecordDisplayAndEmbargo(const GURL& url, ContentSettingsType permission); |
| |
| // Clears any existing embargo status for |url|, |permission|. For |
| // permissions embargoed under repeated dismissals, this means a prompt will |
| // be shown to the user on next permission request. Clears dismiss and |
| // ignore counts. |
| void RemoveEmbargoAndResetCounts(const GURL& url, |
| ContentSettingsType permission); |
| |
| // Same as above, but cleans the slate for all permissions and for all URLs |
| // matching |filter|. |
| void RemoveEmbargoAndResetCounts( |
| base::RepeatingCallback<bool(const GURL& url)> filter); |
| |
| // Add and remove observers that want to receive embargo status updates. |
| void AddObserver(Observer* obs); |
| void RemoveObserver(Observer* obs); |
| |
| static const char* GetPromptDismissCountKeyForTesting(); |
| |
| void SetClockForTesting(base::Clock* clock); |
| |
| private: |
| void PlaceUnderEmbargo(const GURL& request_origin, |
| ContentSettingsType permission, |
| const char* key); |
| |
| void NotifyEmbargoStarted(const GURL& origin, |
| ContentSettingsType content_setting); |
| |
| // Keys used for storing count data in a website setting. |
| static const char kPromptDismissCountKey[]; |
| static const char kPromptIgnoreCountKey[]; |
| static const char kPromptDismissCountWithQuietUiKey[]; |
| static const char kPromptIgnoreCountWithQuietUiKey[]; |
| static const char kPermissionDismissalEmbargoKey[]; |
| static const char kPermissionIgnoreEmbargoKey[]; |
| static const char kPermissionDisplayEmbargoKey[]; |
| |
| raw_ptr<HostContentSettingsMap> settings_map_; |
| |
| raw_ptr<base::Clock> clock_; |
| |
| base::ObserverList<Observer> observers_; |
| }; |
| |
| } // namespace permissions |
| |
| #endif // COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_ |