Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "components/autofill/content/renderer/password_autofill_agent.h" | 5 #include "components/autofill/content/renderer/password_autofill_agent.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> | 10 #include <memory> |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 FormInputElementMap unowned_elements_map; | 261 FormInputElementMap unowned_elements_map; |
| 262 if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names, | 262 if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names, |
| 263 &unowned_elements_map)) | 263 &unowned_elements_map)) |
| 264 results->push_back(unowned_elements_map); | 264 results->push_back(unowned_elements_map); |
| 265 } | 265 } |
| 266 | 266 |
| 267 bool IsElementEditable(const blink::WebInputElement& element) { | 267 bool IsElementEditable(const blink::WebInputElement& element) { |
| 268 return element.IsEnabled() && !element.IsReadOnly(); | 268 return element.IsEnabled() && !element.IsReadOnly(); |
| 269 } | 269 } |
| 270 | 270 |
| 271 bool DoUsernamesMatch(const base::string16& username1, | 271 bool DoUsernamesMatch(const base::string16& potential_suggestion, |
| 272 const base::string16& username2, | 272 const base::string16& current_username, |
| 273 bool exact_match) { | 273 bool exact_match) { |
| 274 if (exact_match) | 274 bool match = (potential_suggestion == current_username); |
|
vabr (Chromium)
2017/06/12 18:56:58
optional nit: I am a bit concerned that we have tw
melandory
2017/06/19 10:53:48
Done.
| |
| 275 return username1 == username2; | 275 return exact_match ? match |
| 276 return FieldIsSuggestionSubstringStartingOnTokenBoundary(username1, username2, | 276 : (match || IsPrefixEndingOnTokenBoundary( |
| 277 true); | 277 current_username, potential_suggestion)); |
| 278 } | 278 } |
| 279 | 279 |
| 280 // Returns whether the given |element| is editable. | 280 // Returns whether the given |element| is editable. |
| 281 bool IsElementAutocompletable(const blink::WebInputElement& element) { | 281 bool IsElementAutocompletable(const blink::WebInputElement& element) { |
| 282 return IsElementEditable(element); | 282 return IsElementEditable(element); |
| 283 } | 283 } |
| 284 | 284 |
| 285 // Returns whether the |username_element| is allowed to be autofilled. | 285 // Returns whether the |username_element| is allowed to be autofilled. |
| 286 // | 286 // |
| 287 // Note that if the user interacts with the |password_field| and the | 287 // Note that if the user interacts with the |password_field| and the |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 if (value) | 366 if (value) |
| 367 it->second.first.reset(new base::string16(*value)); | 367 it->second.first.reset(new base::string16(*value)); |
| 368 it->second.second |= added_flags; | 368 it->second.second |= added_flags; |
| 369 } else { | 369 } else { |
| 370 (*field_value_and_properties_map)[element] = std::make_pair( | 370 (*field_value_and_properties_map)[element] = std::make_pair( |
| 371 value ? base::MakeUnique<base::string16>(*value) : nullptr, | 371 value ? base::MakeUnique<base::string16>(*value) : nullptr, |
| 372 added_flags); | 372 added_flags); |
| 373 } | 373 } |
| 374 } | 374 } |
| 375 | 375 |
| 376 void FindMatchesByUsername(const PasswordFormFillData& fill_data, | |
|
vabr (Chromium)
2017/06/12 18:56:58
nit: Please comment on what the function does and
melandory
2017/06/19 10:53:48
Done.
| |
| 377 const base::string16& current_username, | |
| 378 bool exact_username_match, | |
| 379 RendererSavePasswordProgressLogger* logger, | |
| 380 base::string16* username, | |
| 381 base::string16* password) { | |
| 382 // Look for any suitable matches to current field text. | |
| 383 if (DoUsernamesMatch(fill_data.username_field.value, current_username, | |
| 384 exact_username_match)) { | |
| 385 *username = fill_data.username_field.value; | |
| 386 *password = fill_data.password_field.value; | |
| 387 if (logger) | |
| 388 logger->LogMessage(Logger::STRING_USERNAMES_MATCH); | |
| 389 } else { | |
| 390 // Scan additional logins for a match. | |
| 391 for (const auto& it : fill_data.additional_logins) { | |
| 392 if (DoUsernamesMatch(it.first, current_username, exact_username_match)) { | |
| 393 *username = it.first; | |
| 394 *password = it.second.password; | |
| 395 break; | |
| 396 } | |
| 397 } | |
| 398 if (logger) { | |
| 399 logger->LogBoolean(Logger::STRING_MATCH_IN_ADDITIONAL, | |
| 400 !(username->empty() && password->empty())); | |
| 401 } | |
| 402 | |
| 403 // Check possible usernames. | |
| 404 if (username->empty() && password->empty()) { | |
| 405 for (const auto& it : fill_data.other_possible_usernames) { | |
| 406 for (size_t i = 0; i < it.second.size(); ++i) { | |
| 407 if (DoUsernamesMatch(it.second[i], current_username, | |
| 408 exact_username_match)) { | |
| 409 *username = it.second[i]; | |
| 410 *password = it.first.password; | |
| 411 break; | |
| 412 } | |
| 413 } | |
| 414 if (!username->empty() && !password->empty()) | |
|
vabr (Chromium)
2017/06/12 18:56:58
I know that this is just the old code moved around
melandory
2017/06/19 10:53:48
Done.
| |
| 415 break; | |
| 416 } | |
| 417 } | |
| 418 } | |
| 419 } | |
| 420 | |
| 376 // This function attempts to fill |username_element| and |password_element| | 421 // This function attempts to fill |username_element| and |password_element| |
| 377 // with values from |fill_data|. The |password_element| will only have the | 422 // with values from |fill_data|. The |password_element| will only have the |
| 378 // suggestedValue set, and will be registered for copying that to the real | 423 // suggestedValue set, and will be registered for copying that to the real |
| 379 // value through |registration_callback|. If a match is found, return true and | 424 // value through |registration_callback|. If a match is found, return true and |
| 380 // |field_value_and_properties_map| will be modified with the autofilled | 425 // |field_value_and_properties_map| will be modified with the autofilled |
| 381 // credentials and |FieldPropertiesFlags::AUTOFILLED| flag. | 426 // credentials and |FieldPropertiesFlags::AUTOFILLED| flag. |
| 382 bool FillUserNameAndPassword( | 427 bool FillUserNameAndPassword( |
| 383 blink::WebInputElement* username_element, | 428 blink::WebInputElement* username_element, |
| 384 blink::WebInputElement* password_element, | 429 blink::WebInputElement* password_element, |
| 385 const PasswordFormFillData& fill_data, | 430 const PasswordFormFillData& fill_data, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 397 | 442 |
| 398 base::string16 current_username; | 443 base::string16 current_username; |
| 399 if (!username_element->IsNull()) { | 444 if (!username_element->IsNull()) { |
| 400 current_username = username_element->Value().Utf16(); | 445 current_username = username_element->Value().Utf16(); |
| 401 } | 446 } |
| 402 | 447 |
| 403 // username and password will contain the match found if any. | 448 // username and password will contain the match found if any. |
| 404 base::string16 username; | 449 base::string16 username; |
| 405 base::string16 password; | 450 base::string16 password; |
| 406 | 451 |
| 407 // Look for any suitable matches to current field text. | 452 FindMatchesByUsername(fill_data, current_username, exact_username_match, |
| 408 if (DoUsernamesMatch(fill_data.username_field.value, current_username, | 453 logger, &username, &password); |
| 409 exact_username_match)) { | |
| 410 username = fill_data.username_field.value; | |
| 411 password = fill_data.password_field.value; | |
| 412 if (logger) | |
| 413 logger->LogMessage(Logger::STRING_USERNAMES_MATCH); | |
| 414 } else { | |
| 415 // Scan additional logins for a match. | |
| 416 for (const auto& it : fill_data.additional_logins) { | |
| 417 if (DoUsernamesMatch(it.first, current_username, exact_username_match)) { | |
| 418 username = it.first; | |
| 419 password = it.second.password; | |
| 420 break; | |
| 421 } | |
| 422 } | |
| 423 if (logger) { | |
| 424 logger->LogBoolean(Logger::STRING_MATCH_IN_ADDITIONAL, | |
| 425 !(username.empty() && password.empty())); | |
| 426 } | |
| 427 | 454 |
| 428 // Check possible usernames. | |
| 429 if (username.empty() && password.empty()) { | |
| 430 for (const auto& it : fill_data.other_possible_usernames) { | |
| 431 for (size_t i = 0; i < it.second.size(); ++i) { | |
| 432 if (DoUsernamesMatch( | |
| 433 it.second[i], current_username, exact_username_match)) { | |
| 434 username = it.second[i]; | |
| 435 password = it.first.password; | |
| 436 break; | |
| 437 } | |
| 438 } | |
| 439 if (!username.empty() && !password.empty()) | |
| 440 break; | |
| 441 } | |
| 442 } | |
| 443 } | |
| 444 if (password.empty()) | 455 if (password.empty()) |
| 445 return false; | 456 return false; |
| 446 | 457 |
| 447 // TODO(tkent): Check maxlength and pattern for both username and password | 458 // TODO(tkent): Check maxlength and pattern for both username and password |
| 448 // fields. | 459 // fields. |
| 449 | 460 |
| 450 // Input matches the username, fill in required values. | 461 // Input matches the username, fill in required values. |
| 451 if (!username_element->IsNull() && | 462 if (!username_element->IsNull() && |
| 452 IsElementAutocompletable(*username_element)) { | 463 IsElementAutocompletable(*username_element)) { |
| 453 // TODO(crbug.com/507714): Why not setSuggestedValue? | 464 // TODO(crbug.com/507714): Why not setSuggestedValue? |
| 454 username_element->SetAutofillValue(blink::WebString::FromUTF16(username)); | 465 username_element->SetAutofillValue(blink::WebString::FromUTF16(username)); |
| 455 UpdateFieldValueAndPropertiesMaskMap(*username_element, &username, | 466 UpdateFieldValueAndPropertiesMaskMap(*username_element, &username, |
| 456 FieldPropertiesFlags::AUTOFILLED, | 467 FieldPropertiesFlags::AUTOFILLED, |
| 457 field_value_and_properties_map); | 468 field_value_and_properties_map); |
| 458 username_element->SetAutofilled(true); | 469 username_element->SetAutofilled(true); |
| 459 if (logger) | 470 if (logger) |
| 460 logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element); | 471 logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element); |
| 461 if (set_selection) { | 472 if (set_selection) { |
| 462 form_util::PreviewSuggestion(username, current_username, | 473 form_util::PreviewSuggestion(username, current_username, |
| 463 username_element); | 474 username_element); |
| 464 } | 475 } |
| 465 } else if (current_username != username) { | 476 } else if (exact_username_match && current_username != username) { |
|
vabr (Chromium)
2017/06/12 18:56:58
There is not code path to satisfy this condition:
melandory
2017/06/19 10:53:48
Done.
| |
| 466 // If the username can't be filled and it doesn't match a saved password | 477 // If the username can't be filled and it doesn't match a saved password |
| 467 // as is, don't autofill a password. | 478 // as is, autofill the password only in case the username element id read |
| 479 // only. | |
| 468 return false; | 480 return false; |
| 469 } | 481 } |
| 470 | 482 |
| 471 // Wait to fill in the password until a user gesture occurs. This is to make | 483 // Wait to fill in the password until a user gesture occurs. This is to make |
| 472 // sure that we do not fill in the DOM with a password until we believe the | 484 // sure that we do not fill in the DOM with a password until we believe the |
| 473 // user is intentionally interacting with the page. | 485 // user is intentionally interacting with the page. |
| 474 password_element->SetSuggestedValue(blink::WebString::FromUTF16(password)); | 486 password_element->SetSuggestedValue(blink::WebString::FromUTF16(password)); |
| 475 UpdateFieldValueAndPropertiesMaskMap(*password_element, &password, | 487 UpdateFieldValueAndPropertiesMaskMap(*password_element, &password, |
| 476 FieldPropertiesFlags::AUTOFILLED, | 488 FieldPropertiesFlags::AUTOFILLED, |
| 477 field_value_and_properties_map); | 489 field_value_and_properties_map); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 543 // In all other cases, do nothing. | 555 // In all other cases, do nothing. |
| 544 bool form_has_fillable_username = !username_field_name.empty() && | 556 bool form_has_fillable_username = !username_field_name.empty() && |
| 545 IsElementAutocompletable(username_element); | 557 IsElementAutocompletable(username_element); |
| 546 | 558 |
| 547 if (form_has_fillable_username && username_element.Value().IsEmpty()) { | 559 if (form_has_fillable_username && username_element.Value().IsEmpty()) { |
| 548 // TODO(tkent): Check maxlength and pattern. | 560 // TODO(tkent): Check maxlength and pattern. |
| 549 username_element.SetAutofillValue( | 561 username_element.SetAutofillValue( |
| 550 blink::WebString::FromUTF16(fill_data.username_field.value)); | 562 blink::WebString::FromUTF16(fill_data.username_field.value)); |
| 551 } | 563 } |
| 552 | 564 |
| 553 // Fill if we have an exact match for the username. Note that this sets | 565 bool exact_username_match = |
| 554 // username to autofilled. | 566 username_element.IsNull() || IsElementEditable(username_element); |
| 567 // User the exact match for the editable username fields and allow prefix | |
|
vabr (Chromium)
2017/06/12 18:56:58
nit: User -> Use
melandory
2017/06/19 10:53:48
Done.
| |
| 568 // match for read-only username fields. | |
| 569 // Note that this sets username to autofilled. | |
|
vabr (Chromium)
2017/06/12 18:56:58
nit: The latter sentence no longer makes sense ("t
melandory
2017/06/19 10:53:48
Done.
| |
| 555 return FillUserNameAndPassword( | 570 return FillUserNameAndPassword( |
| 556 &username_element, &password_element, fill_data, | 571 &username_element, &password_element, fill_data, exact_username_match, |
| 557 true /* exact_username_match */, false /* set_selection */, | 572 false /* set_selection */, field_value_and_properties_map, |
| 558 field_value_and_properties_map, registration_callback, logger); | 573 registration_callback, logger); |
| 559 } | 574 } |
| 560 | 575 |
| 561 // Annotate |forms| with form and field signatures as HTML attributes. | 576 // Annotate |forms| with form and field signatures as HTML attributes. |
| 562 void AnnotateFormsWithSignatures( | 577 void AnnotateFormsWithSignatures( |
| 563 blink::WebVector<blink::WebFormElement> forms) { | 578 blink::WebVector<blink::WebFormElement> forms) { |
| 564 for (blink::WebFormElement form : forms) { | 579 for (blink::WebFormElement form : forms) { |
| 565 std::unique_ptr<PasswordForm> password_form( | 580 std::unique_ptr<PasswordForm> password_form( |
| 566 CreatePasswordFormFromWebForm(form, nullptr, nullptr)); | 581 CreatePasswordFormFromWebForm(form, nullptr, nullptr)); |
| 567 if (password_form) { | 582 if (password_form) { |
| 568 form.SetAttribute( | 583 form.SetAttribute( |
| (...skipping 1203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1772 PasswordAutofillAgent::GetPasswordManagerDriver() { | 1787 PasswordAutofillAgent::GetPasswordManagerDriver() { |
| 1773 if (!password_manager_driver_) { | 1788 if (!password_manager_driver_) { |
| 1774 render_frame()->GetRemoteInterfaces()->GetInterface( | 1789 render_frame()->GetRemoteInterfaces()->GetInterface( |
| 1775 mojo::MakeRequest(&password_manager_driver_)); | 1790 mojo::MakeRequest(&password_manager_driver_)); |
| 1776 } | 1791 } |
| 1777 | 1792 |
| 1778 return password_manager_driver_; | 1793 return password_manager_driver_; |
| 1779 } | 1794 } |
| 1780 | 1795 |
| 1781 } // namespace autofill | 1796 } // namespace autofill |
| OLD | NEW |