| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/permissions/permission_decision_auto_blocker.h" | 5 #include "chrome/browser/permissions/permission_decision_auto_blocker.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/feature_list.h" | 9 #include "base/feature_list.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "components/keyed_service/content/browser_context_dependency_manager.h" | 22 #include "components/keyed_service/content/browser_context_dependency_manager.h" |
| 23 #include "components/safe_browsing_db/database_manager.h" | 23 #include "components/safe_browsing_db/database_manager.h" |
| 24 #include "components/variations/variations_associated_data.h" | 24 #include "components/variations/variations_associated_data.h" |
| 25 #include "content/public/browser/web_contents.h" | 25 #include "content/public/browser/web_contents.h" |
| 26 #include "url/gurl.h" | 26 #include "url/gurl.h" |
| 27 | 27 |
| 28 namespace { | 28 namespace { |
| 29 | 29 |
| 30 // The number of times that users may explicitly dismiss a permission prompt | 30 // The number of times that users may explicitly dismiss a permission prompt |
| 31 // from an origin before it is automatically blocked. | 31 // from an origin before it is automatically blocked. |
| 32 int g_prompt_dismissals_before_block = 3; | 32 int g_dismissals_before_block = 3; |
| 33 |
| 34 // The number of times that users may ignore a permission prompt from an origin |
| 35 // before it is automatically blocked. |
| 36 int g_ignores_before_block = 4; |
| 37 |
| 38 // The number of days that an origin will stay under embargo for a requested |
| 39 // permission due to repeated dismissals. |
| 40 int g_dismissal_embargo_days = 7; |
| 41 |
| 42 // The number of days that an origin will stay under embargo for a requested |
| 43 // permission due to repeated ignores. |
| 44 int g_ignore_embargo_days = 7; |
| 33 | 45 |
| 34 // The number of days that an origin will stay under embargo for a requested | 46 // The number of days that an origin will stay under embargo for a requested |
| 35 // permission due to blacklisting. | 47 // permission due to blacklisting. |
| 36 int g_blacklist_embargo_days = 7; | 48 int g_blacklist_embargo_days = 7; |
| 37 | 49 |
| 38 // The number of days that an origin will stay under embargo for a requested | |
| 39 // permission due to repeated dismissals. | |
| 40 int g_dismissal_embargo_days = 7; | |
| 41 | |
| 42 // Maximum time in milliseconds to wait for safe browsing service to check a | 50 // Maximum time in milliseconds to wait for safe browsing service to check a |
| 43 // url for blacklisting. After this amount of time, the check will be aborted | 51 // url for blacklisting. After this amount of time, the check will be aborted |
| 44 // and the url will be treated as not safe. | 52 // and the url will be treated as not safe. |
| 45 // TODO(meredithl): Revisit this once UMA metrics have data about request time. | 53 // TODO(meredithl): Revisit this once UMA metrics have data about request time. |
| 46 const int kCheckUrlTimeoutMs = 2000; | 54 const int kCheckUrlTimeoutMs = 2000; |
| 47 | 55 |
| 48 std::unique_ptr<base::DictionaryValue> GetOriginDict( | 56 std::unique_ptr<base::DictionaryValue> GetOriginDict( |
| 49 HostContentSettingsMap* settings, | 57 HostContentSettingsMap* settings, |
| 50 const GURL& origin_url) { | 58 const GURL& origin_url) { |
| 51 std::unique_ptr<base::DictionaryValue> dict = | 59 std::unique_ptr<base::DictionaryValue> dict = |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 HostContentSettingsMapFactory::GetForProfile(profile); | 110 HostContentSettingsMapFactory::GetForProfile(profile); |
| 103 std::unique_ptr<base::DictionaryValue> dict = GetOriginDict(map, url); | 111 std::unique_ptr<base::DictionaryValue> dict = GetOriginDict(map, url); |
| 104 base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( | 112 base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( |
| 105 dict.get(), PermissionUtil::GetPermissionString(permission)); | 113 dict.get(), PermissionUtil::GetPermissionString(permission)); |
| 106 | 114 |
| 107 int current_count = 0; | 115 int current_count = 0; |
| 108 permission_dict->GetInteger(key, ¤t_count); | 116 permission_dict->GetInteger(key, ¤t_count); |
| 109 return current_count; | 117 return current_count; |
| 110 } | 118 } |
| 111 | 119 |
| 120 bool IsUnderEmbargo(base::DictionaryValue* permission_dict, |
| 121 const base::Feature& feature, |
| 122 const char* key, |
| 123 base::Time current_time, |
| 124 base::TimeDelta offset) { |
| 125 double embargo_date = -1; |
| 126 |
| 127 if (base::FeatureList::IsEnabled(feature) && |
| 128 permission_dict->GetDouble(key, &embargo_date)) { |
| 129 if (current_time < base::Time::FromInternalValue(embargo_date) + offset) |
| 130 return true; |
| 131 } |
| 132 |
| 133 return false; |
| 134 } |
| 135 |
| 112 } // namespace | 136 } // namespace |
| 113 | 137 |
| 114 // PermissionDecisionAutoBlocker::Factory -------------------------------------- | 138 // PermissionDecisionAutoBlocker::Factory -------------------------------------- |
| 115 | 139 |
| 116 // static | 140 // static |
| 117 PermissionDecisionAutoBlocker* | 141 PermissionDecisionAutoBlocker* |
| 118 PermissionDecisionAutoBlocker::Factory::GetForProfile(Profile* profile) { | 142 PermissionDecisionAutoBlocker::Factory::GetForProfile(Profile* profile) { |
| 119 return static_cast<PermissionDecisionAutoBlocker*>( | 143 return static_cast<PermissionDecisionAutoBlocker*>( |
| 120 GetInstance()->GetServiceForBrowserContext(profile, true)); | 144 GetInstance()->GetServiceForBrowserContext(profile, true)); |
| 121 } | 145 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 149 | 173 |
| 150 // static | 174 // static |
| 151 const char PermissionDecisionAutoBlocker::kPromptDismissCountKey[] = | 175 const char PermissionDecisionAutoBlocker::kPromptDismissCountKey[] = |
| 152 "dismiss_count"; | 176 "dismiss_count"; |
| 153 | 177 |
| 154 // static | 178 // static |
| 155 const char PermissionDecisionAutoBlocker::kPromptIgnoreCountKey[] = | 179 const char PermissionDecisionAutoBlocker::kPromptIgnoreCountKey[] = |
| 156 "ignore_count"; | 180 "ignore_count"; |
| 157 | 181 |
| 158 // static | 182 // static |
| 183 const char PermissionDecisionAutoBlocker::kPermissionDismissalEmbargoKey[] = |
| 184 "dismissal_embargo_days"; |
| 185 |
| 186 // static |
| 187 const char PermissionDecisionAutoBlocker::kPermissionIgnoreEmbargoKey[] = |
| 188 "ignore_embargo_days"; |
| 189 |
| 190 // static |
| 159 const char PermissionDecisionAutoBlocker::kPermissionBlacklistEmbargoKey[] = | 191 const char PermissionDecisionAutoBlocker::kPermissionBlacklistEmbargoKey[] = |
| 160 "blacklisting_embargo_days"; | 192 "blacklisting_embargo_days"; |
| 161 | 193 |
| 162 // static | 194 // static |
| 163 const char PermissionDecisionAutoBlocker::kPermissionDismissalEmbargoKey[] = | |
| 164 "dismissal_embargo_days"; | |
| 165 | |
| 166 // static | |
| 167 PermissionDecisionAutoBlocker* PermissionDecisionAutoBlocker::GetForProfile( | 195 PermissionDecisionAutoBlocker* PermissionDecisionAutoBlocker::GetForProfile( |
| 168 Profile* profile) { | 196 Profile* profile) { |
| 169 return PermissionDecisionAutoBlocker::Factory::GetForProfile(profile); | 197 return PermissionDecisionAutoBlocker::Factory::GetForProfile(profile); |
| 170 } | 198 } |
| 171 | 199 |
| 172 // static | 200 // static |
| 173 void PermissionDecisionAutoBlocker::UpdateFromVariations() { | 201 void PermissionDecisionAutoBlocker::UpdateFromVariations() { |
| 174 int prompt_dismissals = -1; | 202 int dismissals_before_block = -1; |
| 203 int ignores_before_block = -1; |
| 204 int dismissal_embargo_days = -1; |
| 205 int ignore_embargo_days = -1; |
| 175 int blacklist_embargo_days = -1; | 206 int blacklist_embargo_days = -1; |
| 176 int dismissal_embargo_days = -1; | 207 |
| 177 std::string dismissals_value = variations::GetVariationParamValueByFeature( | 208 std::string dismissals_before_block_value = |
| 178 features::kBlockPromptsIfDismissedOften, kPromptDismissCountKey); | |
| 179 std::string blacklist_embargo_value = | |
| 180 variations::GetVariationParamValueByFeature( | 209 variations::GetVariationParamValueByFeature( |
| 181 features::kPermissionsBlacklist, kPermissionBlacklistEmbargoKey); | 210 features::kBlockPromptsIfDismissedOften, kPromptDismissCountKey); |
| 182 std::string dismissal_embargo_value = | 211 std::string ignores_before_block_value = |
| 212 variations::GetVariationParamValueByFeature( |
| 213 features::kBlockPromptsIfIgnoredOften, kPromptIgnoreCountKey); |
| 214 std::string dismissal_embargo_days_value = |
| 183 variations::GetVariationParamValueByFeature( | 215 variations::GetVariationParamValueByFeature( |
| 184 features::kBlockPromptsIfDismissedOften, | 216 features::kBlockPromptsIfDismissedOften, |
| 185 kPermissionDismissalEmbargoKey); | 217 kPermissionDismissalEmbargoKey); |
| 218 std::string ignore_embargo_days_value = |
| 219 variations::GetVariationParamValueByFeature( |
| 220 features::kBlockPromptsIfIgnoredOften, kPermissionIgnoreEmbargoKey); |
| 221 std::string blacklist_embargo_days_value = |
| 222 variations::GetVariationParamValueByFeature( |
| 223 features::kPermissionsBlacklist, kPermissionBlacklistEmbargoKey); |
| 224 |
| 186 // If converting the value fails, stick with the current value. | 225 // If converting the value fails, stick with the current value. |
| 187 if (base::StringToInt(dismissals_value, &prompt_dismissals) && | 226 if (base::StringToInt(dismissals_before_block_value, |
| 188 prompt_dismissals > 0) { | 227 &dismissals_before_block) && |
| 189 g_prompt_dismissals_before_block = prompt_dismissals; | 228 dismissals_before_block > 0) { |
| 229 g_dismissals_before_block = dismissals_before_block; |
| 190 } | 230 } |
| 191 if (base::StringToInt(blacklist_embargo_value, &blacklist_embargo_days) && | 231 if (base::StringToInt(ignores_before_block_value, &ignores_before_block) && |
| 232 ignores_before_block > 0) { |
| 233 g_ignores_before_block = ignores_before_block; |
| 234 } |
| 235 if (base::StringToInt(dismissal_embargo_days_value, |
| 236 &dismissal_embargo_days) && |
| 237 dismissal_embargo_days > 0) { |
| 238 g_dismissal_embargo_days = dismissal_embargo_days; |
| 239 } |
| 240 if (base::StringToInt(ignore_embargo_days_value, &ignore_embargo_days) && |
| 241 ignore_embargo_days > 0) { |
| 242 g_ignore_embargo_days = ignore_embargo_days; |
| 243 } |
| 244 if (base::StringToInt(blacklist_embargo_days_value, |
| 245 &blacklist_embargo_days) && |
| 192 blacklist_embargo_days > 0) { | 246 blacklist_embargo_days > 0) { |
| 193 g_blacklist_embargo_days = blacklist_embargo_days; | 247 g_blacklist_embargo_days = blacklist_embargo_days; |
| 194 } | 248 } |
| 195 if (base::StringToInt(dismissal_embargo_value, &dismissal_embargo_days) && | |
| 196 dismissal_embargo_days > 0) { | |
| 197 g_dismissal_embargo_days = dismissal_embargo_days; | |
| 198 } | |
| 199 } | 249 } |
| 200 | 250 |
| 201 void PermissionDecisionAutoBlocker::CheckSafeBrowsingBlacklist( | 251 void PermissionDecisionAutoBlocker::CheckSafeBrowsingBlacklist( |
| 202 content::WebContents* web_contents, | 252 content::WebContents* web_contents, |
| 203 const GURL& request_origin, | 253 const GURL& request_origin, |
| 204 ContentSettingsType permission, | 254 ContentSettingsType permission, |
| 205 base::Callback<void(bool)> callback) { | 255 base::Callback<void(bool)> callback) { |
| 206 DCHECK_EQ(CONTENT_SETTING_ASK, | 256 DCHECK_EQ(CONTENT_SETTING_ASK, |
| 207 GetEmbargoResult(request_origin, permission).content_setting); | 257 GetEmbargoResult(request_origin, permission).content_setting); |
| 208 | 258 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 225 | 275 |
| 226 PermissionResult PermissionDecisionAutoBlocker::GetEmbargoResult( | 276 PermissionResult PermissionDecisionAutoBlocker::GetEmbargoResult( |
| 227 const GURL& request_origin, | 277 const GURL& request_origin, |
| 228 ContentSettingsType permission) { | 278 ContentSettingsType permission) { |
| 229 HostContentSettingsMap* map = | 279 HostContentSettingsMap* map = |
| 230 HostContentSettingsMapFactory::GetForProfile(profile_); | 280 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 231 std::unique_ptr<base::DictionaryValue> dict = | 281 std::unique_ptr<base::DictionaryValue> dict = |
| 232 GetOriginDict(map, request_origin); | 282 GetOriginDict(map, request_origin); |
| 233 base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( | 283 base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( |
| 234 dict.get(), PermissionUtil::GetPermissionString(permission)); | 284 dict.get(), PermissionUtil::GetPermissionString(permission)); |
| 235 double embargo_date = -1; | |
| 236 | 285 |
| 237 base::Time current_time = clock_->Now(); | 286 base::Time current_time = clock_->Now(); |
| 238 if (base::FeatureList::IsEnabled(features::kPermissionsBlacklist) && | 287 if (IsUnderEmbargo(permission_dict, features::kPermissionsBlacklist, |
| 239 permission_dict->GetDouble(kPermissionBlacklistEmbargoKey, | 288 kPermissionBlacklistEmbargoKey, current_time, |
| 240 &embargo_date)) { | 289 base::TimeDelta::FromDays(g_blacklist_embargo_days))) { |
| 241 if (current_time < | 290 return PermissionResult(CONTENT_SETTING_BLOCK, |
| 242 base::Time::FromInternalValue(embargo_date) + | 291 PermissionStatusSource::SAFE_BROWSING_BLACKLIST); |
| 243 base::TimeDelta::FromDays(g_blacklist_embargo_days)) { | |
| 244 return PermissionResult(CONTENT_SETTING_BLOCK, | |
| 245 PermissionStatusSource::SAFE_BROWSING_BLACKLIST); | |
| 246 } | |
| 247 } | 292 } |
| 248 | 293 |
| 249 if (base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften) && | 294 if (IsUnderEmbargo(permission_dict, features::kBlockPromptsIfDismissedOften, |
| 250 permission_dict->GetDouble(kPermissionDismissalEmbargoKey, | 295 kPermissionDismissalEmbargoKey, current_time, |
| 251 &embargo_date)) { | 296 base::TimeDelta::FromDays(g_dismissal_embargo_days))) { |
| 252 if (current_time < | 297 return PermissionResult(CONTENT_SETTING_BLOCK, |
| 253 base::Time::FromInternalValue(embargo_date) + | 298 PermissionStatusSource::MULTIPLE_DISMISSALS); |
| 254 base::TimeDelta::FromDays(g_dismissal_embargo_days)) { | 299 } |
| 255 return PermissionResult(CONTENT_SETTING_BLOCK, | 300 |
| 256 PermissionStatusSource::MULTIPLE_DISMISSALS); | 301 if (IsUnderEmbargo(permission_dict, features::kBlockPromptsIfIgnoredOften, |
| 257 } | 302 kPermissionIgnoreEmbargoKey, current_time, |
| 303 base::TimeDelta::FromDays(g_ignore_embargo_days))) { |
| 304 return PermissionResult(CONTENT_SETTING_BLOCK, |
| 305 PermissionStatusSource::MULTIPLE_IGNORES); |
| 258 } | 306 } |
| 259 | 307 |
| 260 return PermissionResult(CONTENT_SETTING_ASK, | 308 return PermissionResult(CONTENT_SETTING_ASK, |
| 261 PermissionStatusSource::UNSPECIFIED); | 309 PermissionStatusSource::UNSPECIFIED); |
| 262 } | 310 } |
| 263 | 311 |
| 264 int PermissionDecisionAutoBlocker::GetDismissCount( | 312 int PermissionDecisionAutoBlocker::GetDismissCount( |
| 265 const GURL& url, | 313 const GURL& url, |
| 266 ContentSettingsType permission) { | 314 ContentSettingsType permission) { |
| 267 return GetActionCount(url, permission, kPromptDismissCountKey, profile_); | 315 return GetActionCount(url, permission, kPromptDismissCountKey, profile_); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 283 // PermissionContextBase::ShouldEmbargoAfterRepeatedDismissals() to specify | 331 // PermissionContextBase::ShouldEmbargoAfterRepeatedDismissals() to specify |
| 284 // if a permission is opted in. This is difficult right now because: | 332 // if a permission is opted in. This is difficult right now because: |
| 285 // 1. PermissionQueueController needs to call this method at a point where it | 333 // 1. PermissionQueueController needs to call this method at a point where it |
| 286 // does not have a PermissionContextBase available | 334 // does not have a PermissionContextBase available |
| 287 // 2. Not calling RecordDismissAndEmbargo means no repeated dismissal metrics | 335 // 2. Not calling RecordDismissAndEmbargo means no repeated dismissal metrics |
| 288 // are recorded | 336 // are recorded |
| 289 // For now, only plugins are explicitly opted out. We should think about how | 337 // For now, only plugins are explicitly opted out. We should think about how |
| 290 // to make this nicer once PermissionQueueController is removed. | 338 // to make this nicer once PermissionQueueController is removed. |
| 291 if (base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften) && | 339 if (base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften) && |
| 292 permission != CONTENT_SETTINGS_TYPE_PLUGINS && | 340 permission != CONTENT_SETTINGS_TYPE_PLUGINS && |
| 293 current_dismissal_count >= g_prompt_dismissals_before_block) { | 341 current_dismissal_count >= g_dismissals_before_block) { |
| 294 PlaceUnderEmbargo(url, permission, kPermissionDismissalEmbargoKey); | 342 PlaceUnderEmbargo(url, permission, kPermissionDismissalEmbargoKey); |
| 295 return true; | 343 return true; |
| 296 } | 344 } |
| 297 return false; | 345 return false; |
| 298 } | 346 } |
| 299 | 347 |
| 300 int PermissionDecisionAutoBlocker::RecordIgnore( | 348 bool PermissionDecisionAutoBlocker::RecordIgnoreAndEmbargo( |
| 301 const GURL& url, | 349 const GURL& url, |
| 302 ContentSettingsType permission) { | 350 ContentSettingsType permission) { |
| 303 return RecordActionInWebsiteSettings(url, permission, kPromptIgnoreCountKey, | 351 int current_ignore_count = RecordActionInWebsiteSettings( |
| 304 profile_); | 352 url, permission, kPromptIgnoreCountKey, profile_); |
| 353 |
| 354 if (base::FeatureList::IsEnabled(features::kBlockPromptsIfIgnoredOften) && |
| 355 permission != CONTENT_SETTINGS_TYPE_PLUGINS && |
| 356 current_ignore_count >= g_ignores_before_block) { |
| 357 PlaceUnderEmbargo(url, permission, kPermissionIgnoreEmbargoKey); |
| 358 return true; |
| 359 } |
| 360 return false; |
| 305 } | 361 } |
| 306 | 362 |
| 307 void PermissionDecisionAutoBlocker::RemoveCountsByUrl( | 363 void PermissionDecisionAutoBlocker::RemoveCountsByUrl( |
| 308 base::Callback<bool(const GURL& url)> filter) { | 364 base::Callback<bool(const GURL& url)> filter) { |
| 309 HostContentSettingsMap* map = | 365 HostContentSettingsMap* map = |
| 310 HostContentSettingsMapFactory::GetForProfile(profile_); | 366 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 311 | 367 |
| 312 std::unique_ptr<ContentSettingsForOneType> settings( | 368 std::unique_ptr<ContentSettingsForOneType> settings( |
| 313 new ContentSettingsForOneType); | 369 new ContentSettingsForOneType); |
| 314 map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA, | 370 map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA, |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, | 429 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager, |
| 374 int timeout) { | 430 int timeout) { |
| 375 db_manager_ = db_manager; | 431 db_manager_ = db_manager; |
| 376 safe_browsing_timeout_ = timeout; | 432 safe_browsing_timeout_ = timeout; |
| 377 } | 433 } |
| 378 | 434 |
| 379 void PermissionDecisionAutoBlocker::SetClockForTesting( | 435 void PermissionDecisionAutoBlocker::SetClockForTesting( |
| 380 std::unique_ptr<base::Clock> clock) { | 436 std::unique_ptr<base::Clock> clock) { |
| 381 clock_ = std::move(clock); | 437 clock_ = std::move(clock); |
| 382 } | 438 } |
| OLD | NEW |