| 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 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 |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 WebInputElement& username_element, | 147 const WebInputElement& username_element, |
| 148 std::vector<base::string16>* 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(), | 151 username_element.value().utf16()), |
| 152 username_element.value()), | 152 other_possible_usernames->end()); |
| 153 other_possible_usernames->end()); | |
| 154 } | 153 } |
| 155 | 154 |
| 156 // 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 |
| 157 // 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 |
| 158 // 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 |
| 159 // input, the function also sets |confirmation_password| to this field. | 158 // input, the function also sets |confirmation_password| to this field. |
| 160 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords, | 159 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords, |
| 161 WebInputElement* current_password, | 160 WebInputElement* current_password, |
| 162 WebInputElement* new_password, | 161 WebInputElement* new_password, |
| 163 WebInputElement* confirmation_password) { | 162 WebInputElement* confirmation_password) { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 return; | 280 return; |
| 282 | 281 |
| 283 std::vector<blink::WebFormControlElement> autofillable_elements = | 282 std::vector<blink::WebFormControlElement> autofillable_elements = |
| 284 form_util::ExtractAutofillableElementsFromSet(form.control_elements); | 283 form_util::ExtractAutofillableElementsFromSet(form.control_elements); |
| 285 const PasswordFormFieldPredictionMap& field_predictions = | 284 const PasswordFormFieldPredictionMap& field_predictions = |
| 286 predictions_it->second; | 285 predictions_it->second; |
| 287 for (const auto& prediction : field_predictions) { | 286 for (const auto& prediction : field_predictions) { |
| 288 const FormFieldData& target_field = prediction.first; | 287 const FormFieldData& target_field = prediction.first; |
| 289 const PasswordFormFieldPredictionType& type = prediction.second; | 288 const PasswordFormFieldPredictionType& type = prediction.second; |
| 290 for (const auto& control_element : autofillable_elements) { | 289 for (const auto& control_element : autofillable_elements) { |
| 291 if (control_element.nameForAutofill() == target_field.name) { | 290 if (control_element.nameForAutofill().utf16() == target_field.name) { |
| 292 const WebInputElement* input_element = | 291 const WebInputElement* input_element = |
| 293 toWebInputElement(&control_element); | 292 toWebInputElement(&control_element); |
| 294 | 293 |
| 295 // TODO(sebsg): Investigate why this guard is necessary, see | 294 // TODO(sebsg): Investigate why this guard is necessary, see |
| 296 // https://crbug.com/517490 for more details. | 295 // https://crbug.com/517490 for more details. |
| 297 if (input_element) { | 296 if (input_element) { |
| 298 (*predicted_elements)[*input_element] = type; | 297 (*predicted_elements)[*input_element] = type; |
| 299 } | 298 } |
| 300 break; | 299 break; |
| 301 } | 300 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 314 return CreateMatcher(instance, kPasswordSiteUrlRegex); | 313 return CreateMatcher(instance, kPasswordSiteUrlRegex); |
| 315 } | 314 } |
| 316 }; | 315 }; |
| 317 | 316 |
| 318 base::LazyInstance<re2::RE2, PasswordSiteUrlLazyInstanceTraits> | 317 base::LazyInstance<re2::RE2, PasswordSiteUrlLazyInstanceTraits> |
| 319 g_password_site_matcher = LAZY_INSTANCE_INITIALIZER; | 318 g_password_site_matcher = LAZY_INSTANCE_INITIALIZER; |
| 320 | 319 |
| 321 // Returns the |input_field| name if its non-empty; otherwise a |dummy_name|. | 320 // Returns the |input_field| name if its non-empty; otherwise a |dummy_name|. |
| 322 base::string16 FieldName(const WebInputElement& input_field, | 321 base::string16 FieldName(const WebInputElement& input_field, |
| 323 const char dummy_name[]) { | 322 const char dummy_name[]) { |
| 324 base::string16 field_name = input_field.nameForAutofill(); | 323 base::string16 field_name = input_field.nameForAutofill().utf16(); |
| 325 return field_name.empty() ? base::ASCIIToUTF16(dummy_name) : field_name; | 324 return field_name.empty() ? base::ASCIIToUTF16(dummy_name) : field_name; |
| 326 } | 325 } |
| 327 | 326 |
| 328 bool FieldHasNonscriptModifiedValue( | 327 bool FieldHasNonscriptModifiedValue( |
| 329 const FieldValueAndPropertiesMaskMap* field_map, | 328 const FieldValueAndPropertiesMaskMap* field_map, |
| 330 const blink::WebFormControlElement& element) { | 329 const blink::WebFormControlElement& element) { |
| 331 if (!field_map) | 330 if (!field_map) |
| 332 return false; | 331 return false; |
| 333 FieldValueAndPropertiesMaskMap::const_iterator it = field_map->find(element); | 332 FieldValueAndPropertiesMaskMap::const_iterator it = field_map->find(element); |
| 334 return it != field_map->end() && it->second.first.get(); | 333 return it != field_map->end() && it->second.first.get(); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 if (password_form->username_marked_by_site) { | 475 if (password_form->username_marked_by_site) { |
| 477 // A second or subsequent element marked with autocomplete='username'. | 476 // A second or subsequent element marked with autocomplete='username'. |
| 478 // 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 |
| 479 // 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 |
| 480 // username, but will start collecting other_possible_usernames from | 479 // username, but will start collecting other_possible_usernames from |
| 481 // the extra elements marked with autocomplete='username'. Note that | 480 // the extra elements marked with autocomplete='username'. Note that |
| 482 // unlike username_element, other_possible_usernames is used only for | 481 // unlike username_element, other_possible_usernames is used only for |
| 483 // autofill, not for form identification, and blank autofill entries | 482 // autofill, not for form identification, and blank autofill entries |
| 484 // are not useful, so we do not collect empty strings. | 483 // are not useful, so we do not collect empty strings. |
| 485 if (!input_element->value().isEmpty()) | 484 if (!input_element->value().isEmpty()) |
| 486 other_possible_usernames.push_back(input_element->value()); | 485 other_possible_usernames.push_back(input_element->value().utf16()); |
| 487 } else { | 486 } else { |
| 488 // The first element marked with autocomplete='username'. Take the | 487 // The first element marked with autocomplete='username'. Take the |
| 489 // hint and treat it as the username (overruling the tentative choice | 488 // hint and treat it as the username (overruling the tentative choice |
| 490 // we might have made before). Furthermore, drop all other possible | 489 // we might have made before). Furthermore, drop all other possible |
| 491 // 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 |
| 492 // with the autocomplete attribute, making them unlikely alternatives. | 491 // with the autocomplete attribute, making them unlikely alternatives. |
| 493 username_element = *input_element; | 492 username_element = *input_element; |
| 494 password_form->username_marked_by_site = true; | 493 password_form->username_marked_by_site = true; |
| 495 other_possible_usernames.clear(); | 494 other_possible_usernames.clear(); |
| 496 } | 495 } |
| 497 } else { | 496 } else { |
| 498 if (password_form->username_marked_by_site) { | 497 if (password_form->username_marked_by_site) { |
| 499 // Having seen elements with autocomplete='username', elements without | 498 // Having seen elements with autocomplete='username', elements without |
| 500 // this attribute are no longer interesting. No-op. | 499 // this attribute are no longer interesting. No-op. |
| 501 } else { | 500 } else { |
| 502 // No elements marked with autocomplete='username' so far whatsoever. | 501 // No elements marked with autocomplete='username' so far whatsoever. |
| 503 // If we have not yet selected a username element even provisionally, | 502 // If we have not yet selected a username element even provisionally, |
| 504 // 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 |
| 505 // 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 |
| 506 // alternative, at least for now. | 505 // alternative, at least for now. |
| 507 if (username_element.isNull()) | 506 if (username_element.isNull()) |
| 508 latest_input_element = *input_element; | 507 latest_input_element = *input_element; |
| 509 if (!input_element->value().isEmpty()) | 508 if (!input_element->value().isEmpty()) |
| 510 other_possible_usernames.push_back(input_element->value()); | 509 other_possible_usernames.push_back(input_element->value().utf16()); |
| 511 } | 510 } |
| 512 } | 511 } |
| 513 } | 512 } |
| 514 } | 513 } |
| 515 | 514 |
| 516 WebInputElement password; | 515 WebInputElement password; |
| 517 WebInputElement new_password; | 516 WebInputElement new_password; |
| 518 WebInputElement confirmation_password; | 517 WebInputElement confirmation_password; |
| 519 if (!LocateSpecificPasswords(passwords, &password, &new_password, | 518 if (!LocateSpecificPasswords(passwords, &password, &new_password, |
| 520 &confirmation_password)) | 519 &confirmation_password)) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 539 | 538 |
| 540 // Let server predictions override the selection of the username field. This | 539 // Let server predictions override the selection of the username field. This |
| 541 // allows instant adjusting without changing Chromium code. | 540 // allows instant adjusting without changing Chromium code. |
| 542 auto username_element_iterator = predicted_elements.find(username_element); | 541 auto username_element_iterator = predicted_elements.find(username_element); |
| 543 if (map_has_username_prediction && | 542 if (map_has_username_prediction && |
| 544 (username_element_iterator == predicted_elements.end() || | 543 (username_element_iterator == predicted_elements.end() || |
| 545 username_element_iterator->second != PREDICTION_USERNAME)) { | 544 username_element_iterator->second != PREDICTION_USERNAME)) { |
| 546 ExcludeUsernameFromOtherUsernamesList(predicted_username_element, | 545 ExcludeUsernameFromOtherUsernamesList(predicted_username_element, |
| 547 &other_possible_usernames); | 546 &other_possible_usernames); |
| 548 if (!username_element.isNull()) { | 547 if (!username_element.isNull()) { |
| 549 other_possible_usernames.push_back(username_element.value()); | 548 other_possible_usernames.push_back(username_element.value().utf16()); |
| 550 } | 549 } |
| 551 username_element = predicted_username_element; | 550 username_element = predicted_username_element; |
| 552 password_form->was_parsed_using_autofill_predictions = true; | 551 password_form->was_parsed_using_autofill_predictions = true; |
| 553 } | 552 } |
| 554 | 553 |
| 555 if (!username_element.isNull()) { | 554 if (!username_element.isNull()) { |
| 556 password_form->username_element = | 555 password_form->username_element = |
| 557 FieldName(username_element, "anonymous_username"); | 556 FieldName(username_element, "anonymous_username"); |
| 558 base::string16 username_value = username_element.value(); | 557 base::string16 username_value = username_element.value().utf16(); |
| 559 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map, | 558 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map, |
| 560 username_element)) { | 559 username_element)) { |
| 561 base::string16 typed_username_value = | 560 base::string16 typed_username_value = |
| 562 *field_value_and_properties_map->at(username_element).first; | 561 *field_value_and_properties_map->at(username_element).first; |
| 563 if (!base::StartsWith(base::i18n::ToLower(username_value), | 562 if (!base::StartsWith(base::i18n::ToLower(username_value), |
| 564 base::i18n::ToLower(typed_username_value), | 563 base::i18n::ToLower(typed_username_value), |
| 565 base::CompareCase::SENSITIVE)) { | 564 base::CompareCase::SENSITIVE)) { |
| 566 // We check that |username_value| was not obtained by autofilling | 565 // We check that |username_value| was not obtained by autofilling |
| 567 // |typed_username_value|. In case when it was, |typed_username_value| | 566 // |typed_username_value|. In case when it was, |typed_username_value| |
| 568 // is incomplete, so we should leave autofilled value. | 567 // is incomplete, so we should leave autofilled value. |
| 569 username_value = typed_username_value; | 568 username_value = typed_username_value; |
| 570 } | 569 } |
| 571 } | 570 } |
| 572 password_form->username_value = username_value; | 571 password_form->username_value = username_value; |
| 573 } | 572 } |
| 574 | 573 |
| 575 password_form->origin = | 574 password_form->origin = |
| 576 form_util::GetCanonicalOriginForDocument(form.document); | 575 form_util::GetCanonicalOriginForDocument(form.document); |
| 577 GURL::Replacements rep; | 576 GURL::Replacements rep; |
| 578 rep.SetPathStr(""); | 577 rep.SetPathStr(""); |
| 579 password_form->signon_realm = | 578 password_form->signon_realm = |
| 580 password_form->origin.ReplaceComponents(rep).spec(); | 579 password_form->origin.ReplaceComponents(rep).spec(); |
| 581 password_form->other_possible_usernames.swap(other_possible_usernames); | 580 password_form->other_possible_usernames.swap(other_possible_usernames); |
| 582 | 581 |
| 583 if (!password.isNull()) { | 582 if (!password.isNull()) { |
| 584 password_form->password_element = FieldName(password, "anonymous_password"); | 583 password_form->password_element = FieldName(password, "anonymous_password"); |
| 585 blink::WebString password_value = password.value(); | 584 blink::WebString password_value = password.value(); |
| 586 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map, | 585 if (FieldHasNonscriptModifiedValue(field_value_and_properties_map, |
| 587 password)) | 586 password)) |
| 588 password_value = *field_value_and_properties_map->at(password).first; | 587 password_value = blink::WebString::fromUTF16( |
| 589 password_form->password_value = password_value; | 588 *field_value_and_properties_map->at(password).first); |
| 589 password_form->password_value = password_value.utf16(); |
| 590 } | 590 } |
| 591 if (!new_password.isNull()) { | 591 if (!new_password.isNull()) { |
| 592 password_form->new_password_element = | 592 password_form->new_password_element = |
| 593 FieldName(new_password, "anonymous_new_password"); | 593 FieldName(new_password, "anonymous_new_password"); |
| 594 password_form->new_password_value = new_password.value(); | 594 password_form->new_password_value = new_password.value().utf16(); |
| 595 password_form->new_password_value_is_default = | 595 password_form->new_password_value_is_default = |
| 596 new_password.getAttribute("value") == new_password.value(); | 596 new_password.getAttribute("value") == new_password.value(); |
| 597 if (HasAutocompleteAttributeValue(new_password, kAutocompleteNewPassword)) | 597 if (HasAutocompleteAttributeValue(new_password, kAutocompleteNewPassword)) |
| 598 password_form->new_password_marked_by_site = true; | 598 password_form->new_password_marked_by_site = true; |
| 599 if (!confirmation_password.isNull()) { | 599 if (!confirmation_password.isNull()) { |
| 600 password_form->confirmation_password_element = | 600 password_form->confirmation_password_element = |
| 601 FieldName(confirmation_password, "anonymous_confirmation_password"); | 601 FieldName(confirmation_password, "anonymous_confirmation_password"); |
| 602 } | 602 } |
| 603 } | 603 } |
| 604 | 604 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 return std::unique_ptr<PasswordForm>(); | 714 return std::unique_ptr<PasswordForm>(); |
| 715 | 715 |
| 716 // No actual action on the form, so use the the origin as the action. | 716 // No actual action on the form, so use the the origin as the action. |
| 717 password_form->action = password_form->origin; | 717 password_form->action = password_form->origin; |
| 718 | 718 |
| 719 return password_form; | 719 return password_form; |
| 720 } | 720 } |
| 721 | 721 |
| 722 bool HasAutocompleteAttributeValue(const blink::WebInputElement& element, | 722 bool HasAutocompleteAttributeValue(const blink::WebInputElement& element, |
| 723 const char* value_in_lowercase) { | 723 const char* value_in_lowercase) { |
| 724 base::string16 autocomplete_attribute(element.getAttribute("autocomplete")); | 724 base::string16 autocomplete_attribute( |
| 725 element.getAttribute("autocomplete").utf16()); |
| 725 std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString( | 726 std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString( |
| 726 base::UTF16ToUTF8(autocomplete_attribute)); | 727 base::UTF16ToUTF8(autocomplete_attribute)); |
| 727 | 728 |
| 728 return base::ContainsValue(tokens, value_in_lowercase); | 729 return base::ContainsValue(tokens, value_in_lowercase); |
| 729 } | 730 } |
| 730 | 731 |
| 731 } // namespace autofill | 732 } // namespace autofill |
| OLD | NEW |