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
3 // found in the LICENSE file.
5 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
7 #include "components/autofill/content/renderer/form_autofill_util.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"
11 #include "third_party/WebKit/public/web/WebFormControlElement.h"
12 #include "third_party/WebKit/public/web/WebInputElement.h"
14 using blink::WebDocument;
15 using blink::WebFormControlElement;
16 using blink::WebFormElement;
17 using blink::WebInputElement;
18 using blink::WebString;
19 using blink::WebVector;
24 // Maximum number of password fields we will observe before throwing our
25 // hands in the air and giving up with a given form.
26 static const size_t kMaxPasswords = 3;
28 // Helper to determine which password is the main one, and which is
29 // an old password (e.g on a "make new password" form), if any.
30 bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
31 WebInputElement* password,
32 WebInputElement* old_password) {
33 switch (passwords.size()) {
35 // Single password, easy.
36 *password = passwords[0];
39 if (passwords[0].value() == passwords[1].value()) {
40 // Treat two identical passwords as a single password.
41 *password = passwords[0];
43 // Assume first is old password, second is new (no choice but to guess).
44 *old_password = passwords[0];
45 *password = passwords[1];
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];
61 // Three different passwords, or first and last match with middle
62 // different. No idea which is which, so no luck.
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;
79 WebVector<WebFormControlElement> control_elements;
80 form.getFormControlElements(control_elements);
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();
87 WebInputElement* input_element = toWebInputElement(&control_element);
88 if (!input_element || !input_element->isEnabled())
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);
104 passwords.push_back(*input_element);
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());
118 // Get the document URL
119 GURL full_origin(form.document().url());
121 // Calculate the canonical action URL
122 WebString action = form.action();
124 action = WebString(""); // missing 'action' attribute implies current URL
125 GURL full_action(form.document().completeURL(action));
126 if (!full_action.is_valid())
129 WebInputElement password;
130 WebInputElement old_password;
131 if (!LocateSpecificPasswords(passwords, &password, &old_password))
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;
141 password_form->action = full_action.ReplaceComponents(rep);
142 password_form->origin = full_origin.ReplaceComponents(rep);
145 password_form->signon_realm = full_origin.ReplaceComponents(rep).spec();
147 password_form->other_possible_usernames.swap(other_possible_usernames);
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();
154 if (!old_password.isNull()) {
155 password_form->old_password_element = old_password.nameForAutofill();
156 password_form->old_password_value = old_password.value();
159 password_form->scheme = PasswordForm::SCHEME_HTML;
160 password_form->ssl_valid = false;
161 password_form->preferred = false;
162 password_form->blacklisted_by_user = false;
163 password_form->type = PasswordForm::TYPE_MANUAL;
164 password_form->use_additional_authentication = false;
169 scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& web_form) {
170 if (web_form.isNull())
171 return scoped_ptr<PasswordForm>();
173 scoped_ptr<PasswordForm> password_form(new PasswordForm());
174 GetPasswordForm(web_form, password_form.get());
176 if (!password_form->action.is_valid())
177 return scoped_ptr<PasswordForm>();
179 WebFormElementToFormData(web_form,
180 blink::WebFormControlElement(),
183 &password_form->form_data,
184 NULL /* FormFieldData */);
186 return password_form.Pass();
189 } // namespace autofill