| 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_form_conversion_utils.h" | 5 #include "components/autofill/content/renderer/password_form_conversion_utils.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 // test frame origin to match GAIA login page. Once this code gets moved to | 134 // test frame origin to match GAIA login page. Once this code gets moved to |
| 135 // browser, we need to add tests for this as well. | 135 // browser, we need to add tests for this as well. |
| 136 blink::WebVector<blink::WebFormControlElement> web_control_elements; | 136 blink::WebVector<blink::WebFormControlElement> web_control_elements; |
| 137 web_form.getFormControlElements(web_control_elements); | 137 web_form.getFormControlElements(web_control_elements); |
| 138 synthetic_form->control_elements.assign(web_control_elements.begin(), | 138 synthetic_form->control_elements.assign(web_control_elements.begin(), |
| 139 web_control_elements.end()); | 139 web_control_elements.end()); |
| 140 synthetic_form->action = web_form.action(); | 140 synthetic_form->action = web_form.action(); |
| 141 synthetic_form->document = web_form.document(); | 141 synthetic_form->document = web_form.document(); |
| 142 } | 142 } |
| 143 | 143 |
| 144 // Helper function that removes |possible_username_pair| from the vector | 144 // Helper function that removes |username_element.value()| from the vector |
| 145 // |other_possible_usernames|, if the value presents in the vector. | 145 // |other_possible_usernames|, if the value presents in the vector. |
| 146 void ExcludeUsernameFromOtherUsernamesList( | 146 void ExcludeUsernameFromOtherUsernamesList( |
| 147 const PossibleUsernamePair& possible_username_pair, | 147 const WebInputElement& username_element, |
| 148 PossibleUsernamesVector* other_possible_usernames) { | 148 std::vector<base::string16>* other_possible_usernames) { |
| 149 other_possible_usernames->erase( | 149 other_possible_usernames->erase(std::remove(other_possible_usernames->begin(), |
| 150 std::remove(other_possible_usernames->begin(), | 150 other_possible_usernames->end(), |
| 151 other_possible_usernames->end(), possible_username_pair), | 151 username_element.value().utf16()), |
| 152 other_possible_usernames->end()); | 152 other_possible_usernames->end()); |
| 153 } | 153 } |
| 154 | 154 |
| 155 // Helper to determine which password is the main (current) one, and which is | 155 // Helper to determine which password is the main (current) one, and which is |
| 156 // the new password (e.g., on a sign-up or change password form), if any. If the | 156 // the new password (e.g., on a sign-up or change password form), if any. If the |
| 157 // new password is found and there is another password field with the same user | 157 // new password is found and there is another password field with the same user |
| 158 // input, the function also sets |confirmation_password| to this field. | 158 // input, the function also sets |confirmation_password| to this field. |
| 159 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords, | 159 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords, |
| 160 WebInputElement* current_password, | 160 WebInputElement* current_password, |
| 161 WebInputElement* new_password, | 161 WebInputElement* new_password, |
| 162 WebInputElement* confirmation_password) { | 162 WebInputElement* confirmation_password) { |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 if (input_element->isPasswordField()) { | 360 if (input_element->isPasswordField()) { |
| 361 *found_visible_password = true; | 361 *found_visible_password = true; |
| 362 *found_visible_username_before_visible_password = found_visible_username; | 362 *found_visible_username_before_visible_password = found_visible_username; |
| 363 break; | 363 break; |
| 364 } else { | 364 } else { |
| 365 found_visible_username = true; | 365 found_visible_username = true; |
| 366 } | 366 } |
| 367 } | 367 } |
| 368 } | 368 } |
| 369 | 369 |
| 370 autofill::PossibleUsernamePair MakePossibleUsernamePair( | |
| 371 const blink::WebInputElement& input) { | |
| 372 return autofill::PossibleUsernamePair(input.value().utf16(), | |
| 373 input.nameForAutofill().utf16()); | |
| 374 } | |
| 375 | |
| 376 // Get information about a login form encapsulated in a PasswordForm struct. | 370 // Get information about a login form encapsulated in a PasswordForm struct. |
| 377 // If an element of |form| has an entry in |nonscript_modified_values|, the | 371 // If an element of |form| has an entry in |nonscript_modified_values|, the |
| 378 // associated string is used instead of the element's value to create | 372 // associated string is used instead of the element's value to create |
| 379 // the PasswordForm. | 373 // the PasswordForm. |
| 380 bool GetPasswordForm( | 374 bool GetPasswordForm( |
| 381 const SyntheticForm& form, | 375 const SyntheticForm& form, |
| 382 PasswordForm* password_form, | 376 PasswordForm* password_form, |
| 383 const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, | 377 const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, |
| 384 const FormsPredictionsMap* form_predictions) { | 378 const FormsPredictionsMap* form_predictions) { |
| 385 WebInputElement latest_input_element; | 379 WebInputElement latest_input_element; |
| 386 WebInputElement username_element; | 380 WebInputElement username_element; |
| 387 password_form->username_marked_by_site = false; | 381 password_form->username_marked_by_site = false; |
| 388 std::vector<WebInputElement> passwords; | 382 std::vector<WebInputElement> passwords; |
| 389 std::map<blink::WebInputElement, blink::WebInputElement> | 383 std::map<blink::WebInputElement, blink::WebInputElement> |
| 390 last_text_input_before_password; | 384 last_text_input_before_password; |
| 391 autofill::PossibleUsernamesVector other_possible_usernames; | 385 std::vector<base::string16> other_possible_usernames; |
| 392 | 386 |
| 393 // Bail if this is a GAIA passwords site reauthentication form, so that | 387 // Bail if this is a GAIA passwords site reauthentication form, so that |
| 394 // the form will be ignored. | 388 // the form will be ignored. |
| 395 // TODO(msramek): Move this logic to the browser, and disable filling only | 389 // TODO(msramek): Move this logic to the browser, and disable filling only |
| 396 // for the sync credential and if passwords are being synced. | 390 // for the sync credential and if passwords are being synced. |
| 397 if (IsGaiaReauthenticationForm(GURL(form.document.url()).GetOrigin(), | 391 if (IsGaiaReauthenticationForm(GURL(form.document.url()).GetOrigin(), |
| 398 form.control_elements)) { | 392 form.control_elements)) { |
| 399 return false; | 393 return false; |
| 400 } | 394 } |
| 401 | 395 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 if (password_form->username_marked_by_site) { | 475 if (password_form->username_marked_by_site) { |
| 482 // A second or subsequent element marked with autocomplete='username'. | 476 // A second or subsequent element marked with autocomplete='username'. |
| 483 // This makes us less confident that we have understood the form. We | 477 // This makes us less confident that we have understood the form. We |
| 484 // will stick to our choice that the first such element was the real | 478 // will stick to our choice that the first such element was the real |
| 485 // username, but will start collecting other_possible_usernames from | 479 // username, but will start collecting other_possible_usernames from |
| 486 // the extra elements marked with autocomplete='username'. Note that | 480 // the extra elements marked with autocomplete='username'. Note that |
| 487 // unlike username_element, other_possible_usernames is used only for | 481 // unlike username_element, other_possible_usernames is used only for |
| 488 // autofill, not for form identification, and blank autofill entries | 482 // autofill, not for form identification, and blank autofill entries |
| 489 // are not useful, so we do not collect empty strings. | 483 // are not useful, so we do not collect empty strings. |
| 490 if (!input_element->value().isEmpty()) | 484 if (!input_element->value().isEmpty()) |
| 491 other_possible_usernames.push_back( | 485 other_possible_usernames.push_back(input_element->value().utf16()); |
| 492 MakePossibleUsernamePair(*input_element)); | |
| 493 } else { | 486 } else { |
| 494 // The first element marked with autocomplete='username'. Take the | 487 // The first element marked with autocomplete='username'. Take the |
| 495 // hint and treat it as the username (overruling the tentative choice | 488 // hint and treat it as the username (overruling the tentative choice |
| 496 // we might have made before). Furthermore, drop all other possible | 489 // we might have made before). Furthermore, drop all other possible |
| 497 // usernames we have accrued so far: they come from fields not marked | 490 // usernames we have accrued so far: they come from fields not marked |
| 498 // with the autocomplete attribute, making them unlikely alternatives. | 491 // with the autocomplete attribute, making them unlikely alternatives. |
| 499 username_element = *input_element; | 492 username_element = *input_element; |
| 500 password_form->username_marked_by_site = true; | 493 password_form->username_marked_by_site = true; |
| 501 other_possible_usernames.clear(); | 494 other_possible_usernames.clear(); |
| 502 } | 495 } |
| 503 } else { | 496 } else { |
| 504 if (password_form->username_marked_by_site) { | 497 if (password_form->username_marked_by_site) { |
| 505 // Having seen elements with autocomplete='username', elements without | 498 // Having seen elements with autocomplete='username', elements without |
| 506 // this attribute are no longer interesting. No-op. | 499 // this attribute are no longer interesting. No-op. |
| 507 } else { | 500 } else { |
| 508 // No elements marked with autocomplete='username' so far whatsoever. | 501 // No elements marked with autocomplete='username' so far whatsoever. |
| 509 // If we have not yet selected a username element even provisionally, | 502 // If we have not yet selected a username element even provisionally, |
| 510 // then remember this element for the case when the next field turns | 503 // then remember this element for the case when the next field turns |
| 511 // out to be a password. Save a non-empty username as a possible | 504 // out to be a password. Save a non-empty username as a possible |
| 512 // alternative, at least for now. | 505 // alternative, at least for now. |
| 513 if (username_element.isNull()) | 506 if (username_element.isNull()) |
| 514 latest_input_element = *input_element; | 507 latest_input_element = *input_element; |
| 515 if (!input_element->value().isEmpty()) | 508 if (!input_element->value().isEmpty()) |
| 516 other_possible_usernames.push_back( | 509 other_possible_usernames.push_back(input_element->value().utf16()); |
| 517 MakePossibleUsernamePair(*input_element)); | |
| 518 } | 510 } |
| 519 } | 511 } |
| 520 } | 512 } |
| 521 } | 513 } |
| 522 | 514 |
| 523 WebInputElement password; | 515 WebInputElement password; |
| 524 WebInputElement new_password; | 516 WebInputElement new_password; |
| 525 WebInputElement confirmation_password; | 517 WebInputElement confirmation_password; |
| 526 if (!LocateSpecificPasswords(passwords, &password, &new_password, | 518 if (!LocateSpecificPasswords(passwords, &password, &new_password, |
| 527 &confirmation_password)) | 519 &confirmation_password)) |
| 528 return false; | 520 return false; |
| 529 | 521 |
| 530 DCHECK_EQ(passwords.size(), last_text_input_before_password.size()); | 522 DCHECK_EQ(passwords.size(), last_text_input_before_password.size()); |
| 531 if (username_element.isNull()) { | 523 if (username_element.isNull()) { |
| 532 if (!password.isNull()) | 524 if (!password.isNull()) |
| 533 username_element = last_text_input_before_password[password]; | 525 username_element = last_text_input_before_password[password]; |
| 534 if (username_element.isNull() && !new_password.isNull()) | 526 if (username_element.isNull() && !new_password.isNull()) |
| 535 username_element = last_text_input_before_password[new_password]; | 527 username_element = last_text_input_before_password[new_password]; |
| 536 if (!username_element.isNull()) | 528 if (!username_element.isNull()) |
| 537 ExcludeUsernameFromOtherUsernamesList( | 529 ExcludeUsernameFromOtherUsernamesList(username_element, |
| 538 MakePossibleUsernamePair(username_element), | 530 &other_possible_usernames); |
| 539 &other_possible_usernames); | |
| 540 } | 531 } |
| 541 | 532 |
| 542 password_form->layout = SequenceToLayout(layout_sequence); | 533 password_form->layout = SequenceToLayout(layout_sequence); |
| 543 | 534 |
| 544 WebInputElement predicted_username_element; | 535 WebInputElement predicted_username_element; |
| 545 bool map_has_username_prediction = MapContainsPrediction( | 536 bool map_has_username_prediction = MapContainsPrediction( |
| 546 predicted_elements, PREDICTION_USERNAME, &predicted_username_element); | 537 predicted_elements, PREDICTION_USERNAME, &predicted_username_element); |
| 547 | 538 |
| 548 // Let server predictions override the selection of the username field. This | 539 // Let server predictions override the selection of the username field. This |
| 549 // allows instant adjusting without changing Chromium code. | 540 // allows instant adjusting without changing Chromium code. |
| 550 auto username_element_iterator = predicted_elements.find(username_element); | 541 auto username_element_iterator = predicted_elements.find(username_element); |
| 551 if (map_has_username_prediction && | 542 if (map_has_username_prediction && |
| 552 (username_element_iterator == predicted_elements.end() || | 543 (username_element_iterator == predicted_elements.end() || |
| 553 username_element_iterator->second != PREDICTION_USERNAME)) { | 544 username_element_iterator->second != PREDICTION_USERNAME)) { |
| 554 ExcludeUsernameFromOtherUsernamesList( | 545 ExcludeUsernameFromOtherUsernamesList(predicted_username_element, |
| 555 MakePossibleUsernamePair(predicted_username_element), | 546 &other_possible_usernames); |
| 556 &other_possible_usernames); | |
| 557 if (!username_element.isNull()) { | 547 if (!username_element.isNull()) { |
| 558 other_possible_usernames.push_back( | 548 other_possible_usernames.push_back(username_element.value().utf16()); |
| 559 MakePossibleUsernamePair(username_element)); | |
| 560 } | 549 } |
| 561 username_element = predicted_username_element; | 550 username_element = predicted_username_element; |
| 562 password_form->was_parsed_using_autofill_predictions = true; | 551 password_form->was_parsed_using_autofill_predictions = true; |
| 563 } | 552 } |
| 564 | 553 |
| 565 if (!username_element.isNull()) { | 554 if (!username_element.isNull()) { |
| 566 password_form->username_element = | 555 password_form->username_element = |
| 567 FieldName(username_element, "anonymous_username"); | 556 FieldName(username_element, "anonymous_username"); |
| 568 base::string16 username_value = username_element.value().utf16(); | 557 base::string16 username_value = username_element.value().utf16(); |
| 569 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map, | 558 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map, |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 const char* value_in_lowercase) { | 726 const char* value_in_lowercase) { |
| 738 base::string16 autocomplete_attribute( | 727 base::string16 autocomplete_attribute( |
| 739 element.getAttribute("autocomplete").utf16()); | 728 element.getAttribute("autocomplete").utf16()); |
| 740 std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString( | 729 std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString( |
| 741 base::UTF16ToUTF8(autocomplete_attribute)); | 730 base::UTF16ToUTF8(autocomplete_attribute)); |
| 742 | 731 |
| 743 return base::ContainsValue(tokens, value_in_lowercase); | 732 return base::ContainsValue(tokens, value_in_lowercase); |
| 744 } | 733 } |
| 745 | 734 |
| 746 } // namespace autofill | 735 } // namespace autofill |
| OLD | NEW |