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/logging.h" | |
|
Garrett Casto
2014/04/16 22:56:55
I think that this is unnecessary.
| |
| 7 #include "components/autofill/content/renderer/form_autofill_util.h" | 8 #include "components/autofill/content/renderer/form_autofill_util.h" |
| 8 #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" | |
| 11 #include "third_party/WebKit/public/web/WebDocument.h" | |
| 9 #include "third_party/WebKit/public/web/WebFormControlElement.h" | 12 #include "third_party/WebKit/public/web/WebFormControlElement.h" |
| 10 #include "third_party/WebKit/public/web/WebPasswordFormData.h" | 13 #include "third_party/WebKit/public/web/WebInputElement.h" |
| 11 | 14 |
| 15 using blink::WebDocument; | |
| 16 using blink::WebFormControlElement; | |
| 12 using blink::WebFormElement; | 17 using blink::WebFormElement; |
| 13 using blink::WebPasswordFormData; | 18 using blink::WebInputElement; |
| 19 using blink::WebString; | |
| 20 using blink::WebVector; | |
| 14 | 21 |
| 15 namespace autofill { | 22 namespace autofill { |
| 16 namespace { | 23 namespace { |
| 17 | 24 |
| 25 // Maximum number of password fields we will observe before throwing our | |
| 26 // hands in the air and giving up with a given form. | |
| 27 static const size_t kMaxPasswords = 3; | |
| 28 | |
| 18 scoped_ptr<PasswordForm> InitPasswordFormFromWebPasswordForm( | 29 scoped_ptr<PasswordForm> InitPasswordFormFromWebPasswordForm( |
| 19 const WebFormElement& web_form, | 30 const WebFormElement& web_form, |
| 20 const blink::WebPasswordFormData& web_password_form) { | 31 PasswordForm* password_form) { |
| 21 PasswordForm* password_form = new PasswordForm(); | 32 GetPasswordForm(web_form, password_form); |
| 22 password_form->signon_realm = web_password_form.signonRealm.utf8(); | 33 |
| 23 password_form->origin = web_password_form.origin; | 34 if (!password_form->action.is_valid()) |
| 24 password_form->action = web_password_form.action; | 35 return scoped_ptr<PasswordForm>(); |
| 25 password_form->submit_element = web_password_form.submitElement; | 36 |
| 26 password_form->username_element = web_password_form.userNameElement; | |
| 27 password_form->username_value = web_password_form.userNameValue; | |
| 28 password_form->other_possible_usernames.insert( | |
| 29 password_form->other_possible_usernames.begin(), | |
| 30 web_password_form.possibleUserNames.data(), | |
| 31 web_password_form.possibleUserNames.data() + | |
| 32 web_password_form.possibleUserNames.size()); | |
| 33 password_form->password_element = web_password_form.passwordElement; | |
| 34 password_form->password_value = web_password_form.passwordValue; | |
| 35 password_form->password_autocomplete_set = | |
| 36 web_password_form.passwordShouldAutocomplete; | |
| 37 password_form->old_password_element = web_password_form.oldPasswordElement; | |
| 38 password_form->old_password_value = web_password_form.oldPasswordValue; | |
| 39 password_form->scheme = PasswordForm::SCHEME_HTML; | |
| 40 password_form->ssl_valid = false; | |
| 41 password_form->preferred = false; | |
| 42 password_form->blacklisted_by_user = false; | |
| 43 password_form->type = PasswordForm::TYPE_MANUAL; | |
| 44 password_form->use_additional_authentication = false; | |
| 45 WebFormElementToFormData(web_form, | 37 WebFormElementToFormData(web_form, |
| 46 blink::WebFormControlElement(), | 38 blink::WebFormControlElement(), |
| 47 REQUIRE_NONE, | 39 REQUIRE_NONE, |
| 48 EXTRACT_NONE, | 40 EXTRACT_NONE, |
| 49 &password_form->form_data, | 41 &password_form->form_data, |
| 50 NULL /* FormFieldData */); | 42 NULL /* FormFieldData */); |
| 51 return scoped_ptr<PasswordForm>(password_form); | 43 return scoped_ptr<PasswordForm>(password_form); |
| 52 } | 44 } |
| 53 | 45 |
| 46 // Helper to determine which password is the main one, and which is | |
| 47 // an old password (e.g on a "make new password" form), if any. | |
| 48 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords, | |
| 49 WebInputElement* password, | |
| 50 WebInputElement* old_password) | |
| 51 { | |
|
Garrett Casto
2014/04/16 22:56:55
In Chromium, starting braces don't get their own l
| |
| 52 switch (passwords.size()) { | |
| 53 case 1: | |
| 54 // Single password, easy. | |
| 55 *password = passwords[0]; | |
| 56 break; | |
| 57 case 2: | |
| 58 if (passwords[0].value() == passwords[1].value()) { | |
| 59 // Treat two identical passwords as a single password. | |
| 60 *password = passwords[0]; | |
| 61 } else { | |
| 62 // Assume first is old password, second is new (no choice but to guess). | |
| 63 *old_password = passwords[0]; | |
| 64 *password = passwords[1]; | |
| 65 } | |
| 66 break; | |
| 67 case 3: | |
| 68 if (passwords[0].value() == passwords[1].value() && | |
| 69 passwords[0].value() == passwords[2].value()) { | |
| 70 // All three passwords the same? Just treat as one and hope. | |
| 71 *password = passwords[0]; | |
| 72 } else if (passwords[0].value() == passwords[1].value()) { | |
| 73 // Two the same and one different -> old password is duplicated one. | |
| 74 *old_password = passwords[0]; | |
| 75 *password = passwords[2]; | |
| 76 } else if (passwords[1].value() == passwords[2].value()) { | |
| 77 *old_password = passwords[0]; | |
| 78 *password = passwords[1]; | |
| 79 } else { | |
| 80 // Three different passwords, or first and last match with middle | |
| 81 // different. No idea which is which, so no luck. | |
| 82 return false; | |
| 83 } | |
| 84 break; | |
| 85 default: | |
| 86 return false; | |
| 87 } | |
| 88 return true; | |
| 89 } | |
| 90 | |
| 54 } // namespace | 91 } // namespace |
| 55 | 92 |
| 56 scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& webform) { | 93 void GetPasswordForm(const WebFormElement& form, PasswordForm* password_form) |
| 57 WebPasswordFormData web_password_form(webform); | 94 { |
| 58 if (web_password_form.isValid()) | 95 WebInputElement latest_input_element; |
| 59 return InitPasswordFormFromWebPasswordForm(webform, web_password_form); | 96 std::vector<WebInputElement> passwords; |
| 60 return scoped_ptr<PasswordForm>(); | 97 std::vector<base::string16> other_possible_usernames; |
| 98 | |
| 99 WebVector<WebFormControlElement> control_elements; | |
| 100 form.getFormControlElements(control_elements); | |
| 101 | |
| 102 for (size_t i = 0; i < control_elements.size(); ++i) { | |
| 103 WebFormControlElement control_element = control_elements[i]; | |
| 104 if (control_element.isActivatedSubmit()) | |
| 105 password_form->submit_element = control_element.formControlName(); | |
| 106 | |
| 107 WebInputElement* input_element = toWebInputElement(&control_element); | |
| 108 if (!input_element) | |
| 109 continue; | |
| 110 | |
| 111 if (!input_element->isEnabled()) | |
|
Garrett Casto
2014/04/16 22:56:55
Nit: Can you merge this with the previous if state
| |
| 112 continue; | |
| 113 | |
| 114 if ((passwords.size() < kMaxPasswords) && | |
| 115 input_element->isPasswordField()) { | |
| 116 // We assume that the username element is the input element before the | |
| 117 // first password element. | |
| 118 if (passwords.empty() && !latest_input_element.isNull()) { | |
| 119 password_form->username_element = | |
| 120 latest_input_element.nameForAutofill(); | |
| 121 password_form->username_value = latest_input_element.value(); | |
| 122 // Remove the selected username from other_possible_usernames. | |
| 123 if (!other_possible_usernames.empty() && | |
| 124 !latest_input_element.value().isEmpty()) | |
| 125 other_possible_usernames.resize(other_possible_usernames.size() - 1); | |
| 126 } | |
| 127 passwords.push_back(*input_element); | |
| 128 } | |
| 129 | |
| 130 // Various input types such as text, url, email can be a username field. | |
| 131 if (input_element->isTextField() && !input_element->isPasswordField()) { | |
| 132 latest_input_element = *input_element; | |
| 133 // We ignore elements that have no value. Unlike username_element, | |
| 134 // other_possible_usernames is used only for autofill, not for form | |
| 135 // identification, and blank autofill entries are not useful. | |
| 136 if (!input_element->value().isEmpty()) | |
| 137 other_possible_usernames.push_back(input_element->value()); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 // Get the document URL | |
| 142 GURL full_origin(form.document().url()); | |
| 143 | |
| 144 // Calculate the canonical action URL | |
| 145 WebString action = form.action(); | |
| 146 if (action.isNull()) | |
| 147 action = WebString(""); // missing 'action' attribute implies current URL | |
| 148 GURL full_action(form.document().completeURL(action)); | |
| 149 if (!full_action.is_valid()) | |
| 150 return; | |
| 151 | |
| 152 // We want to keep the path but strip any authentication data, as well as | |
| 153 // query and ref portions of URL, for the form action and form origin. | |
| 154 GURL::Replacements rep; | |
| 155 rep.ClearUsername(); | |
| 156 rep.ClearPassword(); | |
| 157 rep.ClearQuery(); | |
| 158 rep.ClearRef(); | |
| 159 password_form->action = full_action.ReplaceComponents(rep); | |
|
Garrett Casto
2014/04/16 22:56:55
You don't want to do that here. Checking to see if
| |
| 160 password_form->origin = full_origin.ReplaceComponents(rep); | |
| 161 | |
| 162 rep.SetPathStr(""); | |
| 163 password_form->signon_realm = full_origin.ReplaceComponents(rep).spec(); | |
| 164 | |
| 165 password_form->other_possible_usernames.insert( | |
|
Garrett Casto
2014/04/16 22:56:55
Inserting in this way was only necessary because t
| |
| 166 password_form->other_possible_usernames.begin(), | |
| 167 other_possible_usernames.data(), | |
| 168 other_possible_usernames.data() + | |
| 169 other_possible_usernames.size()); | |
| 170 | |
| 171 WebInputElement password; | |
| 172 WebInputElement old_password; | |
| 173 if (!LocateSpecificPasswords(passwords, &password, &old_password)) | |
| 174 return; | |
| 175 | |
| 176 if (!password.isNull()) { | |
| 177 password_form->password_element = password.nameForAutofill(); | |
| 178 password_form->password_value = password.value(); | |
| 179 password_form->password_autocomplete_set = password.autoComplete(); | |
| 180 } | |
| 181 if (!old_password.isNull()) { | |
| 182 password_form->old_password_element = old_password.nameForAutofill(); | |
| 183 password_form->old_password_value = old_password.value(); | |
| 184 } | |
| 185 | |
| 186 password_form->scheme = PasswordForm::SCHEME_HTML; | |
| 187 password_form->ssl_valid = false; | |
| 188 password_form->preferred = false; | |
| 189 password_form->blacklisted_by_user = false; | |
| 190 password_form->type = PasswordForm::TYPE_MANUAL; | |
| 191 password_form->use_additional_authentication = false; | |
| 61 } | 192 } |
| 62 | 193 |
| 63 } // namespace autofill | 194 scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& web_form) { |
| 195 if (web_form.isNull()) | |
| 196 return scoped_ptr<PasswordForm>(); | |
| 197 | |
| 198 PasswordForm* password_form = new PasswordForm(); | |
| 199 return InitPasswordFormFromWebPasswordForm(web_form, password_form); | |
| 200 } | |
| 201 | |
| 202 } // namespace autofill | |
| OLD | NEW |