1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_
6 #define COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_
7 
8 #include "base/callback.h"
9 #include "base/gtest_prod_util.h"
10 #include "base/macros.h"
11 #include "base/memory/singleton.h"
12 #include "base/time/default_clock.h"
13 #include "components/content_settings/core/browser/host_content_settings_map.h"
14 #include "components/content_settings/core/common/content_settings_types.h"
15 #include "components/keyed_service/core/keyed_service.h"
16 #include "components/permissions/permission_result.h"
17 #include "url/gurl.h"
18 
19 class GURL;
20 
21 namespace settings {
22 FORWARD_DECLARE_TEST(SiteSettingsHandlerTest, GetAllSites);
23 FORWARD_DECLARE_TEST(SiteSettingsHandlerTest, GetRecentSitePermissions);
24 }  // namespace settings
25 
26 namespace site_settings {
27 FORWARD_DECLARE_TEST(RecentSiteSettingsHelperTest, CheckRecentSitePermissions);
28 }  // namespace site_settings
29 
30 namespace permissions {
31 
32 // The PermissionDecisionAutoBlocker decides whether or not a given origin
33 // should be automatically blocked from requesting a permission. When an origin
34 // is blocked, it is placed under an "embargo". Until the embargo expires, any
35 // requests made by the origin are automatically blocked. Once the embargo is
36 // lifted, the origin will be permitted to request a permission again, which may
37 // result in it being placed under embargo again. Currently, an origin can be
38 // placed under embargo if it has a number of prior dismissals greater than a
39 // threshold.
40 class PermissionDecisionAutoBlocker : public KeyedService {
41  public:
42   explicit PermissionDecisionAutoBlocker(HostContentSettingsMap* settings_map);
43   ~PermissionDecisionAutoBlocker() override;
44 
45   // Checks the status of the content setting to determine if |request_origin|
46   // is under embargo for |permission|. This checks all types of embargo.
47   // Prefer to use PermissionManager::GetPermissionStatus when possible. This
48   // method is only exposed to facilitate permission checks from threads other
49   // than the UI thread. See https://crbug.com/658020.
50   static PermissionResult GetEmbargoResult(HostContentSettingsMap* settings_map,
51                                            const GURL& request_origin,
52                                            ContentSettingsType permission,
53                                            base::Time current_time);
54 
55   // Updates the threshold to start blocking prompts from the field trial.
56   static void UpdateFromVariations();
57 
58   // Checks the status of the content setting to determine if |request_origin|
59   // is under embargo for |permission|. This checks all types of embargo.
60   PermissionResult GetEmbargoResult(const GURL& request_origin,
61                                     ContentSettingsType permission);
62 
63   // Returns the most recent recorded time either an ignore or dismiss embargo
64   // was started. Records of embargo start times persist beyond the duration of
65   // the embargo, but are removed along with embargoes when RemoveEmbargoByUrl
66   // or RemoveCountsByUrl are used. Returns base::Time() if no record is found.
67   base::Time GetEmbargoStartTime(const GURL& request_origin,
68                                  ContentSettingsType permission);
69 
70   // Returns the current number of dismisses recorded for |permission| type at
71   // |url|.
72   int GetDismissCount(const GURL& url, ContentSettingsType permission);
73 
74   // Returns the current number of ignores recorded for |permission|
75   // type at |url|.
76   int GetIgnoreCount(const GURL& url, ContentSettingsType permission);
77 
78   // Returns a set of urls currently under embargo for |content_type|.
79   std::set<GURL> GetEmbargoedOrigins(ContentSettingsType content_type);
80 
81   // Returns a set of urls currently under embargo for the provided
82   // |content_type| types.
83   std::set<GURL> GetEmbargoedOrigins(
84       std::vector<ContentSettingsType> content_types);
85 
86   // Records that a dismissal of a prompt for |permission| was made. If the
87   // total number of dismissals exceeds a threshhold and
88   // features::kBlockPromptsIfDismissedOften is enabled, it will place |url|
89   // under embargo for |permission|. |dismissed_prompt_was_quiet| will inform
90   // the decision of which threshold to pick, depending on whether the prompt
91   // that was presented to the user was quiet or not.
92   bool RecordDismissAndEmbargo(const GURL& url,
93                                ContentSettingsType permission,
94                                bool dismissed_prompt_was_quiet);
95 
96   // Records that an ignore of a prompt for |permission| was made. If the total
97   // number of ignores exceeds a threshold and
98   // features::kBlockPromptsIfIgnoredOften is enabled, it will place |url| under
99   // embargo for |permission|. |ignored_prompt_was_quiet| will inform the
100   // decision of which threshold to pick, depending on whether the prompt that
101   // was presented to the user was quiet or not.
102   bool RecordIgnoreAndEmbargo(const GURL& url,
103                               ContentSettingsType permission,
104                               bool ignored_prompt_was_quiet);
105 
106   // Clears any existing embargo status for |url|, |permission|. For permissions
107   // embargoed under repeated dismissals, this means a prompt will be shown to
108   // the user on next permission request. This is a NO-OP for non-embargoed
109   // |url|, |permission| pairs.
110   void RemoveEmbargoByUrl(const GURL& url, ContentSettingsType permission);
111 
112   // Removes any recorded counts for urls which match |filter|.
113   void RemoveCountsByUrl(base::Callback<bool(const GURL& url)> filter);
114 
115   static const char* GetPromptDismissCountKeyForTesting();
116 
117  private:
118   friend class PermissionDecisionAutoBlockerUnitTest;
119   FRIEND_TEST_ALL_PREFIXES(site_settings::RecentSiteSettingsHelperTest,
120                            CheckRecentSitePermissions);
121   FRIEND_TEST_ALL_PREFIXES(settings::SiteSettingsHandlerTest, GetAllSites);
122   FRIEND_TEST_ALL_PREFIXES(settings::SiteSettingsHandlerTest,
123                            GetRecentSitePermissions);
124 
125   void PlaceUnderEmbargo(const GURL& request_origin,
126                          ContentSettingsType permission,
127                          const char* key);
128 
129   void SetClockForTesting(base::Clock* clock);
130 
131   // Keys used for storing count data in a website setting.
132   static const char kPromptDismissCountKey[];
133   static const char kPromptIgnoreCountKey[];
134   static const char kPromptDismissCountWithQuietUiKey[];
135   static const char kPromptIgnoreCountWithQuietUiKey[];
136   static const char kPermissionDismissalEmbargoKey[];
137   static const char kPermissionIgnoreEmbargoKey[];
138 
139   HostContentSettingsMap* settings_map_;
140 
141   base::Clock* clock_;
142 
143   DISALLOW_IMPLICIT_CONSTRUCTORS(PermissionDecisionAutoBlocker);
144 };
145 
146 }  // namespace permissions
147 
148 #endif  // COMPONENTS_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_
149