Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/password_manager/password_form_manager.h" | 5 #include "chrome/browser/password_manager/password_form_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 | 182 |
| 183 // Make sure the important fields stay the same as the initially observed or | 183 // Make sure the important fields stay the same as the initially observed or |
| 184 // autofilled ones, as they may have changed if the user experienced a login | 184 // autofilled ones, as they may have changed if the user experienced a login |
| 185 // failure. | 185 // failure. |
| 186 // Look for these credentials in the list containing auto-fill entries. | 186 // Look for these credentials in the list containing auto-fill entries. |
| 187 PasswordFormMap::const_iterator it = | 187 PasswordFormMap::const_iterator it = |
| 188 best_matches_.find(credentials.username_value); | 188 best_matches_.find(credentials.username_value); |
| 189 if (it != best_matches_.end()) { | 189 if (it != best_matches_.end()) { |
| 190 // The user signed in with a login we autofilled. | 190 // The user signed in with a login we autofilled. |
| 191 pending_credentials_ = *it->second; | 191 pending_credentials_ = *it->second; |
| 192 is_new_login_ = false; | 192 |
| 193 // PSL origin matches should always be new logins, since we want to store | |
| 194 // them so they can automatically be filled in later. | |
| 195 is_new_login_ = pending_credentials_.is_psl_origin_match; | |
| 193 | 196 |
| 194 // Check to see if we're using a known username but a new password. | 197 // Check to see if we're using a known username but a new password. |
| 195 if (pending_credentials_.password_value != credentials.password_value) | 198 if (pending_credentials_.password_value != credentials.password_value) |
| 196 user_action_ = kUserActionOverride; | 199 user_action_ = kUserActionOverride; |
| 197 } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES && | 200 } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES && |
| 198 UpdatePendingCredentialsIfOtherPossibleUsername( | 201 UpdatePendingCredentialsIfOtherPossibleUsername( |
| 199 credentials.username_value)) { | 202 credentials.username_value)) { |
| 200 // |pending_credentials_| is now set. Note we don't update | 203 // |pending_credentials_| is now set. Note we don't update |
| 201 // |pending_credentials_.username_value| to |credentials.username_value| | 204 // |pending_credentials_.username_value| to |credentials.username_value| |
| 202 // yet because we need to keep the original username to modify the stored | 205 // yet because we need to keep the original username to modify the stored |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 219 if (pending_credentials_.action.is_empty()) | 222 if (pending_credentials_.action.is_empty()) |
| 220 pending_credentials_.action = observed_form_.action; | 223 pending_credentials_.action = observed_form_.action; |
| 221 | 224 |
| 222 pending_credentials_.password_value = credentials.password_value; | 225 pending_credentials_.password_value = credentials.password_value; |
| 223 pending_credentials_.preferred = credentials.preferred; | 226 pending_credentials_.preferred = credentials.preferred; |
| 224 | 227 |
| 225 if (has_generated_password_) | 228 if (has_generated_password_) |
| 226 pending_credentials_.type = PasswordForm::TYPE_GENERATED; | 229 pending_credentials_.type = PasswordForm::TYPE_GENERATED; |
| 227 } | 230 } |
| 228 | 231 |
| 232 bool PasswordFormManager::IsPSLOriginMatched() { | |
| 233 return pending_credentials_.is_psl_origin_match; | |
| 234 } | |
| 235 | |
| 229 void PasswordFormManager::Save() { | 236 void PasswordFormManager::Save() { |
| 230 DCHECK_EQ(state_, POST_MATCHING_PHASE); | 237 DCHECK_EQ(state_, POST_MATCHING_PHASE); |
| 231 DCHECK(!profile_->IsOffTheRecord()); | 238 DCHECK(!profile_->IsOffTheRecord()); |
| 232 | 239 |
| 233 if (IsNewLogin()) | 240 if (IsNewLogin()) |
| 234 SaveAsNewLogin(true); | 241 SaveAsNewLogin(true); |
| 235 else | 242 else |
| 236 UpdateLogin(); | 243 UpdateLogin(); |
| 237 } | 244 } |
| 238 | 245 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 331 if (preferred_match_->blacklisted_by_user) { | 338 if (preferred_match_->blacklisted_by_user) { |
| 332 manager_action_ = kManagerActionBlacklisted; | 339 manager_action_ = kManagerActionBlacklisted; |
| 333 return; | 340 return; |
| 334 } | 341 } |
| 335 | 342 |
| 336 // If not blacklisted, send a message to allow password generation. | 343 // If not blacklisted, send a message to allow password generation. |
| 337 SendNotBlacklistedToRenderer(); | 344 SendNotBlacklistedToRenderer(); |
| 338 | 345 |
| 339 // Proceed to autofill. | 346 // Proceed to autofill. |
| 340 // Note that we provide the choices but don't actually prefill a value if | 347 // Note that we provide the choices but don't actually prefill a value if |
| 341 // either: (1) we are in Incognito mode, or (2) the ACTION paths don't match. | 348 // either: (1) we are in Incognito mode, or (2) the ACTION paths don't match. |
|
nilesh
2013/06/04 23:02:36
update the comment.
nyquist
2013/06/05 00:08:51
Done.
| |
| 342 bool wait_for_username = | 349 bool wait_for_username = |
| 343 profile_->IsOffTheRecord() || | 350 profile_->IsOffTheRecord() || |
| 344 observed_form_.action.GetWithEmptyPath() != | 351 observed_form_.action.GetWithEmptyPath() != |
| 345 preferred_match_->action.GetWithEmptyPath(); | 352 preferred_match_->action.GetWithEmptyPath() || |
| 353 preferred_match_->is_psl_origin_match; | |
| 346 if (wait_for_username) | 354 if (wait_for_username) |
| 347 manager_action_ = kManagerActionNone; | 355 manager_action_ = kManagerActionNone; |
| 348 else | 356 else |
| 349 manager_action_ = kManagerActionAutofilled; | 357 manager_action_ = kManagerActionAutofilled; |
| 350 password_manager_->Autofill(observed_form_, best_matches_, | 358 password_manager_->Autofill(observed_form_, best_matches_, |
| 351 *preferred_match_, wait_for_username); | 359 *preferred_match_, wait_for_username); |
| 352 } | 360 } |
| 353 | 361 |
| 354 void PasswordFormManager::OnPasswordStoreRequestDone( | 362 void PasswordFormManager::OnPasswordStoreRequestDone( |
| 355 CancelableRequestProvider::Handle handle, | 363 CancelableRequestProvider::Handle handle, |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 373 OnRequestDone(results); | 381 OnRequestDone(results); |
| 374 } | 382 } |
| 375 | 383 |
| 376 bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const { | 384 bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const { |
| 377 // Ignore change password forms until we have some change password | 385 // Ignore change password forms until we have some change password |
| 378 // functionality | 386 // functionality |
| 379 if (observed_form_.old_password_element.length() != 0) { | 387 if (observed_form_.old_password_element.length() != 0) { |
| 380 return true; | 388 return true; |
| 381 } | 389 } |
| 382 // Don't match an invalid SSL form with one saved under secure | 390 // Don't match an invalid SSL form with one saved under secure |
| 383 // circumstances. | 391 // circumstances unless it was found as a PSL origin domain match. |
| 384 if (form.ssl_valid && !observed_form_.ssl_valid) { | 392 if (form.ssl_valid && |
| 393 !observed_form_.ssl_valid && | |
| 394 !form.is_psl_origin_match) { | |
| 385 return true; | 395 return true; |
| 386 } | 396 } |
| 387 return false; | 397 return false; |
| 388 } | 398 } |
| 389 | 399 |
| 390 void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) { | 400 void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) { |
| 391 DCHECK_EQ(state_, POST_MATCHING_PHASE); | 401 DCHECK_EQ(state_, POST_MATCHING_PHASE); |
| 392 DCHECK(IsNewLogin()); | 402 DCHECK(IsNewLogin()); |
| 393 // The new_form is being used to sign in, so it is preferred. | 403 // The new_form is being used to sign in, so it is preferred. |
| 394 DCHECK(pending_credentials_.preferred); | 404 DCHECK(pending_credentials_.preferred); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 521 } | 531 } |
| 522 return false; | 532 return false; |
| 523 } | 533 } |
| 524 | 534 |
| 525 int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const { | 535 int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const { |
| 526 DCHECK_EQ(state_, MATCHING_PHASE); | 536 DCHECK_EQ(state_, MATCHING_PHASE); |
| 527 // For scoring of candidate login data: | 537 // For scoring of candidate login data: |
| 528 // The most important element that should match is the origin, followed by | 538 // The most important element that should match is the origin, followed by |
| 529 // the action, the password name, the submit button name, and finally the | 539 // the action, the password name, the submit button name, and finally the |
| 530 // username input field name. | 540 // username input field name. |
| 531 // Exact origin match gives an addition of 32 (1 << 5) + # of matching url | 541 // Exact origin match gives an addition of 32 (1 << 5) + # of matching url |
|
nilesh
2013/06/04 23:02:36
Update these comments.
nyquist
2013/06/05 00:08:51
Done.
| |
| 532 // dirs. | 542 // dirs. |
| 533 // Partial match gives an addition of 16 (1 << 4) + # matching url dirs | 543 // Partial match gives an addition of 16 (1 << 4) + # matching url dirs |
| 534 // That way, a partial match cannot trump an exact match even if | 544 // That way, a partial match cannot trump an exact match even if |
| 535 // the partial one matches all other attributes (action, elements) (and | 545 // the partial one matches all other attributes (action, elements) (and |
| 536 // regardless of the matching depth in the URL path). | 546 // regardless of the matching depth in the URL path). |
| 537 int score = 0; | 547 int score = 0; |
| 538 if (candidate.origin == observed_form_.origin) { | 548 if (candidate.origin == observed_form_.origin) { |
| 539 // This check is here for the most common case which | 549 // This check is here for the most common case which |
| 540 // is we have a single match in the db for the given host, | 550 // is we have a single match in the db for the given host, |
| 541 // so we don't generally need to walk the entire URL path (the else | 551 // so we don't generally need to walk the entire URL path (the else |
| 542 // clause). | 552 // clause). |
| 543 score += (1 << 5) + static_cast<int>(form_path_tokens_.size()); | 553 score += (1 << 6) + static_cast<int>(form_path_tokens_.size()); |
| 544 } else { | 554 } else { |
| 545 // Walk the origin URL paths one directory at a time to see how | 555 // Walk the origin URL paths one directory at a time to see how |
| 546 // deep the two match. | 556 // deep the two match. |
| 547 std::vector<std::string> candidate_path_tokens; | 557 std::vector<std::string> candidate_path_tokens; |
| 548 base::SplitString(candidate.origin.path(), '/', &candidate_path_tokens); | 558 base::SplitString(candidate.origin.path(), '/', &candidate_path_tokens); |
| 549 size_t depth = 0; | 559 size_t depth = 0; |
| 550 size_t max_dirs = std::min(form_path_tokens_.size(), | 560 size_t max_dirs = std::min(form_path_tokens_.size(), |
| 551 candidate_path_tokens.size()); | 561 candidate_path_tokens.size()); |
| 552 while ((depth < max_dirs) && (form_path_tokens_[depth] == | 562 while ((depth < max_dirs) && (form_path_tokens_[depth] == |
| 553 candidate_path_tokens[depth])) { | 563 candidate_path_tokens[depth])) { |
| 554 depth++; | 564 depth++; |
| 555 score++; | 565 score++; |
| 556 } | 566 } |
| 557 // do we have a partial match? | 567 // do we have a partial match? |
| 558 score += (depth > 0) ? 1 << 4 : 0; | 568 score += (depth > 0) ? 1 << 5 : 0; |
| 559 } | 569 } |
| 560 if (observed_form_.scheme == PasswordForm::SCHEME_HTML) { | 570 if (observed_form_.scheme == PasswordForm::SCHEME_HTML) { |
| 571 // PSL origin matched domains should have lower score than perfect matches. | |
| 572 if (!candidate.is_psl_origin_match) | |
| 573 score += 1 << 4; | |
| 561 if (candidate.action == observed_form_.action) | 574 if (candidate.action == observed_form_.action) |
| 562 score += 1 << 3; | 575 score += 1 << 3; |
| 563 if (candidate.password_element == observed_form_.password_element) | 576 if (candidate.password_element == observed_form_.password_element) |
| 564 score += 1 << 2; | 577 score += 1 << 2; |
| 565 if (candidate.submit_element == observed_form_.submit_element) | 578 if (candidate.submit_element == observed_form_.submit_element) |
| 566 score += 1 << 1; | 579 score += 1 << 1; |
| 567 if (candidate.username_element == observed_form_.username_element) | 580 if (candidate.username_element == observed_form_.username_element) |
| 568 score += 1 << 0; | 581 score += 1 << 0; |
| 569 } | 582 } |
| 570 | 583 |
| 571 return score; | 584 return score; |
| 572 } | 585 } |
| 573 | 586 |
| 574 void PasswordFormManager::SubmitPassed() { | 587 void PasswordFormManager::SubmitPassed() { |
| 575 submit_result_ = kSubmitResultPassed; | 588 submit_result_ = kSubmitResultPassed; |
| 576 } | 589 } |
| 577 | 590 |
| 578 void PasswordFormManager::SubmitFailed() { | 591 void PasswordFormManager::SubmitFailed() { |
| 579 submit_result_ = kSubmitResultFailed; | 592 submit_result_ = kSubmitResultFailed; |
| 580 } | 593 } |
| 581 | 594 |
| 582 void PasswordFormManager::SendNotBlacklistedToRenderer() { | 595 void PasswordFormManager::SendNotBlacklistedToRenderer() { |
| 583 content::RenderViewHost* host = web_contents_->GetRenderViewHost(); | 596 content::RenderViewHost* host = web_contents_->GetRenderViewHost(); |
| 584 host->Send(new AutofillMsg_FormNotBlacklisted(host->GetRoutingID(), | 597 host->Send(new AutofillMsg_FormNotBlacklisted(host->GetRoutingID(), |
| 585 observed_form_)); | 598 observed_form_)); |
| 586 } | 599 } |
| OLD | NEW |