Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / components / autofill / content / renderer / password_form_conversion_utils.cc
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.
4
5 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
6
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"
13
14 using blink::WebDocument;
15 using blink::WebFormControlElement;
16 using blink::WebFormElement;
17 using blink::WebInputElement;
18 using blink::WebString;
19 using blink::WebVector;
20
21 namespace autofill {
22 namespace {
23
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;
27
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()) {
34     case 1:
35       // Single password, easy.
36       *password = passwords[0];
37       break;
38     case 2:
39       if (passwords[0].value() == passwords[1].value()) {
40         // Treat two identical passwords as a single password.
41         *password = passwords[0];
42       } else {
43         // Assume first is old password, second is new (no choice but to guess).
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
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;
165 }
166
167 }  // namespace
168
169 scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& web_form) {
170   if (web_form.isNull())
171     return scoped_ptr<PasswordForm>();
172
173   scoped_ptr<PasswordForm> password_form(new PasswordForm());
174   GetPasswordForm(web_form, password_form.get());
175
176   if (!password_form->action.is_valid())
177     return scoped_ptr<PasswordForm>();
178
179   WebFormElementToFormData(web_form,
180                            blink::WebFormControlElement(),
181                            REQUIRE_NONE,
182                            EXTRACT_NONE,
183                            &password_form->form_data,
184                            NULL /* FormFieldData */);
185
186   return password_form.Pass();
187 }
188
189 }  // namespace autofill