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

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

Issue 369323003: Implement autocomplete='current-password' and 'new-password'. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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 | Annotate | Revision Log
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 "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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698