Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: components/autofill/content/renderer/password_form_conversion_utils.cc

Issue 2747733004: [Password Manager] Send username correction votes (Closed)
Patch Set: Changes addressed to reviewer comments Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 |username_element.value()| from the vector 144 // Helper function that removes |possible_username_pair| 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 WebInputElement& username_element, 147 const PossibleUsernamePair& possible_username_pair,
148 std::vector<base::string16>* other_possible_usernames) { 148 PossibleUsernamesVector* other_possible_usernames) {
149 other_possible_usernames->erase(std::remove(other_possible_usernames->begin(), 149 other_possible_usernames->erase(
150 other_possible_usernames->end(), 150 std::remove(other_possible_usernames->begin(),
151 username_element.value().utf16()), 151 other_possible_usernames->end(), possible_username_pair),
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
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
370 // Get information about a login form encapsulated in a PasswordForm struct. 376 // Get information about a login form encapsulated in a PasswordForm struct.
371 // If an element of |form| has an entry in |nonscript_modified_values|, the 377 // If an element of |form| has an entry in |nonscript_modified_values|, the
372 // associated string is used instead of the element's value to create 378 // associated string is used instead of the element's value to create
373 // the PasswordForm. 379 // the PasswordForm.
374 bool GetPasswordForm( 380 bool GetPasswordForm(
375 const SyntheticForm& form, 381 const SyntheticForm& form,
376 PasswordForm* password_form, 382 PasswordForm* password_form,
377 const FieldValueAndPropertiesMaskMap* field_value_and_properties_map, 383 const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
378 const FormsPredictionsMap* form_predictions) { 384 const FormsPredictionsMap* form_predictions) {
379 WebInputElement latest_input_element; 385 WebInputElement latest_input_element;
380 WebInputElement username_element; 386 WebInputElement username_element;
381 password_form->username_marked_by_site = false; 387 password_form->username_marked_by_site = false;
382 std::vector<WebInputElement> passwords; 388 std::vector<WebInputElement> passwords;
383 std::map<blink::WebInputElement, blink::WebInputElement> 389 std::map<blink::WebInputElement, blink::WebInputElement>
384 last_text_input_before_password; 390 last_text_input_before_password;
385 std::vector<base::string16> other_possible_usernames; 391 autofill::PossibleUsernamesVector other_possible_usernames;
386 392
387 // Bail if this is a GAIA passwords site reauthentication form, so that 393 // Bail if this is a GAIA passwords site reauthentication form, so that
388 // the form will be ignored. 394 // the form will be ignored.
389 // TODO(msramek): Move this logic to the browser, and disable filling only 395 // TODO(msramek): Move this logic to the browser, and disable filling only
390 // for the sync credential and if passwords are being synced. 396 // for the sync credential and if passwords are being synced.
391 if (IsGaiaReauthenticationForm(GURL(form.document.url()).GetOrigin(), 397 if (IsGaiaReauthenticationForm(GURL(form.document.url()).GetOrigin(),
392 form.control_elements)) { 398 form.control_elements)) {
393 return false; 399 return false;
394 } 400 }
395 401
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 if (password_form->username_marked_by_site) { 481 if (password_form->username_marked_by_site) {
476 // A second or subsequent element marked with autocomplete='username'. 482 // A second or subsequent element marked with autocomplete='username'.
477 // This makes us less confident that we have understood the form. We 483 // This makes us less confident that we have understood the form. We
478 // will stick to our choice that the first such element was the real 484 // will stick to our choice that the first such element was the real
479 // username, but will start collecting other_possible_usernames from 485 // username, but will start collecting other_possible_usernames from
480 // the extra elements marked with autocomplete='username'. Note that 486 // the extra elements marked with autocomplete='username'. Note that
481 // unlike username_element, other_possible_usernames is used only for 487 // unlike username_element, other_possible_usernames is used only for
482 // autofill, not for form identification, and blank autofill entries 488 // autofill, not for form identification, and blank autofill entries
483 // are not useful, so we do not collect empty strings. 489 // are not useful, so we do not collect empty strings.
484 if (!input_element->value().isEmpty()) 490 if (!input_element->value().isEmpty())
485 other_possible_usernames.push_back(input_element->value().utf16()); 491 other_possible_usernames.push_back(
492 MakePossibleUsernamePair(*input_element));
486 } else { 493 } else {
487 // The first element marked with autocomplete='username'. Take the 494 // The first element marked with autocomplete='username'. Take the
488 // hint and treat it as the username (overruling the tentative choice 495 // hint and treat it as the username (overruling the tentative choice
489 // we might have made before). Furthermore, drop all other possible 496 // we might have made before). Furthermore, drop all other possible
490 // usernames we have accrued so far: they come from fields not marked 497 // usernames we have accrued so far: they come from fields not marked
491 // with the autocomplete attribute, making them unlikely alternatives. 498 // with the autocomplete attribute, making them unlikely alternatives.
492 username_element = *input_element; 499 username_element = *input_element;
493 password_form->username_marked_by_site = true; 500 password_form->username_marked_by_site = true;
494 other_possible_usernames.clear(); 501 other_possible_usernames.clear();
495 } 502 }
496 } else { 503 } else {
497 if (password_form->username_marked_by_site) { 504 if (password_form->username_marked_by_site) {
498 // Having seen elements with autocomplete='username', elements without 505 // Having seen elements with autocomplete='username', elements without
499 // this attribute are no longer interesting. No-op. 506 // this attribute are no longer interesting. No-op.
500 } else { 507 } else {
501 // No elements marked with autocomplete='username' so far whatsoever. 508 // No elements marked with autocomplete='username' so far whatsoever.
502 // If we have not yet selected a username element even provisionally, 509 // If we have not yet selected a username element even provisionally,
503 // then remember this element for the case when the next field turns 510 // then remember this element for the case when the next field turns
504 // out to be a password. Save a non-empty username as a possible 511 // out to be a password. Save a non-empty username as a possible
505 // alternative, at least for now. 512 // alternative, at least for now.
506 if (username_element.isNull()) 513 if (username_element.isNull())
507 latest_input_element = *input_element; 514 latest_input_element = *input_element;
508 if (!input_element->value().isEmpty()) 515 if (!input_element->value().isEmpty())
509 other_possible_usernames.push_back(input_element->value().utf16()); 516 other_possible_usernames.push_back(
517 MakePossibleUsernamePair(*input_element));
510 } 518 }
511 } 519 }
512 } 520 }
513 } 521 }
514 522
515 WebInputElement password; 523 WebInputElement password;
516 WebInputElement new_password; 524 WebInputElement new_password;
517 WebInputElement confirmation_password; 525 WebInputElement confirmation_password;
518 if (!LocateSpecificPasswords(passwords, &password, &new_password, 526 if (!LocateSpecificPasswords(passwords, &password, &new_password,
519 &confirmation_password)) 527 &confirmation_password))
520 return false; 528 return false;
521 529
522 DCHECK_EQ(passwords.size(), last_text_input_before_password.size()); 530 DCHECK_EQ(passwords.size(), last_text_input_before_password.size());
523 if (username_element.isNull()) { 531 if (username_element.isNull()) {
524 if (!password.isNull()) 532 if (!password.isNull())
525 username_element = last_text_input_before_password[password]; 533 username_element = last_text_input_before_password[password];
526 if (username_element.isNull() && !new_password.isNull()) 534 if (username_element.isNull() && !new_password.isNull())
527 username_element = last_text_input_before_password[new_password]; 535 username_element = last_text_input_before_password[new_password];
528 if (!username_element.isNull()) 536 if (!username_element.isNull())
529 ExcludeUsernameFromOtherUsernamesList(username_element, 537 ExcludeUsernameFromOtherUsernamesList(
530 &other_possible_usernames); 538 MakePossibleUsernamePair(username_element),
539 &other_possible_usernames);
531 } 540 }
532 541
533 password_form->layout = SequenceToLayout(layout_sequence); 542 password_form->layout = SequenceToLayout(layout_sequence);
534 543
535 WebInputElement predicted_username_element; 544 WebInputElement predicted_username_element;
536 bool map_has_username_prediction = MapContainsPrediction( 545 bool map_has_username_prediction = MapContainsPrediction(
537 predicted_elements, PREDICTION_USERNAME, &predicted_username_element); 546 predicted_elements, PREDICTION_USERNAME, &predicted_username_element);
538 547
539 // Let server predictions override the selection of the username field. This 548 // Let server predictions override the selection of the username field. This
540 // allows instant adjusting without changing Chromium code. 549 // allows instant adjusting without changing Chromium code.
541 auto username_element_iterator = predicted_elements.find(username_element); 550 auto username_element_iterator = predicted_elements.find(username_element);
542 if (map_has_username_prediction && 551 if (map_has_username_prediction &&
543 (username_element_iterator == predicted_elements.end() || 552 (username_element_iterator == predicted_elements.end() ||
544 username_element_iterator->second != PREDICTION_USERNAME)) { 553 username_element_iterator->second != PREDICTION_USERNAME)) {
545 ExcludeUsernameFromOtherUsernamesList(predicted_username_element, 554 ExcludeUsernameFromOtherUsernamesList(
546 &other_possible_usernames); 555 MakePossibleUsernamePair(predicted_username_element),
556 &other_possible_usernames);
547 if (!username_element.isNull()) { 557 if (!username_element.isNull()) {
548 other_possible_usernames.push_back(username_element.value().utf16()); 558 other_possible_usernames.push_back(
559 MakePossibleUsernamePair(username_element));
549 } 560 }
550 username_element = predicted_username_element; 561 username_element = predicted_username_element;
551 password_form->was_parsed_using_autofill_predictions = true; 562 password_form->was_parsed_using_autofill_predictions = true;
552 } 563 }
553 564
554 if (!username_element.isNull()) { 565 if (!username_element.isNull()) {
555 password_form->username_element = 566 password_form->username_element =
556 FieldName(username_element, "anonymous_username"); 567 FieldName(username_element, "anonymous_username");
557 base::string16 username_value = username_element.value().utf16(); 568 base::string16 username_value = username_element.value().utf16();
558 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map, 569 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map,
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 const char* value_in_lowercase) { 737 const char* value_in_lowercase) {
727 base::string16 autocomplete_attribute( 738 base::string16 autocomplete_attribute(
728 element.getAttribute("autocomplete").utf16()); 739 element.getAttribute("autocomplete").utf16());
729 std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString( 740 std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString(
730 base::UTF16ToUTF8(autocomplete_attribute)); 741 base::UTF16ToUTF8(autocomplete_attribute));
731 742
732 return base::ContainsValue(tokens, value_in_lowercase); 743 return base::ContainsValue(tokens, value_in_lowercase);
733 } 744 }
734 745
735 } // namespace autofill 746 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698