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 "base/strings/string_util.h" | 7 #include "base/strings/string_util.h" |
8 #include "components/autofill/content/renderer/form_autofill_util.h" | 8 #include "components/autofill/content/renderer/form_autofill_util.h" |
9 #include "components/autofill/core/common/password_form.h" | 9 #include "components/autofill/core/common/password_form.h" |
10 #include "third_party/WebKit/public/platform/WebString.h" | 10 #include "third_party/WebKit/public/platform/WebString.h" |
(...skipping 10 matching lines...) Expand all Loading... | |
21 | 21 |
22 namespace autofill { | 22 namespace autofill { |
23 namespace { | 23 namespace { |
24 | 24 |
25 // Maximum number of password fields we will observe before throwing our | 25 // Maximum number of password fields we will observe before throwing our |
26 // hands in the air and giving up with a given form. | 26 // hands in the air and giving up with a given form. |
27 static const size_t kMaxPasswords = 3; | 27 static const size_t kMaxPasswords = 3; |
28 | 28 |
29 // Checks in a case-insensitive way if the autocomplete attribute for the given | 29 // Checks in a case-insensitive way if the autocomplete attribute for the given |
30 // |element| is present and has the specified |value_in_lowercase|. | 30 // |element| is present and has the specified |value_in_lowercase|. |
31 bool HasAutocompleteAttributeValue(const WebInputElement* element, | 31 bool HasAutocompleteAttributeValue(const WebInputElement& element, |
32 const char* value_in_lowercase) { | 32 const char* value_in_lowercase) { |
33 return LowerCaseEqualsASCII(element->getAttribute("autocomplete"), | 33 return LowerCaseEqualsASCII(element.getAttribute("autocomplete"), |
34 value_in_lowercase); | 34 value_in_lowercase); |
35 } | 35 } |
36 | 36 |
37 // Helper to determine which password is the main (current) one, and which is | 37 // Helper to determine which password is the main (current) one, and which is |
38 // the new password (e.g., on a sign-up or change password form), if any. | 38 // the new password (e.g., on a sign-up or change password form), if any. |
39 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords, | 39 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords, |
40 WebInputElement* password, | 40 WebInputElement* current_password, |
41 WebInputElement* new_password) { | 41 WebInputElement* new_password) { |
42 // First, look for elements marked with either autocomplete='current-password' | |
43 // and/or 'new-password', and treat the first of each kind as that element. | |
44 for (std::vector<WebInputElement>::const_iterator it = passwords.begin(); | |
45 it != passwords.end(); it++) { | |
46 // If some password elements are marked with autocomplete='current-password' | |
47 // or with 'new-password', take the hint, and treat the first of each kind | |
48 // the element we are looking for. | |
vabr (Chromium)
2014/07/05 09:21:39
typo: the element -> as the element
engedy
2014/07/07 08:00:39
Done. I have actually removed this block of commen
| |
49 if (HasAutocompleteAttributeValue(*it, "current-password") && | |
50 current_password->isNull()) { | |
51 *current_password = *it; | |
vabr (Chromium)
2014/07/05 09:21:39
optional nit: I wonder if we should document that
engedy
2014/07/07 08:00:39
Done.
| |
52 } else if (HasAutocompleteAttributeValue(*it, "new-password") && | |
53 new_password->isNull()) { | |
54 *new_password = *it; | |
55 } | |
56 } | |
57 | |
58 // If we have found any marked-up elements, take the hint and skip all the | |
59 // heuristics we normally do, i.e., ignore the rest of the password fields. | |
60 // We do this under the assumption they are not intentionally not marked, | |
vabr (Chromium)
2014/07/05 09:21:39
typo: remove the first "not"
engedy
2014/07/07 08:00:39
Done, also rephrased.
| |
61 // because they are used for other purposes, e.g., PINs, OTPs, and the like. | |
62 if (!current_password->isNull() || !new_password->isNull()) | |
63 return true; | |
64 | |
42 switch (passwords.size()) { | 65 switch (passwords.size()) { |
43 case 1: | 66 case 1: |
44 // Single password, easy. | 67 // Single password, easy. |
45 *password = passwords[0]; | 68 *current_password = passwords[0]; |
46 break; | 69 break; |
47 case 2: | 70 case 2: |
48 if (passwords[0].value() == passwords[1].value()) { | 71 if (passwords[0].value() == passwords[1].value()) { |
49 // Two identical passwords: assume we are seeing a new password with a | 72 // Two identical passwords: assume we are seeing a new password with a |
50 // confirmation. This can be either a sign-up form or a password change | 73 // confirmation. This can be either a sign-up form or a password change |
51 // form that does not ask for the old password. | 74 // form that does not ask for the old password. |
52 *new_password = passwords[0]; | 75 *new_password = passwords[0]; |
53 } else { | 76 } else { |
54 // Assume first is old password, second is new (no choice but to guess). | 77 // Assume first is old password, second is new (no choice but to guess). |
55 *password = passwords[0]; | 78 *current_password = passwords[0]; |
56 *new_password = passwords[1]; | 79 *new_password = passwords[1]; |
57 } | 80 } |
58 break; | 81 break; |
59 case 3: | 82 case 3: |
60 if (!passwords[0].value().isEmpty() && | 83 if (!passwords[0].value().isEmpty() && |
61 (passwords[0].value() == passwords[1].value() && | 84 (passwords[0].value() == passwords[1].value() && |
62 passwords[0].value() == passwords[2].value())) { | 85 passwords[0].value() == passwords[2].value())) { |
63 // All three passwords are the same and non-empty? This does not make | 86 // All three passwords are the same and non-empty? This does not make |
64 // any sense, give up. | 87 // any sense, give up. |
65 return false; | 88 return false; |
66 } else if (passwords[1].value() == passwords[2].value()) { | 89 } else if (passwords[1].value() == passwords[2].value()) { |
67 // New password is the duplicated one, and comes second; or empty form | 90 // New password is the duplicated one, and comes second; or empty form |
68 // with 3 password fields, in which case we will assume this layout. | 91 // with 3 password fields, in which case we will assume this layout. |
69 *password = passwords[0]; | 92 *current_password = passwords[0]; |
70 *new_password = passwords[1]; | 93 *new_password = passwords[1]; |
71 } else if (passwords[0].value() == passwords[1].value()) { | 94 } else if (passwords[0].value() == passwords[1].value()) { |
72 // It is strange that the new password comes first, but trust more which | 95 // It is strange that the new password comes first, but trust more which |
73 // fields are duplicated than the ordering of fields. | 96 // fields are duplicated than the ordering of fields. |
74 *password = passwords[2]; | 97 *current_password = passwords[2]; |
75 *new_password = passwords[0]; | 98 *new_password = passwords[0]; |
76 } else { | 99 } else { |
77 // Three different passwords, or first and last match with middle | 100 // Three different passwords, or first and last match with middle |
78 // different. No idea which is which, so no luck. | 101 // different. No idea which is which, so no luck. |
79 return false; | 102 return false; |
80 } | 103 } |
81 break; | 104 break; |
82 default: | 105 default: |
83 return false; | 106 return false; |
84 } | 107 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
121 DCHECK(!other_possible_usernames.empty()); | 144 DCHECK(!other_possible_usernames.empty()); |
122 DCHECK_EQ(base::string16(latest_input_element.value()), | 145 DCHECK_EQ(base::string16(latest_input_element.value()), |
123 other_possible_usernames.back()); | 146 other_possible_usernames.back()); |
124 other_possible_usernames.pop_back(); | 147 other_possible_usernames.pop_back(); |
125 } | 148 } |
126 } | 149 } |
127 } | 150 } |
128 | 151 |
129 // Various input types such as text, url, email can be a username field. | 152 // Various input types such as text, url, email can be a username field. |
130 if (input_element->isTextField() && !input_element->isPasswordField()) { | 153 if (input_element->isTextField() && !input_element->isPasswordField()) { |
131 if (HasAutocompleteAttributeValue(input_element, "username")) { | 154 if (HasAutocompleteAttributeValue(*input_element, "username")) { |
132 if (has_seen_element_with_autocomplete_username_before) { | 155 if (has_seen_element_with_autocomplete_username_before) { |
133 // A second or subsequent element marked with autocomplete='username'. | 156 // A second or subsequent element marked with autocomplete='username'. |
134 // This makes us less confident that we have understood the form. We | 157 // This makes us less confident that we have understood the form. We |
135 // will stick to our choice that the first such element was the real | 158 // will stick to our choice that the first such element was the real |
136 // username, but will start collecting other_possible_usernames from | 159 // username, but will start collecting other_possible_usernames from |
137 // the extra elements marked with autocomplete='username'. Note that | 160 // the extra elements marked with autocomplete='username'. Note that |
138 // unlike username_element, other_possible_usernames is used only for | 161 // unlike username_element, other_possible_usernames is used only for |
139 // autofill, not for form identification, and blank autofill entries | 162 // autofill, not for form identification, and blank autofill entries |
140 // are not useful, so we do not collect empty strings. | 163 // are not useful, so we do not collect empty strings. |
141 if (!input_element->value().isEmpty()) | 164 if (!input_element->value().isEmpty()) |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 blink::WebFormControlElement(), | 262 blink::WebFormControlElement(), |
240 REQUIRE_NONE, | 263 REQUIRE_NONE, |
241 EXTRACT_NONE, | 264 EXTRACT_NONE, |
242 &password_form->form_data, | 265 &password_form->form_data, |
243 NULL /* FormFieldData */); | 266 NULL /* FormFieldData */); |
244 | 267 |
245 return password_form.Pass(); | 268 return password_form.Pass(); |
246 } | 269 } |
247 | 270 |
248 } // namespace autofill | 271 } // namespace autofill |
OLD | NEW |