Chromium Code Reviews| 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 16 matching lines...) Expand all Loading... | |
| 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 one, and which is | 37 // Helper to determine which password is the main (current) one, and which is |
| 38 // an old password (e.g on a "make new 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* password, |
| 41 WebInputElement* old_password) { | 41 WebInputElement* new_password) { |
| 42 switch (passwords.size()) { | 42 switch (passwords.size()) { |
| 43 case 1: | 43 case 1: |
| 44 // Single password, easy. | 44 // Single password, easy. |
| 45 *password = passwords[0]; | 45 *password = passwords[0]; |
| 46 break; | 46 break; |
| 47 case 2: | 47 case 2: |
| 48 if (passwords[0].value() == passwords[1].value()) { | 48 if (passwords[0].value() == passwords[1].value()) { |
| 49 // Treat two identical passwords as a single password. | 49 // Two identical passwords: assume we are seeing a new password with a |
| 50 *password = passwords[0]; | 50 // confirmation. This can be either a sign-up form or a password change |
| 51 // form that does not ask for the old password. | |
| 52 *new_password = passwords[0]; | |
| 51 } else { | 53 } else { |
| 52 // Assume first is old password, second is new (no choice but to guess). | 54 // Assume first is old password, second is new (no choice but to guess). |
| 53 *old_password = passwords[0]; | 55 *password = passwords[0]; |
| 54 *password = passwords[1]; | 56 *new_password = passwords[1]; |
| 55 } | 57 } |
| 56 break; | 58 break; |
| 57 case 3: | 59 case 3: |
| 58 if (passwords[0].value() == passwords[1].value() && | 60 if (!passwords[0].value().isEmpty() && |
|
engedy
2014/07/03 13:34:19
We have found a problem here that the set of eleme
| |
| 59 passwords[0].value() == passwords[2].value()) { | 61 (passwords[0].value() == passwords[1].value() && |
| 60 // All three passwords the same? Just treat as one and hope. | 62 passwords[0].value() == passwords[2].value())) { |
| 63 // All three passwords are the same and non-empty? This does not make | |
| 64 // any sense, give up. | |
| 65 return false; | |
| 66 } else if (passwords[1].value() == passwords[2].value()) { | |
| 67 // 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. | |
| 61 *password = passwords[0]; | 69 *password = passwords[0]; |
| 70 *new_password = passwords[1]; | |
| 62 } else if (passwords[0].value() == passwords[1].value()) { | 71 } else if (passwords[0].value() == passwords[1].value()) { |
|
engedy
2014/07/03 13:34:19
Note that this is also a behavior change.
| |
| 63 // Two the same and one different -> old password is duplicated one. | 72 // It is strange that the new password comes first, but trust more which |
| 64 *old_password = passwords[0]; | 73 // fields are duplicated than the ordering of fields. |
| 65 *password = passwords[2]; | 74 *password = passwords[2]; |
| 66 } else if (passwords[1].value() == passwords[2].value()) { | 75 *new_password = passwords[0]; |
| 67 *old_password = passwords[0]; | |
| 68 *password = passwords[1]; | |
| 69 } else { | 76 } else { |
| 70 // Three different passwords, or first and last match with middle | 77 // Three different passwords, or first and last match with middle |
| 71 // different. No idea which is which, so no luck. | 78 // different. No idea which is which, so no luck. |
| 72 return false; | 79 return false; |
| 73 } | 80 } |
| 74 break; | 81 break; |
| 75 default: | 82 default: |
| 76 return false; | 83 return false; |
| 77 } | 84 } |
| 78 return true; | 85 return true; |
| 79 } | 86 } |
| 80 | 87 |
| 81 // Get information about a login form that encapsulated in the | 88 // Get information about a login form encapsulated in a PasswordForm struct. |
| 82 // PasswordForm struct. | |
| 83 void GetPasswordForm(const WebFormElement& form, PasswordForm* password_form) { | 89 void GetPasswordForm(const WebFormElement& form, PasswordForm* password_form) { |
| 84 WebInputElement latest_input_element; | 90 WebInputElement latest_input_element; |
| 85 WebInputElement username_element; | 91 WebInputElement username_element; |
| 86 // Caches whether |username_element| is marked with autocomplete='username'. | 92 // Caches whether |username_element| is marked with autocomplete='username'. |
| 87 // Needed for performance reasons to avoid recalculating this multiple times. | 93 // Needed for performance reasons to avoid recalculating this multiple times. |
| 88 bool has_seen_element_with_autocomplete_username_before = false; | 94 bool has_seen_element_with_autocomplete_username_before = false; |
| 89 std::vector<WebInputElement> passwords; | 95 std::vector<WebInputElement> passwords; |
| 90 std::vector<base::string16> other_possible_usernames; | 96 std::vector<base::string16> other_possible_usernames; |
| 91 | 97 |
| 92 WebVector<WebFormControlElement> control_elements; | 98 WebVector<WebFormControlElement> control_elements; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 } | 167 } |
| 162 } | 168 } |
| 163 } | 169 } |
| 164 } | 170 } |
| 165 | 171 |
| 166 if (!username_element.isNull()) { | 172 if (!username_element.isNull()) { |
| 167 password_form->username_element = username_element.nameForAutofill(); | 173 password_form->username_element = username_element.nameForAutofill(); |
| 168 password_form->username_value = username_element.value(); | 174 password_form->username_value = username_element.value(); |
| 169 } | 175 } |
| 170 | 176 |
| 177 if (!username_element.isNull()) { | |
| 178 password_form->username_element = username_element.nameForAutofill(); | |
| 179 password_form->username_value = username_element.value(); | |
| 180 } | |
| 181 | |
| 171 // Get the document URL | 182 // Get the document URL |
| 172 GURL full_origin(form.document().url()); | 183 GURL full_origin(form.document().url()); |
| 173 | 184 |
| 174 // Calculate the canonical action URL | 185 // Calculate the canonical action URL |
| 175 WebString action = form.action(); | 186 WebString action = form.action(); |
| 176 if (action.isNull()) | 187 if (action.isNull()) |
| 177 action = WebString(""); // missing 'action' attribute implies current URL | 188 action = WebString(""); // missing 'action' attribute implies current URL |
| 178 GURL full_action(form.document().completeURL(action)); | 189 GURL full_action(form.document().completeURL(action)); |
| 179 if (!full_action.is_valid()) | 190 if (!full_action.is_valid()) |
| 180 return; | 191 return; |
| 181 | 192 |
| 182 WebInputElement password; | 193 WebInputElement password; |
| 183 WebInputElement old_password; | 194 WebInputElement new_password; |
| 184 if (!LocateSpecificPasswords(passwords, &password, &old_password)) | 195 if (!LocateSpecificPasswords(passwords, &password, &new_password)) |
| 185 return; | 196 return; |
| 186 | 197 |
| 187 // We want to keep the path but strip any authentication data, as well as | 198 // We want to keep the path but strip any authentication data, as well as |
| 188 // query and ref portions of URL, for the form action and form origin. | 199 // query and ref portions of URL, for the form action and form origin. |
| 189 GURL::Replacements rep; | 200 GURL::Replacements rep; |
| 190 rep.ClearUsername(); | 201 rep.ClearUsername(); |
| 191 rep.ClearPassword(); | 202 rep.ClearPassword(); |
| 192 rep.ClearQuery(); | 203 rep.ClearQuery(); |
| 193 rep.ClearRef(); | 204 rep.ClearRef(); |
| 194 password_form->action = full_action.ReplaceComponents(rep); | 205 password_form->action = full_action.ReplaceComponents(rep); |
| 195 password_form->origin = full_origin.ReplaceComponents(rep); | 206 password_form->origin = full_origin.ReplaceComponents(rep); |
| 196 | 207 |
| 197 rep.SetPathStr(""); | 208 rep.SetPathStr(""); |
| 198 password_form->signon_realm = full_origin.ReplaceComponents(rep).spec(); | 209 password_form->signon_realm = full_origin.ReplaceComponents(rep).spec(); |
| 199 | 210 |
| 200 password_form->other_possible_usernames.swap(other_possible_usernames); | 211 password_form->other_possible_usernames.swap(other_possible_usernames); |
| 201 | 212 |
| 202 if (!password.isNull()) { | 213 if (!password.isNull()) { |
| 203 password_form->password_element = password.nameForAutofill(); | 214 password_form->password_element = password.nameForAutofill(); |
| 204 password_form->password_value = password.value(); | 215 password_form->password_value = password.value(); |
| 205 password_form->password_autocomplete_set = password.autoComplete(); | 216 password_form->password_autocomplete_set = password.autoComplete(); |
| 206 } | 217 } |
| 207 if (!old_password.isNull()) { | 218 if (!new_password.isNull()) { |
| 208 password_form->old_password_element = old_password.nameForAutofill(); | 219 password_form->new_password_element = new_password.nameForAutofill(); |
| 209 password_form->old_password_value = old_password.value(); | 220 password_form->new_password_value = new_password.value(); |
| 210 } | 221 } |
| 211 | 222 |
| 212 password_form->scheme = PasswordForm::SCHEME_HTML; | 223 password_form->scheme = PasswordForm::SCHEME_HTML; |
| 213 password_form->ssl_valid = false; | 224 password_form->ssl_valid = false; |
| 214 password_form->preferred = false; | 225 password_form->preferred = false; |
| 215 password_form->blacklisted_by_user = false; | 226 password_form->blacklisted_by_user = false; |
| 216 password_form->type = PasswordForm::TYPE_MANUAL; | 227 password_form->type = PasswordForm::TYPE_MANUAL; |
| 217 password_form->use_additional_authentication = false; | 228 password_form->use_additional_authentication = false; |
| 218 } | 229 } |
| 219 | 230 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 233 blink::WebFormControlElement(), | 244 blink::WebFormControlElement(), |
| 234 REQUIRE_NONE, | 245 REQUIRE_NONE, |
| 235 EXTRACT_NONE, | 246 EXTRACT_NONE, |
| 236 &password_form->form_data, | 247 &password_form->form_data, |
| 237 NULL /* FormFieldData */); | 248 NULL /* FormFieldData */); |
| 238 | 249 |
| 239 return password_form.Pass(); | 250 return password_form.Pass(); |
| 240 } | 251 } |
| 241 | 252 |
| 242 } // namespace autofill | 253 } // namespace autofill |
| OLD | NEW |