| Index: components/autofill/content/renderer/password_form_conversion_utils.cc
|
| diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
|
| index 72efccca58d6d485cb91e1ca52ad14a172fa282f..e59900b247e5c0c13a03a696f543856f42094df8 100644
|
| --- a/components/autofill/content/renderer/password_form_conversion_utils.cc
|
| +++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
|
| @@ -28,21 +28,46 @@ static const size_t kMaxPasswords = 3;
|
|
|
| // Checks in a case-insensitive way if the autocomplete attribute for the given
|
| // |element| is present and has the specified |value_in_lowercase|.
|
| -bool HasAutocompleteAttributeValue(const WebInputElement* element,
|
| +bool HasAutocompleteAttributeValue(const WebInputElement& element,
|
| const char* value_in_lowercase) {
|
| - return LowerCaseEqualsASCII(element->getAttribute("autocomplete"),
|
| + return LowerCaseEqualsASCII(element.getAttribute("autocomplete"),
|
| value_in_lowercase);
|
| }
|
|
|
| // Helper to determine which password is the main (current) one, and which is
|
| // the new password (e.g., on a sign-up or change password form), if any.
|
| bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
|
| - WebInputElement* password,
|
| + WebInputElement* current_password,
|
| WebInputElement* new_password) {
|
| + DCHECK(current_password && current_password->isNull());
|
| + DCHECK(new_password && new_password->isNull());
|
| +
|
| + // First, look for elements marked with either autocomplete='current-password'
|
| + // or 'new-password' -- if we find any, take the hint, and treat the first of
|
| + // each kind as the element we are looking for.
|
| + for (std::vector<WebInputElement>::const_iterator it = passwords.begin();
|
| + it != passwords.end(); it++) {
|
| + if (HasAutocompleteAttributeValue(*it, "current-password") &&
|
| + current_password->isNull()) {
|
| + *current_password = *it;
|
| + } else if (HasAutocompleteAttributeValue(*it, "new-password") &&
|
| + new_password->isNull()) {
|
| + *new_password = *it;
|
| + }
|
| + }
|
| +
|
| + // If we have seen an element with either of autocomplete attributes above,
|
| + // take that as a signal that the page author must have intentionally left the
|
| + // rest of the password fields unmarked. Perhaps they are used for other
|
| + // purposes, e.g., PINs, OTPs, and the like. So we skip all the heuristics we
|
| + // normally do, and ignore the rest of the password fields.
|
| + if (!current_password->isNull() || !new_password->isNull())
|
| + return true;
|
| +
|
| switch (passwords.size()) {
|
| case 1:
|
| // Single password, easy.
|
| - *password = passwords[0];
|
| + *current_password = passwords[0];
|
| break;
|
| case 2:
|
| if (passwords[0].value() == passwords[1].value()) {
|
| @@ -52,7 +77,7 @@ bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
|
| *new_password = passwords[0];
|
| } else {
|
| // Assume first is old password, second is new (no choice but to guess).
|
| - *password = passwords[0];
|
| + *current_password = passwords[0];
|
| *new_password = passwords[1];
|
| }
|
| break;
|
| @@ -66,12 +91,12 @@ bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
|
| } else if (passwords[1].value() == passwords[2].value()) {
|
| // New password is the duplicated one, and comes second; or empty form
|
| // with 3 password fields, in which case we will assume this layout.
|
| - *password = passwords[0];
|
| + *current_password = passwords[0];
|
| *new_password = passwords[1];
|
| } else if (passwords[0].value() == passwords[1].value()) {
|
| // It is strange that the new password comes first, but trust more which
|
| // fields are duplicated than the ordering of fields.
|
| - *password = passwords[2];
|
| + *current_password = passwords[2];
|
| *new_password = passwords[0];
|
| } else {
|
| // Three different passwords, or first and last match with middle
|
| @@ -128,7 +153,7 @@ void GetPasswordForm(const WebFormElement& form, PasswordForm* password_form) {
|
|
|
| // Various input types such as text, url, email can be a username field.
|
| if (input_element->isTextField() && !input_element->isPasswordField()) {
|
| - if (HasAutocompleteAttributeValue(input_element, "username")) {
|
| + if (HasAutocompleteAttributeValue(*input_element, "username")) {
|
| if (has_seen_element_with_autocomplete_username_before) {
|
| // A second or subsequent element marked with autocomplete='username'.
|
| // This makes us less confident that we have understood the form. We
|
|
|