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