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 <memory> | 9 #include <memory> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 FormInputElementMap unowned_elements_map; | 260 FormInputElementMap unowned_elements_map; |
| 261 if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names, | 261 if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names, |
| 262 &unowned_elements_map)) | 262 &unowned_elements_map)) |
| 263 results->push_back(unowned_elements_map); | 263 results->push_back(unowned_elements_map); |
| 264 } | 264 } |
| 265 | 265 |
| 266 bool IsElementEditable(const blink::WebInputElement& element) { | 266 bool IsElementEditable(const blink::WebInputElement& element) { |
| 267 return element.IsEnabled() && !element.IsReadOnly(); | 267 return element.IsEnabled() && !element.IsReadOnly(); |
| 268 } | 268 } |
| 269 | 269 |
| 270 bool DoUsernamesMatch(const base::string16& username1, | 270 bool DoUsernamesMatch(const base::string16& potential_suggestion, |
| 271 const base::string16& username2, | 271 const base::string16& current_username, |
| 272 bool exact_match) { | 272 bool exact_match) { |
| 273 if (exact_match) | 273 bool match = (potential_suggestion == current_username); |
| 274 return username1 == username2; | 274 return exact_match |
| 275 return FieldIsSuggestionSubstringStartingOnTokenBoundary(username1, username2, | 275 ? match |
| 276 true); | 276 : (match || IsPrefixStartingOnTokenBoundary( |
| 277 current_username, potential_suggestion, true)); | |
|
dvadym
2017/06/01 12:15:56
As far as I understand the main use case is emails
melandory
2017/06/12 14:56:12
My motivation was that since currently gmail suffe
vabr (Chromium)
2017/06/12 18:56:58
Currently case sensitive equality is required. Let
| |
| 277 } | 278 } |
| 278 | 279 |
| 279 // Returns |true| if the given element is editable. Otherwise, returns |false|. | 280 // Returns |true| if the given element is editable. Otherwise, returns |false|. |
| 280 bool IsElementAutocompletable(const blink::WebInputElement& element) { | 281 bool IsElementAutocompletable(const blink::WebInputElement& element) { |
| 281 return IsElementEditable(element); | 282 return IsElementEditable(element); |
| 282 } | 283 } |
| 283 | 284 |
| 284 // Return true if either password_value or new_password_value is not empty and | 285 // Return true if either password_value or new_password_value is not empty and |
| 285 // not default. | 286 // not default. |
| 286 bool FormContainsNonDefaultPasswordValue(const PasswordForm& password_form) { | 287 bool FormContainsNonDefaultPasswordValue(const PasswordForm& password_form) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 351 if (value) | 352 if (value) |
| 352 it->second.first.reset(new base::string16(*value)); | 353 it->second.first.reset(new base::string16(*value)); |
| 353 it->second.second |= added_flags; | 354 it->second.second |= added_flags; |
| 354 } else { | 355 } else { |
| 355 (*field_value_and_properties_map)[element] = std::make_pair( | 356 (*field_value_and_properties_map)[element] = std::make_pair( |
| 356 value ? base::MakeUnique<base::string16>(*value) : nullptr, | 357 value ? base::MakeUnique<base::string16>(*value) : nullptr, |
| 357 added_flags); | 358 added_flags); |
| 358 } | 359 } |
| 359 } | 360 } |
| 360 | 361 |
| 362 void FindMatchesByUsername(const PasswordFormFillData& fill_data, | |
| 363 const base::string16& current_username, | |
| 364 bool exact_username_match, | |
| 365 RendererSavePasswordProgressLogger* logger, | |
| 366 base::string16* username, | |
| 367 base::string16* password) { | |
| 368 // Look for any suitable matches to current field text. | |
| 369 if (DoUsernamesMatch(fill_data.username_field.value, current_username, | |
| 370 exact_username_match)) { | |
| 371 *username = fill_data.username_field.value; | |
| 372 *password = fill_data.password_field.value; | |
| 373 if (logger) | |
| 374 logger->LogMessage(Logger::STRING_USERNAMES_MATCH); | |
| 375 } else { | |
| 376 // Scan additional logins for a match. | |
| 377 for (const auto& it : fill_data.additional_logins) { | |
| 378 if (DoUsernamesMatch(it.first, current_username, exact_username_match)) { | |
| 379 *username = it.first; | |
| 380 *password = it.second.password; | |
| 381 break; | |
| 382 } | |
| 383 } | |
| 384 if (logger) { | |
| 385 logger->LogBoolean(Logger::STRING_MATCH_IN_ADDITIONAL, | |
| 386 !(username->empty() && password->empty())); | |
| 387 } | |
| 388 | |
| 389 // Check possible usernames. | |
| 390 if (username->empty() && password->empty()) { | |
| 391 for (const auto& it : fill_data.other_possible_usernames) { | |
| 392 for (size_t i = 0; i < it.second.size(); ++i) { | |
| 393 if (DoUsernamesMatch(it.second[i], current_username, | |
| 394 exact_username_match)) { | |
| 395 *username = it.second[i]; | |
| 396 *password = it.first.password; | |
| 397 break; | |
| 398 } | |
| 399 } | |
| 400 if (!username->empty() && !password->empty()) | |
| 401 break; | |
| 402 } | |
| 403 } | |
| 404 } | |
| 405 } | |
| 406 | |
| 361 // This function attempts to fill |username_element| and |password_element| | 407 // This function attempts to fill |username_element| and |password_element| |
| 362 // with values from |fill_data|. The |password_element| will only have the | 408 // with values from |fill_data|. The |password_element| will only have the |
| 363 // suggestedValue set, and will be registered for copying that to the real | 409 // suggestedValue set, and will be registered for copying that to the real |
| 364 // value through |registration_callback|. If a match is found, return true and | 410 // value through |registration_callback|. If a match is found, return true and |
| 365 // |field_value_and_properties_map| will be modified with the autofilled | 411 // |field_value_and_properties_map| will be modified with the autofilled |
| 366 // credentials and |FieldPropertiesFlags::AUTOFILLED| flag. | 412 // credentials and |FieldPropertiesFlags::AUTOFILLED| flag. |
| 367 bool FillUserNameAndPassword( | 413 bool FillUserNameAndPassword( |
| 368 blink::WebInputElement* username_element, | 414 blink::WebInputElement* username_element, |
| 369 blink::WebInputElement* password_element, | 415 blink::WebInputElement* password_element, |
| 370 const PasswordFormFillData& fill_data, | 416 const PasswordFormFillData& fill_data, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 382 | 428 |
| 383 base::string16 current_username; | 429 base::string16 current_username; |
| 384 if (!username_element->IsNull()) { | 430 if (!username_element->IsNull()) { |
| 385 current_username = username_element->Value().Utf16(); | 431 current_username = username_element->Value().Utf16(); |
| 386 } | 432 } |
| 387 | 433 |
| 388 // username and password will contain the match found if any. | 434 // username and password will contain the match found if any. |
| 389 base::string16 username; | 435 base::string16 username; |
| 390 base::string16 password; | 436 base::string16 password; |
| 391 | 437 |
| 392 // Look for any suitable matches to current field text. | 438 FindMatchesByUsername(fill_data, current_username, exact_username_match, |
| 393 if (DoUsernamesMatch(fill_data.username_field.value, current_username, | 439 logger, &username, &password); |
| 394 exact_username_match)) { | |
| 395 username = fill_data.username_field.value; | |
| 396 password = fill_data.password_field.value; | |
| 397 if (logger) | |
| 398 logger->LogMessage(Logger::STRING_USERNAMES_MATCH); | |
| 399 } else { | |
| 400 // Scan additional logins for a match. | |
| 401 for (const auto& it : fill_data.additional_logins) { | |
| 402 if (DoUsernamesMatch(it.first, current_username, exact_username_match)) { | |
| 403 username = it.first; | |
| 404 password = it.second.password; | |
| 405 break; | |
| 406 } | |
| 407 } | |
| 408 if (logger) { | |
| 409 logger->LogBoolean(Logger::STRING_MATCH_IN_ADDITIONAL, | |
| 410 !(username.empty() && password.empty())); | |
| 411 } | |
| 412 | 440 |
| 413 // Check possible usernames. | |
| 414 if (username.empty() && password.empty()) { | |
| 415 for (const auto& it : fill_data.other_possible_usernames) { | |
| 416 for (size_t i = 0; i < it.second.size(); ++i) { | |
| 417 if (DoUsernamesMatch( | |
| 418 it.second[i], current_username, exact_username_match)) { | |
| 419 username = it.second[i]; | |
| 420 password = it.first.password; | |
| 421 break; | |
| 422 } | |
| 423 } | |
| 424 if (!username.empty() && !password.empty()) | |
| 425 break; | |
| 426 } | |
| 427 } | |
| 428 } | |
| 429 if (password.empty()) | 441 if (password.empty()) |
| 430 return false; | 442 return false; |
| 431 | 443 |
| 432 // TODO(tkent): Check maxlength and pattern for both username and password | 444 // TODO(tkent): Check maxlength and pattern for both username and password |
| 433 // fields. | 445 // fields. |
| 434 | 446 |
| 435 // Input matches the username, fill in required values. | 447 // Input matches the username, fill in required values. |
| 436 if (!username_element->IsNull() && | 448 if (!username_element->IsNull() && |
| 437 IsElementAutocompletable(*username_element)) { | 449 IsElementAutocompletable(*username_element)) { |
| 438 // TODO(crbug.com/507714): Why not setSuggestedValue? | 450 // TODO(crbug.com/507714): Why not setSuggestedValue? |
| 439 username_element->SetAutofillValue(blink::WebString::FromUTF16(username)); | 451 username_element->SetAutofillValue(blink::WebString::FromUTF16(username)); |
| 440 UpdateFieldValueAndPropertiesMaskMap(*username_element, &username, | 452 UpdateFieldValueAndPropertiesMaskMap(*username_element, &username, |
| 441 FieldPropertiesFlags::AUTOFILLED, | 453 FieldPropertiesFlags::AUTOFILLED, |
| 442 field_value_and_properties_map); | 454 field_value_and_properties_map); |
| 443 username_element->SetAutofilled(true); | 455 username_element->SetAutofilled(true); |
| 444 if (logger) | 456 if (logger) |
| 445 logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element); | 457 logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element); |
| 446 if (set_selection) { | 458 if (set_selection) { |
| 447 form_util::PreviewSuggestion(username, current_username, | 459 form_util::PreviewSuggestion(username, current_username, |
| 448 username_element); | 460 username_element); |
| 449 } | 461 } |
| 450 } else if (current_username != username) { | 462 } else if (exact_username_match && current_username != username) { |
| 451 // If the username can't be filled and it doesn't match a saved password | 463 // If the username can't be filled and it doesn't match a saved password |
| 452 // as is, don't autofill a password. | 464 // as is, autofill the password only in case the username element id read |
| 465 // only. | |
| 453 return false; | 466 return false; |
| 454 } | 467 } |
| 455 | 468 |
| 456 // Wait to fill in the password until a user gesture occurs. This is to make | 469 // Wait to fill in the password until a user gesture occurs. This is to make |
| 457 // sure that we do not fill in the DOM with a password until we believe the | 470 // sure that we do not fill in the DOM with a password until we believe the |
| 458 // user is intentionally interacting with the page. | 471 // user is intentionally interacting with the page. |
| 459 password_element->SetSuggestedValue(blink::WebString::FromUTF16(password)); | 472 password_element->SetSuggestedValue(blink::WebString::FromUTF16(password)); |
| 460 UpdateFieldValueAndPropertiesMaskMap(*password_element, &password, | 473 UpdateFieldValueAndPropertiesMaskMap(*password_element, &password, |
| 461 FieldPropertiesFlags::AUTOFILLED, | 474 FieldPropertiesFlags::AUTOFILLED, |
| 462 field_value_and_properties_map); | 475 field_value_and_properties_map); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 528 // In all other cases, do nothing. | 541 // In all other cases, do nothing. |
| 529 bool form_has_fillable_username = !username_field_name.empty() && | 542 bool form_has_fillable_username = !username_field_name.empty() && |
| 530 IsElementAutocompletable(username_element); | 543 IsElementAutocompletable(username_element); |
| 531 | 544 |
| 532 if (form_has_fillable_username && username_element.Value().IsEmpty()) { | 545 if (form_has_fillable_username && username_element.Value().IsEmpty()) { |
| 533 // TODO(tkent): Check maxlength and pattern. | 546 // TODO(tkent): Check maxlength and pattern. |
| 534 username_element.SetAutofillValue( | 547 username_element.SetAutofillValue( |
| 535 blink::WebString::FromUTF16(fill_data.username_field.value)); | 548 blink::WebString::FromUTF16(fill_data.username_field.value)); |
| 536 } | 549 } |
| 537 | 550 |
| 538 // Fill if we have an exact match for the username. Note that this sets | 551 bool exact_username_match = |
| 539 // username to autofilled. | 552 username_element.IsNull() || IsElementEditable(username_element); |
| 553 // User the exact match for the editable username fields and allow prefix | |
| 554 // match for read-only username fields. | |
| 555 // Note that this sets username to autofilled. | |
| 540 return FillUserNameAndPassword( | 556 return FillUserNameAndPassword( |
| 541 &username_element, &password_element, fill_data, | 557 &username_element, &password_element, fill_data, exact_username_match, |
| 542 true /* exact_username_match */, false /* set_selection */, | 558 false /* set_selection */, field_value_and_properties_map, |
| 543 field_value_and_properties_map, registration_callback, logger); | 559 registration_callback, logger); |
| 544 } | 560 } |
| 545 | 561 |
| 546 // Annotate |forms| with form and field signatures as HTML attributes. | 562 // Annotate |forms| with form and field signatures as HTML attributes. |
| 547 void AnnotateFormsWithSignatures( | 563 void AnnotateFormsWithSignatures( |
| 548 blink::WebVector<blink::WebFormElement> forms) { | 564 blink::WebVector<blink::WebFormElement> forms) { |
| 549 for (blink::WebFormElement form : forms) { | 565 for (blink::WebFormElement form : forms) { |
| 550 std::unique_ptr<PasswordForm> password_form( | 566 std::unique_ptr<PasswordForm> password_form( |
| 551 CreatePasswordFormFromWebForm(form, nullptr, nullptr)); | 567 CreatePasswordFormFromWebForm(form, nullptr, nullptr)); |
| 552 if (password_form) { | 568 if (password_form) { |
| 553 form.SetAttribute( | 569 form.SetAttribute( |
| (...skipping 1163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1717 PasswordAutofillAgent::GetPasswordManagerDriver() { | 1733 PasswordAutofillAgent::GetPasswordManagerDriver() { |
| 1718 if (!password_manager_driver_) { | 1734 if (!password_manager_driver_) { |
| 1719 render_frame()->GetRemoteInterfaces()->GetInterface( | 1735 render_frame()->GetRemoteInterfaces()->GetInterface( |
| 1720 mojo::MakeRequest(&password_manager_driver_)); | 1736 mojo::MakeRequest(&password_manager_driver_)); |
| 1721 } | 1737 } |
| 1722 | 1738 |
| 1723 return password_manager_driver_; | 1739 return password_manager_driver_; |
| 1724 } | 1740 } |
| 1725 | 1741 |
| 1726 } // namespace autofill | 1742 } // namespace autofill |
| OLD | NEW |