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..0294768cab0b2cf9cb6a8fc7df158a6050b19d03 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 autocomplete attribute, take that as |
vabr (Chromium)
2014/07/07 10:01:47
optional nit: either autocomplete attribute -> eit
engedy
2014/07/07 10:49:26
Done. This is exactly the kind of ambiguity I am r
|
+ // 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 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 |