Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
|
lpz
2017/06/08 15:18:33
meta comment: this might be just my ignorance, but
Jialiu Lin
2017/06/08 20:47:30
Yes, UMFAMILIAR_LOGIN_PAGE(a.k.a password on focus
| |
| 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 "components/safe_browsing/password_protection/password_protection_servi ce.h" | 5 #include "components/safe_browsing/password_protection/password_protection_servi ce.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| 11 #include "base/metrics/field_trial.h" | 11 #include "base/metrics/field_trial.h" |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 31 namespace safe_browsing { | 31 namespace safe_browsing { |
| 32 | 32 |
| 33 namespace { | 33 namespace { |
| 34 | 34 |
| 35 // Keys for storing password protection verdict into a DictionaryValue. | 35 // Keys for storing password protection verdict into a DictionaryValue. |
| 36 const char kCacheCreationTime[] = "cache_creation_time"; | 36 const char kCacheCreationTime[] = "cache_creation_time"; |
| 37 const char kVerdictProto[] = "verdict_proto"; | 37 const char kVerdictProto[] = "verdict_proto"; |
| 38 const int kRequestTimeoutMs = 10000; | 38 const int kRequestTimeoutMs = 10000; |
| 39 const char kPasswordProtectionRequestUrl[] = | 39 const char kPasswordProtectionRequestUrl[] = |
| 40 "https://sb-ssl.google.com/safebrowsing/clientreport/login"; | 40 "https://sb-ssl.google.com/safebrowsing/clientreport/login"; |
| 41 const char kPasswordOnFocusCacheKey[] = "password_on_focus_cache_key"; | |
| 41 | 42 |
| 42 // Helper function to determine if the given origin matches content settings | 43 // Helper function to determine if the given origin matches content settings |
| 43 // map's patterns. | 44 // map's patterns. |
| 44 bool OriginMatchPrimaryPattern( | 45 bool OriginMatchPrimaryPattern( |
| 45 const GURL& origin, | 46 const GURL& origin, |
| 46 const ContentSettingsPattern& primary_pattern, | 47 const ContentSettingsPattern& primary_pattern, |
| 47 const ContentSettingsPattern& secondary_pattern_unused) { | 48 const ContentSettingsPattern& secondary_pattern_unused) { |
| 48 return ContentSettingsPattern::FromURLNoWildcard(origin) == primary_pattern; | 49 return ContentSettingsPattern::FromURLNoWildcard(origin) == primary_pattern; |
| 49 } | 50 } |
| 50 | 51 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 80 const char kPasswordOnFocusRequestOutcomeHistogramName[] = | 81 const char kPasswordOnFocusRequestOutcomeHistogramName[] = |
| 81 "PasswordProtection.RequestOutcome.PasswordFieldOnFocus"; | 82 "PasswordProtection.RequestOutcome.PasswordFieldOnFocus"; |
| 82 const char kPasswordEntryRequestOutcomeHistogramName[] = | 83 const char kPasswordEntryRequestOutcomeHistogramName[] = |
| 83 "PasswordProtection.RequestOutcome.ProtectedPasswordEntry"; | 84 "PasswordProtection.RequestOutcome.ProtectedPasswordEntry"; |
| 84 | 85 |
| 85 PasswordProtectionService::PasswordProtectionService( | 86 PasswordProtectionService::PasswordProtectionService( |
| 86 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, | 87 const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, |
| 87 scoped_refptr<net::URLRequestContextGetter> request_context_getter, | 88 scoped_refptr<net::URLRequestContextGetter> request_context_getter, |
| 88 HistoryService* history_service, | 89 HistoryService* history_service, |
| 89 HostContentSettingsMap* host_content_settings_map) | 90 HostContentSettingsMap* host_content_settings_map) |
| 90 : stored_verdict_count_(-1), | 91 : stored_verdict_count_password_on_focus_(-1), |
| 92 stored_verdict_count_password_entry_(-1), | |
| 91 database_manager_(database_manager), | 93 database_manager_(database_manager), |
| 92 request_context_getter_(request_context_getter), | 94 request_context_getter_(request_context_getter), |
| 93 history_service_observer_(this), | 95 history_service_observer_(this), |
| 94 content_settings_(host_content_settings_map), | 96 content_settings_(host_content_settings_map), |
| 95 weak_factory_(this) { | 97 weak_factory_(this) { |
| 96 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 98 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 97 if (history_service) | 99 if (history_service) |
| 98 history_service_observer_.Add(history_service); | 100 history_service_observer_.Add(history_service); |
| 99 } | 101 } |
| 100 | 102 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 118 return false; | 120 return false; |
| 119 | 121 |
| 120 const std::string& hostname = url.HostNoBrackets(); | 122 const std::string& hostname = url.HostNoBrackets(); |
| 121 return !net::IsLocalhost(hostname) && !net::IsHostnameNonUnique(hostname) && | 123 return !net::IsLocalhost(hostname) && !net::IsHostnameNonUnique(hostname) && |
| 122 hostname.find('.') != std::string::npos; | 124 hostname.find('.') != std::string::npos; |
| 123 } | 125 } |
| 124 | 126 |
| 125 LoginReputationClientResponse::VerdictType | 127 LoginReputationClientResponse::VerdictType |
| 126 PasswordProtectionService::GetCachedVerdict( | 128 PasswordProtectionService::GetCachedVerdict( |
| 127 const GURL& url, | 129 const GURL& url, |
| 130 TriggerType type, | |
| 128 LoginReputationClientResponse* out_response) { | 131 LoginReputationClientResponse* out_response) { |
| 132 DCHECK(content_settings_); | |
| 133 DCHECK(type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || | |
| 134 type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); | |
| 135 | |
| 129 if (!url.is_valid()) | 136 if (!url.is_valid()) |
| 130 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; | 137 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; |
| 131 | 138 |
| 132 DCHECK(content_settings_); | |
| 133 | |
| 134 GURL hostname = GetHostNameWithHTTPScheme(url); | 139 GURL hostname = GetHostNameWithHTTPScheme(url); |
| 135 std::unique_ptr<base::DictionaryValue> verdict_dictionary = | 140 std::unique_ptr<base::DictionaryValue> cache_dictionary = |
| 136 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( | 141 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( |
| 137 hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, | 142 hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, |
| 138 std::string(), nullptr)); | 143 std::string(), nullptr)); |
| 139 // Return early if there is no verdict cached for this origin. | 144 |
| 140 if (!verdict_dictionary.get() || verdict_dictionary->empty()) | 145 if (!cache_dictionary.get() || cache_dictionary->empty()) |
| 141 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; | 146 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; |
| 142 | 147 |
| 148 base::DictionaryValue* verdict_dictionary = nullptr; | |
| 149 if (type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { | |
| 150 // All UNFAMILIAR_LOGIN_PAGE verdicts (a.k.a password on focus ping) | |
| 151 // are cached under |kPasswordOnFocusCacheKey|. | |
| 152 if (!cache_dictionary->HasKey(kPasswordOnFocusCacheKey)) { | |
| 153 return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; | |
| 154 } | |
| 155 DCHECK(cache_dictionary->GetDictionaryWithoutPathExpansion( | |
| 156 kPasswordOnFocusCacheKey, &verdict_dictionary)); | |
| 157 } else { | |
| 158 verdict_dictionary = cache_dictionary.get(); | |
| 159 } | |
| 160 | |
| 143 std::vector<std::string> paths; | 161 std::vector<std::string> paths; |
| 144 GeneratePathVariantsWithoutQuery(url, &paths); | 162 GeneratePathVariantsWithoutQuery(url, &paths); |
| 145 int max_path_depth = -1; | 163 int max_path_depth = -1; |
| 146 LoginReputationClientResponse::VerdictType most_matching_verdict = | 164 LoginReputationClientResponse::VerdictType most_matching_verdict = |
| 147 LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; | 165 LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; |
| 148 // For all the verdicts of the same origin, we key them by |cache_expression|. | 166 // For all the verdicts of the same origin, we key them by |cache_expression|. |
| 149 // Its corresponding value is a DictionaryValue contains its creation time and | 167 // Its corresponding value is a DictionaryValue contains its creation time and |
| 150 // the serialized verdict proto. | 168 // the serialized verdict proto. |
| 151 for (base::DictionaryValue::Iterator it(*verdict_dictionary.get()); | 169 for (base::DictionaryValue::Iterator it(*verdict_dictionary); !it.IsAtEnd(); |
| 152 !it.IsAtEnd(); it.Advance()) { | 170 it.Advance()) { |
| 171 if (type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT && | |
| 172 it.key() == kPasswordOnFocusCacheKey) { | |
| 173 continue; | |
| 174 } | |
| 153 base::DictionaryValue* verdict_entry = nullptr; | 175 base::DictionaryValue* verdict_entry = nullptr; |
| 154 CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion( | 176 CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion( |
| 155 it.key() /* cache_expression */, &verdict_entry)); | 177 it.key() /* cache_expression */, &verdict_entry)); |
| 156 int verdict_received_time; | 178 int verdict_received_time; |
| 157 LoginReputationClientResponse verdict; | 179 LoginReputationClientResponse verdict; |
| 158 CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict)); | 180 CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict)); |
| 159 // Since password protection content settings are keyed by origin, we only | 181 // Since password protection content settings are keyed by origin, we only |
| 160 // need to compare the path part of the cache_expression and the given url. | 182 // need to compare the path part of the cache_expression and the given url. |
| 161 std::string cache_expression_path = | 183 std::string cache_expression_path = |
| 162 GetCacheExpressionPath(verdict.cache_expression()); | 184 GetCacheExpressionPath(verdict.cache_expression()); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 173 ? LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED | 195 ? LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED |
| 174 : verdict.verdict_type(); | 196 : verdict.verdict_type(); |
| 175 out_response->CopyFrom(verdict); | 197 out_response->CopyFrom(verdict); |
| 176 } | 198 } |
| 177 } | 199 } |
| 178 return most_matching_verdict; | 200 return most_matching_verdict; |
| 179 } | 201 } |
| 180 | 202 |
| 181 void PasswordProtectionService::CacheVerdict( | 203 void PasswordProtectionService::CacheVerdict( |
| 182 const GURL& url, | 204 const GURL& url, |
| 205 TriggerType type, | |
| 183 LoginReputationClientResponse* verdict, | 206 LoginReputationClientResponse* verdict, |
| 184 const base::Time& receive_time) { | 207 const base::Time& receive_time) { |
| 185 DCHECK(verdict); | 208 DCHECK(verdict); |
| 186 DCHECK(content_settings_); | 209 DCHECK(content_settings_); |
| 210 DCHECK(type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || | |
| 211 type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); | |
| 187 | 212 |
| 188 GURL hostname = GetHostNameWithHTTPScheme(url); | 213 GURL hostname = GetHostNameWithHTTPScheme(url); |
| 189 std::unique_ptr<base::DictionaryValue> verdict_dictionary = | 214 int* stored_verdict_count = |
| 215 type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE | |
| 216 ? &stored_verdict_count_password_on_focus_ | |
| 217 : &stored_verdict_count_password_entry_; | |
| 218 std::unique_ptr<base::DictionaryValue> cache_dictionary = | |
| 190 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( | 219 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( |
| 191 hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, | 220 hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, |
| 192 std::string(), nullptr)); | 221 std::string(), nullptr)); |
| 193 | 222 |
| 194 if (!verdict_dictionary.get()) | 223 if (!cache_dictionary.get()) |
| 195 verdict_dictionary = base::MakeUnique<base::DictionaryValue>(); | 224 cache_dictionary = base::MakeUnique<base::DictionaryValue>(); |
| 196 | 225 |
| 197 std::unique_ptr<base::DictionaryValue> verdict_entry = | 226 std::unique_ptr<base::DictionaryValue> verdict_entry = |
| 198 CreateDictionaryFromVerdict(verdict, receive_time); | 227 CreateDictionaryFromVerdict(verdict, receive_time); |
| 199 | 228 |
| 229 base::DictionaryValue* verdict_dictionary = nullptr; | |
| 230 if (type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { | |
| 231 // All UNFAMILIAR_LOGIN_PAGE verdicts (a.k.a password on focus ping) | |
| 232 // are cached under |kPasswordOnFocusCacheKey|. | |
| 233 if (!cache_dictionary->HasKey(kPasswordOnFocusCacheKey)) { | |
| 234 cache_dictionary->SetDictionaryWithoutPathExpansion( | |
| 235 kPasswordOnFocusCacheKey, base::MakeUnique<base::DictionaryValue>()); | |
| 236 } | |
| 237 DCHECK(cache_dictionary->GetDictionaryWithoutPathExpansion( | |
| 238 kPasswordOnFocusCacheKey, &verdict_dictionary)); | |
| 239 } else { | |
| 240 verdict_dictionary = cache_dictionary.get(); | |
| 241 } | |
| 242 | |
| 200 // Increases stored verdict count if we haven't seen this cache expression | 243 // Increases stored verdict count if we haven't seen this cache expression |
| 201 // before. | 244 // before. |
| 202 if (!verdict_dictionary->HasKey(verdict->cache_expression())) | 245 if (!verdict_dictionary->HasKey(verdict->cache_expression())) |
| 203 stored_verdict_count_ = GetStoredVerdictCount() + 1; | 246 *stored_verdict_count = GetStoredVerdictCount(type) + 1; |
| 204 // If same cache_expression is already in this verdict_dictionary, we simply | 247 // If same cache_expression is already in this verdict_dictionary, we simply |
| 205 // override it. | 248 // override it. |
| 206 verdict_dictionary->SetWithoutPathExpansion(verdict->cache_expression(), | 249 verdict_dictionary->SetWithoutPathExpansion(verdict->cache_expression(), |
| 207 std::move(verdict_entry)); | 250 std::move(verdict_entry)); |
| 208 content_settings_->SetWebsiteSettingDefaultScope( | 251 content_settings_->SetWebsiteSettingDefaultScope( |
| 209 hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, | 252 hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, |
| 210 std::string(), std::move(verdict_dictionary)); | 253 std::string(), std::move(cache_dictionary)); |
| 211 } | 254 } |
| 212 | 255 |
| 213 void PasswordProtectionService::CleanUpExpiredVerdicts() { | 256 void PasswordProtectionService::CleanUpExpiredVerdicts() { |
| 214 DCHECK(content_settings_); | 257 DCHECK(content_settings_); |
| 215 if (GetStoredVerdictCount() <= 0) | 258 |
| 259 if (GetStoredVerdictCount( | |
| 260 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) <= 0 && | |
| 261 GetStoredVerdictCount( | |
| 262 LoginReputationClientRequest::PASSWORD_REUSE_EVENT) <= 0) | |
| 216 return; | 263 return; |
| 217 | 264 |
| 218 ContentSettingsForOneType password_protection_settings; | 265 ContentSettingsForOneType password_protection_settings; |
| 219 content_settings_->GetSettingsForOneType( | 266 content_settings_->GetSettingsForOneType( |
| 220 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | 267 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), |
| 221 &password_protection_settings); | 268 &password_protection_settings); |
| 222 | 269 |
| 223 for (const ContentSettingPatternSource& source : | 270 for (const ContentSettingPatternSource& source : |
| 224 password_protection_settings) { | 271 password_protection_settings) { |
| 225 GURL primary_pattern_url = GURL(source.primary_pattern.ToString()); | 272 GURL primary_pattern_url = GURL(source.primary_pattern.ToString()); |
| 226 // Find all verdicts associated with this origin. | 273 // Find all verdicts associated with this origin. |
| 227 std::unique_ptr<base::DictionaryValue> verdict_dictionary = | 274 std::unique_ptr<base::DictionaryValue> cache_dictionary = |
| 228 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( | 275 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( |
| 229 primary_pattern_url, GURL(), | 276 primary_pattern_url, GURL(), |
| 230 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); | 277 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); |
| 231 std::vector<std::string> expired_keys; | 278 bool has_expired_password_on_focus_entry = RemoveExpiredVerdicts( |
| 232 for (base::DictionaryValue::Iterator it(*verdict_dictionary.get()); | 279 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, |
| 233 !it.IsAtEnd(); it.Advance()) { | 280 cache_dictionary.get()); |
| 234 base::DictionaryValue* verdict_entry = nullptr; | 281 bool has_expired_password_reuse_entry = RemoveExpiredVerdicts( |
| 235 CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion( | 282 LoginReputationClientRequest::PASSWORD_REUSE_EVENT, |
| 236 it.key(), &verdict_entry)); | 283 cache_dictionary.get()); |
| 237 int verdict_received_time; | |
| 238 LoginReputationClientResponse verdict; | |
| 239 CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict)); | |
| 240 | 284 |
| 241 if (IsCacheExpired(verdict_received_time, verdict.cache_duration_sec())) { | 285 if (cache_dictionary->size() == 0u) { |
| 242 // Since DictionaryValue::Iterator cannot be used to modify the | |
| 243 // dictionary, we record the keys of expired verdicts in |expired_keys| | |
| 244 // and remove them in the next for-loop. | |
| 245 expired_keys.push_back(it.key()); | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 for (const std::string& key : expired_keys) { | |
| 250 verdict_dictionary->RemoveWithoutPathExpansion(key, nullptr); | |
| 251 stored_verdict_count_--; | |
| 252 } | |
| 253 | |
| 254 if (verdict_dictionary->size() == 0u) { | |
| 255 content_settings_->ClearSettingsForOneTypeWithPredicate( | 286 content_settings_->ClearSettingsForOneTypeWithPredicate( |
| 256 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, base::Time(), | 287 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, base::Time(), |
| 257 base::Bind(&OriginMatchPrimaryPattern, primary_pattern_url)); | 288 base::Bind(&OriginMatchPrimaryPattern, primary_pattern_url)); |
| 258 } else if (expired_keys.size() > 0u) { | 289 } else if (has_expired_password_on_focus_entry || |
| 290 has_expired_password_reuse_entry) { | |
| 259 // Set the website setting of this origin with the updated | 291 // Set the website setting of this origin with the updated |
| 260 // |verdict_diectionary|. | 292 // |verdict_diectionary|. |
| 261 content_settings_->SetWebsiteSettingDefaultScope( | 293 content_settings_->SetWebsiteSettingDefaultScope( |
| 262 primary_pattern_url, GURL(), | 294 primary_pattern_url, GURL(), |
| 263 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | 295 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), |
| 264 std::move(verdict_dictionary)); | 296 std::move(cache_dictionary)); |
| 265 } | 297 } |
| 266 } | 298 } |
| 267 } | 299 } |
| 268 | 300 |
| 269 void PasswordProtectionService::StartRequest( | 301 void PasswordProtectionService::StartRequest( |
| 270 WebContents* web_contents, | 302 WebContents* web_contents, |
| 271 const GURL& main_frame_url, | 303 const GURL& main_frame_url, |
| 272 const GURL& password_form_action, | 304 const GURL& password_form_action, |
| 273 const GURL& password_form_frame_url, | 305 const GURL& password_form_frame_url, |
| 274 const std::string& saved_domain, | 306 const std::string& saved_domain, |
| 275 LoginReputationClientRequest::TriggerType type) { | 307 TriggerType type) { |
| 276 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 308 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 277 scoped_refptr<PasswordProtectionRequest> request( | 309 scoped_refptr<PasswordProtectionRequest> request( |
| 278 new PasswordProtectionRequest(web_contents, main_frame_url, | 310 new PasswordProtectionRequest(web_contents, main_frame_url, |
| 279 password_form_action, | 311 password_form_action, |
| 280 password_form_frame_url, saved_domain, type, | 312 password_form_frame_url, saved_domain, type, |
| 281 this, GetRequestTimeoutInMS())); | 313 this, GetRequestTimeoutInMS())); |
| 282 DCHECK(request); | 314 DCHECK(request); |
| 283 request->Start(); | 315 request->Start(); |
| 284 requests_.insert(std::move(request)); | 316 requests_.insert(std::move(request)); |
| 285 } | 317 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 322 | 354 |
| 323 void PasswordProtectionService::RequestFinished( | 355 void PasswordProtectionService::RequestFinished( |
| 324 PasswordProtectionRequest* request, | 356 PasswordProtectionRequest* request, |
| 325 bool already_cached, | 357 bool already_cached, |
| 326 std::unique_ptr<LoginReputationClientResponse> response) { | 358 std::unique_ptr<LoginReputationClientResponse> response) { |
| 327 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 359 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 328 DCHECK(request); | 360 DCHECK(request); |
| 329 | 361 |
| 330 if (response) { | 362 if (response) { |
| 331 if (!already_cached) { | 363 if (!already_cached) { |
| 332 CacheVerdict(request->main_frame_url(), response.get(), | 364 CacheVerdict(request->main_frame_url(), request->request_type(), |
| 333 base::Time::Now()); | 365 response.get(), base::Time::Now()); |
| 334 } | 366 } |
| 335 | 367 |
| 336 if (request->request_type() == | 368 if (request->request_type() == |
| 337 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE && | 369 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE && |
| 338 response->verdict_type() == LoginReputationClientResponse::PHISHING && | 370 response->verdict_type() == LoginReputationClientResponse::PHISHING && |
| 339 base::FeatureList::IsEnabled(kPasswordProtectionInterstitial)) { | 371 base::FeatureList::IsEnabled(kPasswordProtectionInterstitial)) { |
| 340 ShowPhishingInterstitial(request->main_frame_url(), | 372 ShowPhishingInterstitial(request->main_frame_url(), |
| 341 response->verdict_token(), | 373 response->verdict_token(), |
| 342 request->web_contents()); | 374 request->web_contents()); |
| 343 } | 375 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 369 return database_manager_; | 401 return database_manager_; |
| 370 } | 402 } |
| 371 | 403 |
| 372 GURL PasswordProtectionService::GetPasswordProtectionRequestUrl() { | 404 GURL PasswordProtectionService::GetPasswordProtectionRequestUrl() { |
| 373 GURL url(kPasswordProtectionRequestUrl); | 405 GURL url(kPasswordProtectionRequestUrl); |
| 374 std::string api_key = google_apis::GetAPIKey(); | 406 std::string api_key = google_apis::GetAPIKey(); |
| 375 DCHECK(!api_key.empty()); | 407 DCHECK(!api_key.empty()); |
| 376 return url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true)); | 408 return url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true)); |
| 377 } | 409 } |
| 378 | 410 |
| 379 int PasswordProtectionService::GetStoredVerdictCount() { | 411 int PasswordProtectionService::GetStoredVerdictCount(TriggerType type) { |
| 380 DCHECK(content_settings_); | 412 DCHECK(content_settings_); |
| 413 DCHECK(type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || | |
| 414 type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); | |
| 415 int* stored_verdict_count = | |
| 416 type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE | |
| 417 ? &stored_verdict_count_password_on_focus_ | |
| 418 : &stored_verdict_count_password_entry_; | |
| 381 // If we have already computed this, return its value. | 419 // If we have already computed this, return its value. |
| 382 if (stored_verdict_count_ >= 0) | 420 if (*stored_verdict_count >= 0) |
| 383 return stored_verdict_count_; | 421 return *stored_verdict_count; |
| 384 | 422 |
| 385 ContentSettingsForOneType password_protection_settings; | 423 ContentSettingsForOneType password_protection_settings; |
| 386 content_settings_->GetSettingsForOneType( | 424 content_settings_->GetSettingsForOneType( |
| 387 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | 425 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), |
| 388 &password_protection_settings); | 426 &password_protection_settings); |
| 389 stored_verdict_count_ = 0; | 427 stored_verdict_count_password_on_focus_ = 0; |
| 428 stored_verdict_count_password_entry_ = 0; | |
| 390 if (password_protection_settings.empty()) | 429 if (password_protection_settings.empty()) |
| 391 return 0; | 430 return 0; |
| 392 | 431 |
| 393 for (const ContentSettingPatternSource& source : | 432 for (const ContentSettingPatternSource& source : |
| 394 password_protection_settings) { | 433 password_protection_settings) { |
| 395 std::unique_ptr<base::DictionaryValue> verdict_dictionary = | 434 std::unique_ptr<base::DictionaryValue> verdict_dictionary = |
|
lpz
2017/06/08 15:18:33
should this be "cache_dictionary" for consistency
Jialiu Lin
2017/06/08 20:47:30
Done.
| |
| 396 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( | 435 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( |
| 397 GURL(source.primary_pattern.ToString()), GURL(), | 436 GURL(source.primary_pattern.ToString()), GURL(), |
| 398 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); | 437 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); |
| 399 if (verdict_dictionary.get() && !verdict_dictionary->empty()) | 438 if (verdict_dictionary.get() && !verdict_dictionary->empty()) { |
|
lpz
2017/06/08 15:18:33
I think this block could use a couple comments (ie
Jialiu Lin
2017/06/08 20:47:30
The outer dict size is # of PASSWORD_REUSE_EVENT v
| |
| 400 stored_verdict_count_ += static_cast<int>(verdict_dictionary->size()); | 439 stored_verdict_count_password_entry_ += |
| 440 static_cast<int>(verdict_dictionary->size()); | |
| 441 if (verdict_dictionary->HasKey(kPasswordOnFocusCacheKey)) { | |
| 442 stored_verdict_count_password_entry_ -= 1; | |
| 443 base::DictionaryValue* password_on_focus_dict = nullptr; | |
| 444 verdict_dictionary->GetDictionaryWithoutPathExpansion( | |
| 445 kPasswordOnFocusCacheKey, &password_on_focus_dict); | |
| 446 stored_verdict_count_password_on_focus_ += | |
| 447 static_cast<int>(password_on_focus_dict->size()); | |
| 448 } | |
| 449 } | |
| 401 } | 450 } |
| 402 return stored_verdict_count_; | 451 return *stored_verdict_count; |
| 403 } | 452 } |
| 404 | 453 |
| 405 int PasswordProtectionService::GetRequestTimeoutInMS() { | 454 int PasswordProtectionService::GetRequestTimeoutInMS() { |
| 406 return kRequestTimeoutMs; | 455 return kRequestTimeoutMs; |
| 407 } | 456 } |
| 408 | 457 |
| 409 void PasswordProtectionService::FillUserPopulation( | 458 void PasswordProtectionService::FillUserPopulation( |
| 410 const LoginReputationClientRequest::TriggerType& request_type, | 459 TriggerType request_type, |
| 411 LoginReputationClientRequest* request_proto) { | 460 LoginReputationClientRequest* request_proto) { |
| 412 ChromeUserPopulation* user_population = request_proto->mutable_population(); | 461 ChromeUserPopulation* user_population = request_proto->mutable_population(); |
| 413 user_population->set_user_population( | 462 user_population->set_user_population( |
| 414 IsExtendedReporting() ? ChromeUserPopulation::EXTENDED_REPORTING | 463 IsExtendedReporting() ? ChromeUserPopulation::EXTENDED_REPORTING |
| 415 : ChromeUserPopulation::SAFE_BROWSING); | 464 : ChromeUserPopulation::SAFE_BROWSING); |
| 416 user_population->set_is_history_sync_enabled(IsHistorySyncEnabled()); | 465 user_population->set_is_history_sync_enabled(IsHistorySyncEnabled()); |
| 417 | 466 |
| 418 base::FieldTrial* low_reputation_field_trial = | 467 base::FieldTrial* low_reputation_field_trial = |
| 419 base::FeatureList::GetFieldTrial(kPasswordFieldOnFocusPinging); | 468 base::FeatureList::GetFieldTrial(kPasswordFieldOnFocusPinging); |
| 420 if (low_reputation_field_trial) { | 469 if (low_reputation_field_trial) { |
| 421 user_population->add_finch_active_groups( | 470 user_population->add_finch_active_groups( |
| 422 low_reputation_field_trial->trial_name() + "|" + | 471 low_reputation_field_trial->trial_name() + "|" + |
| 423 low_reputation_field_trial->group_name()); | 472 low_reputation_field_trial->group_name()); |
| 424 } | 473 } |
| 425 base::FieldTrial* password_entry_field_trial = | 474 base::FieldTrial* password_entry_field_trial = |
| 426 base::FeatureList::GetFieldTrial(kProtectedPasswordEntryPinging); | 475 base::FeatureList::GetFieldTrial(kProtectedPasswordEntryPinging); |
| 427 if (password_entry_field_trial) { | 476 if (password_entry_field_trial) { |
| 428 user_population->add_finch_active_groups( | 477 user_population->add_finch_active_groups( |
| 429 low_reputation_field_trial->trial_name() + "|" + | 478 low_reputation_field_trial->trial_name() + "|" + |
| 430 low_reputation_field_trial->group_name()); | 479 low_reputation_field_trial->group_name()); |
| 431 } | 480 } |
| 432 } | 481 } |
| 433 | 482 |
| 434 void PasswordProtectionService::OnURLsDeleted( | 483 void PasswordProtectionService::OnURLsDeleted( |
| 435 history::HistoryService* history_service, | 484 history::HistoryService* history_service, |
| 436 bool all_history, | 485 bool all_history, |
| 437 bool expired, | 486 bool expired, |
| 438 const history::URLRows& deleted_rows, | 487 const history::URLRows& deleted_rows, |
| 439 const std::set<GURL>& favicon_urls) { | 488 const std::set<GURL>& favicon_urls) { |
| 440 if (stored_verdict_count_ <= 0) | 489 if (stored_verdict_count_password_on_focus_ <= 0 && |
| 490 stored_verdict_count_password_entry_ <= 0) { | |
| 441 return; | 491 return; |
| 492 } | |
| 442 | 493 |
| 443 BrowserThread::PostTask( | 494 BrowserThread::PostTask( |
| 444 BrowserThread::UI, FROM_HERE, | 495 BrowserThread::UI, FROM_HERE, |
| 445 base::Bind(&PasswordProtectionService::RemoveContentSettingsOnURLsDeleted, | 496 base::Bind(&PasswordProtectionService::RemoveContentSettingsOnURLsDeleted, |
| 446 GetWeakPtr(), all_history, deleted_rows)); | 497 GetWeakPtr(), all_history, deleted_rows)); |
| 447 } | 498 } |
| 448 | 499 |
| 449 void PasswordProtectionService::HistoryServiceBeingDeleted( | 500 void PasswordProtectionService::HistoryServiceBeingDeleted( |
| 450 history::HistoryService* history_service) { | 501 history::HistoryService* history_service) { |
| 451 history_service_observer_.RemoveAll(); | 502 history_service_observer_.RemoveAll(); |
| 452 } | 503 } |
| 453 | 504 |
| 454 void PasswordProtectionService::RemoveContentSettingsOnURLsDeleted( | 505 void PasswordProtectionService::RemoveContentSettingsOnURLsDeleted( |
| 455 bool all_history, | 506 bool all_history, |
| 456 const history::URLRows& deleted_rows) { | 507 const history::URLRows& deleted_rows) { |
| 457 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 508 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 458 DCHECK(content_settings_); | 509 DCHECK(content_settings_); |
| 459 | 510 |
| 460 if (all_history) { | 511 if (all_history) { |
| 461 content_settings_->ClearSettingsForOneType( | 512 content_settings_->ClearSettingsForOneType( |
| 462 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION); | 513 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION); |
| 463 stored_verdict_count_ = 0; | 514 stored_verdict_count_password_on_focus_ = 0; |
| 515 stored_verdict_count_password_entry_ = 0; | |
| 464 return; | 516 return; |
| 465 } | 517 } |
| 466 | 518 |
| 467 // For now, if a URL is deleted from history, we simply remove all the | 519 // For now, if a URL is deleted from history, we simply remove all the |
| 468 // cached verdicts of the same origin. This is a pretty aggressive deletion. | 520 // cached verdicts of the same origin. This is a pretty aggressive deletion. |
| 469 // We might revisit this logic later to decide if we want to only delete the | 521 // We might revisit this logic later to decide if we want to only delete the |
| 470 // cached verdict whose cache expression matches this URL. | 522 // cached verdict whose cache expression matches this URL. |
| 471 for (const history::URLRow& row : deleted_rows) { | 523 for (const history::URLRow& row : deleted_rows) { |
| 472 if (!row.url().SchemeIsHTTPOrHTTPS()) | 524 if (!row.url().SchemeIsHTTPOrHTTPS()) |
| 473 continue; | 525 continue; |
| 474 GURL url_key = GetHostNameWithHTTPScheme(row.url()); | 526 GURL url_key = GetHostNameWithHTTPScheme(row.url()); |
| 475 std::unique_ptr<base::DictionaryValue> verdict_dictionary = | 527 stored_verdict_count_password_on_focus_ = |
| 476 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( | 528 GetStoredVerdictCount( |
| 477 url_key, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, | 529 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) - |
| 478 std::string(), nullptr)); | 530 GetVerdictCountForURL( |
| 479 | 531 url_key, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE); |
| 480 // Move on if we have no cached verdict for this deleted history row. | 532 stored_verdict_count_password_entry_ = |
| 481 if (!verdict_dictionary.get() || verdict_dictionary->empty()) | 533 GetStoredVerdictCount( |
| 482 continue; | 534 LoginReputationClientRequest::PASSWORD_REUSE_EVENT) - |
| 483 | 535 GetVerdictCountForURL( |
| 484 int verdict_count = static_cast<int>(verdict_dictionary->size()); | 536 url_key, LoginReputationClientRequest::PASSWORD_REUSE_EVENT); |
| 485 stored_verdict_count_ = GetStoredVerdictCount() - verdict_count; | |
| 486 content_settings_->ClearSettingsForOneTypeWithPredicate( | 537 content_settings_->ClearSettingsForOneTypeWithPredicate( |
| 487 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, base::Time(), | 538 CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, base::Time(), |
| 488 base::Bind(&OriginMatchPrimaryPattern, url_key)); | 539 base::Bind(&OriginMatchPrimaryPattern, url_key)); |
| 489 } | 540 } |
| 490 } | 541 } |
| 491 | 542 |
| 543 int PasswordProtectionService::GetVerdictCountForURL(const GURL& url, | |
| 544 TriggerType type) { | |
| 545 DCHECK(type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || | |
| 546 type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); | |
| 547 std::unique_ptr<base::DictionaryValue> verdict_dictionary = | |
| 548 base::DictionaryValue::From(content_settings_->GetWebsiteSetting( | |
| 549 url, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), | |
| 550 nullptr)); | |
| 551 if (!verdict_dictionary.get() || verdict_dictionary->empty()) | |
| 552 return 0; | |
| 553 | |
| 554 if (type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { | |
| 555 base::DictionaryValue* password_on_focus_dict = nullptr; | |
| 556 verdict_dictionary->GetDictionaryWithoutPathExpansion( | |
| 557 kPasswordOnFocusCacheKey, &password_on_focus_dict); | |
| 558 return password_on_focus_dict ? password_on_focus_dict->size() : 0; | |
| 559 } else { | |
| 560 return verdict_dictionary->HasKey(kPasswordOnFocusCacheKey) | |
| 561 ? verdict_dictionary->size() - 1 | |
| 562 : verdict_dictionary->size(); | |
| 563 } | |
| 564 } | |
| 565 | |
| 566 bool PasswordProtectionService::RemoveExpiredVerdicts( | |
| 567 TriggerType type, | |
| 568 base::DictionaryValue* cache_dict) { | |
| 569 DCHECK(type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || | |
| 570 type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); | |
| 571 base::DictionaryValue* verdict_dictionary = nullptr; | |
| 572 if (type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT) { | |
| 573 verdict_dictionary = cache_dict; | |
| 574 } else { | |
| 575 if (!cache_dict->GetDictionaryWithoutPathExpansion(kPasswordOnFocusCacheKey, | |
| 576 &verdict_dictionary)) { | |
| 577 return false; | |
| 578 } | |
| 579 } | |
| 580 | |
| 581 if (!verdict_dictionary || verdict_dictionary->empty()) | |
| 582 return false; | |
|
lpz
2017/06/08 15:18:33
nit: +1 newline after
Jialiu Lin
2017/06/08 20:47:30
Done.
| |
| 583 std::vector<std::string> expired_keys; | |
| 584 for (base::DictionaryValue::Iterator it(*verdict_dictionary); !it.IsAtEnd(); | |
| 585 it.Advance()) { | |
| 586 if (type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT && | |
| 587 it.key() == std::string(kPasswordOnFocusCacheKey)) | |
| 588 continue; | |
|
lpz
2017/06/08 15:18:33
nit: +1 newline after
Jialiu Lin
2017/06/08 20:47:30
Done.
| |
| 589 base::DictionaryValue* verdict_entry = nullptr; | |
| 590 CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion( | |
| 591 it.key(), &verdict_entry)); | |
| 592 int verdict_received_time; | |
| 593 LoginReputationClientResponse verdict; | |
| 594 CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict)); | |
| 595 | |
| 596 if (IsCacheExpired(verdict_received_time, verdict.cache_duration_sec())) { | |
| 597 // Since DictionaryValue::Iterator cannot be used to modify the | |
| 598 // dictionary, we record the keys of expired verdicts in |expired_keys| | |
| 599 // and remove them in the next for-loop. | |
| 600 expired_keys.push_back(it.key()); | |
| 601 } | |
| 602 } | |
| 603 | |
| 604 for (const std::string& key : expired_keys) { | |
| 605 verdict_dictionary->RemoveWithoutPathExpansion(key, nullptr); | |
| 606 if (type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT) | |
| 607 stored_verdict_count_password_entry_--; | |
| 608 else | |
| 609 stored_verdict_count_password_on_focus_--; | |
| 610 } | |
| 611 | |
| 612 if (type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE && | |
| 613 verdict_dictionary->size() == 0U) { | |
| 614 cache_dict->RemoveWithoutPathExpansion(kPasswordOnFocusCacheKey, nullptr); | |
| 615 } | |
| 616 | |
| 617 return expired_keys.size() > 0U; | |
| 618 } | |
| 619 | |
| 492 // static | 620 // static |
| 493 bool PasswordProtectionService::ParseVerdictEntry( | 621 bool PasswordProtectionService::ParseVerdictEntry( |
| 494 base::DictionaryValue* verdict_entry, | 622 base::DictionaryValue* verdict_entry, |
| 495 int* out_verdict_received_time, | 623 int* out_verdict_received_time, |
| 496 LoginReputationClientResponse* out_verdict) { | 624 LoginReputationClientResponse* out_verdict) { |
| 497 std::string serialized_verdict_proto; | 625 std::string serialized_verdict_proto; |
| 498 return verdict_entry && out_verdict && | 626 return verdict_entry && out_verdict && |
| 499 verdict_entry->GetInteger(kCacheCreationTime, | 627 verdict_entry->GetInteger(kCacheCreationTime, |
| 500 out_verdict_received_time) && | 628 out_verdict_received_time) && |
| 501 verdict_entry->GetString(kVerdictProto, &serialized_verdict_proto) && | 629 verdict_entry->GetString(kVerdictProto, &serialized_verdict_proto) && |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 582 if (is_password_entry_ping) { | 710 if (is_password_entry_ping) { |
| 583 UMA_HISTOGRAM_ENUMERATION(kPasswordEntryRequestOutcomeHistogramName, reason, | 711 UMA_HISTOGRAM_ENUMERATION(kPasswordEntryRequestOutcomeHistogramName, reason, |
| 584 MAX_OUTCOME); | 712 MAX_OUTCOME); |
| 585 } else { | 713 } else { |
| 586 UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogramName, | 714 UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogramName, |
| 587 reason, MAX_OUTCOME); | 715 reason, MAX_OUTCOME); |
| 588 } | 716 } |
| 589 } | 717 } |
| 590 | 718 |
| 591 } // namespace safe_browsing | 719 } // namespace safe_browsing |
| OLD | NEW |