• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_autofill_agent.h"
6 
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/autofill/content/common/autofill_messages.h"
13 #include "components/autofill/content/renderer/form_autofill_util.h"
14 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
15 #include "components/autofill/core/common/form_field_data.h"
16 #include "components/autofill/core/common/password_autofill_util.h"
17 #include "components/autofill/core/common/password_form.h"
18 #include "components/autofill/core/common/password_form_fill_data.h"
19 #include "content/public/renderer/render_view.h"
20 #include "third_party/WebKit/public/platform/WebVector.h"
21 #include "third_party/WebKit/public/web/WebAutofillClient.h"
22 #include "third_party/WebKit/public/web/WebDocument.h"
23 #include "third_party/WebKit/public/web/WebElement.h"
24 #include "third_party/WebKit/public/web/WebFormElement.h"
25 #include "third_party/WebKit/public/web/WebFrame.h"
26 #include "third_party/WebKit/public/web/WebInputEvent.h"
27 #include "third_party/WebKit/public/web/WebNode.h"
28 #include "third_party/WebKit/public/web/WebNodeList.h"
29 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
30 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
31 #include "third_party/WebKit/public/web/WebView.h"
32 #include "ui/events/keycodes/keyboard_codes.h"
33 
34 namespace autofill {
35 namespace {
36 
37 // The size above which we stop triggering autocomplete.
38 static const size_t kMaximumTextSizeForAutocomplete = 1000;
39 
40 // Maps element names to the actual elements to simplify form filling.
41 typedef std::map<base::string16, blink::WebInputElement>
42     FormInputElementMap;
43 
44 // Utility struct for form lookup and autofill. When we parse the DOM to look up
45 // a form, in addition to action and origin URL's we have to compare all
46 // necessary form elements. To avoid having to look these up again when we want
47 // to fill the form, the FindFormElements function stores the pointers
48 // in a FormElements* result, referenced to ensure they are safe to use.
49 struct FormElements {
50   blink::WebFormElement form_element;
51   FormInputElementMap input_elements;
52 };
53 
54 typedef std::vector<FormElements*> FormElementsList;
55 
56 // Helper to search the given form element for the specified input elements
57 // in |data|, and add results to |result|.
FindFormInputElements(blink::WebFormElement * fe,const FormData & data,FormElements * result)58 static bool FindFormInputElements(blink::WebFormElement* fe,
59                                   const FormData& data,
60                                   FormElements* result) {
61   // Loop through the list of elements we need to find on the form in order to
62   // autofill it. If we don't find any one of them, abort processing this
63   // form; it can't be the right one.
64   for (size_t j = 0; j < data.fields.size(); j++) {
65     blink::WebVector<blink::WebNode> temp_elements;
66     fe->getNamedElements(data.fields[j].name, temp_elements);
67 
68     // Match the first input element, if any.
69     // |getNamedElements| may return non-input elements where the names match,
70     // so the results are filtered for input elements.
71     // If more than one match is made, then we have ambiguity (due to misuse
72     // of "name" attribute) so is it considered not found.
73     bool found_input = false;
74     for (size_t i = 0; i < temp_elements.size(); ++i) {
75       if (temp_elements[i].to<blink::WebElement>().hasTagName("input")) {
76         // Check for a non-unique match.
77         if (found_input) {
78           found_input = false;
79           break;
80         }
81 
82         // Only fill saved passwords into password fields and usernames into
83         // text fields.
84         blink::WebInputElement input_element =
85             temp_elements[i].to<blink::WebInputElement>();
86         if (input_element.isPasswordField() !=
87             (data.fields[j].form_control_type == "password"))
88           continue;
89 
90         // This element matched, add it to our temporary result. It's possible
91         // there are multiple matches, but for purposes of identifying the form
92         // one suffices and if some function needs to deal with multiple
93         // matching elements it can get at them through the FormElement*.
94         // Note: This assignment adds a reference to the InputElement.
95         result->input_elements[data.fields[j].name] = input_element;
96         found_input = true;
97       }
98     }
99 
100     // A required element was not found. This is not the right form.
101     // Make sure no input elements from a partially matched form in this
102     // iteration remain in the result set.
103     // Note: clear will remove a reference from each InputElement.
104     if (!found_input) {
105       result->input_elements.clear();
106       return false;
107     }
108   }
109   return true;
110 }
111 
112 // Helper to locate form elements identified by |data|.
FindFormElements(blink::WebView * view,const FormData & data,FormElementsList * results)113 void FindFormElements(blink::WebView* view,
114                       const FormData& data,
115                       FormElementsList* results) {
116   DCHECK(view);
117   DCHECK(results);
118   blink::WebFrame* main_frame = view->mainFrame();
119   if (!main_frame)
120     return;
121 
122   GURL::Replacements rep;
123   rep.ClearQuery();
124   rep.ClearRef();
125 
126   // Loop through each frame.
127   for (blink::WebFrame* f = main_frame; f; f = f->traverseNext(false)) {
128     blink::WebDocument doc = f->document();
129     if (!doc.isHTMLDocument())
130       continue;
131 
132     GURL full_origin(doc.url());
133     if (data.origin != full_origin.ReplaceComponents(rep))
134       continue;
135 
136     blink::WebVector<blink::WebFormElement> forms;
137     doc.forms(forms);
138 
139     for (size_t i = 0; i < forms.size(); ++i) {
140       blink::WebFormElement fe = forms[i];
141 
142       GURL full_action(f->document().completeURL(fe.action()));
143       if (full_action.is_empty()) {
144         // The default action URL is the form's origin.
145         full_action = full_origin;
146       }
147 
148       // Action URL must match.
149       if (data.action != full_action.ReplaceComponents(rep))
150         continue;
151 
152       scoped_ptr<FormElements> curr_elements(new FormElements);
153       if (!FindFormInputElements(&fe, data, curr_elements.get()))
154         continue;
155 
156       // We found the right element.
157       // Note: this assignment adds a reference to |fe|.
158       curr_elements->form_element = fe;
159       results->push_back(curr_elements.release());
160     }
161   }
162 }
163 
IsElementEditable(const blink::WebInputElement & element)164 bool IsElementEditable(const blink::WebInputElement& element) {
165   return element.isEnabled() && !element.isReadOnly();
166 }
167 
SetElementAutofilled(blink::WebInputElement * element,bool autofilled)168 void SetElementAutofilled(blink::WebInputElement* element, bool autofilled) {
169   if (element->isAutofilled() == autofilled)
170     return;
171   element->setAutofilled(autofilled);
172   // Notify any changeEvent listeners.
173   element->dispatchFormControlChangeEvent();
174 }
175 
DoUsernamesMatch(const base::string16 & username1,const base::string16 & username2,bool exact_match)176 bool DoUsernamesMatch(const base::string16& username1,
177                       const base::string16& username2,
178                       bool exact_match) {
179   if (exact_match)
180     return username1 == username2;
181   return StartsWith(username1, username2, true);
182 }
183 
184 }  // namespace
185 
186 ////////////////////////////////////////////////////////////////////////////////
187 // PasswordAutofillAgent, public:
188 
PasswordAutofillAgent(content::RenderView * render_view)189 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
190     : content::RenderViewObserver(render_view),
191       usernames_usage_(NOTHING_TO_AUTOFILL),
192       web_view_(render_view->GetWebView()),
193       weak_ptr_factory_(this) {
194 }
195 
~PasswordAutofillAgent()196 PasswordAutofillAgent::~PasswordAutofillAgent() {
197 }
198 
TextFieldDidEndEditing(const blink::WebInputElement & element)199 bool PasswordAutofillAgent::TextFieldDidEndEditing(
200     const blink::WebInputElement& element) {
201   LoginToPasswordInfoMap::const_iterator iter =
202       login_to_password_info_.find(element);
203   if (iter == login_to_password_info_.end())
204     return false;
205 
206   const PasswordFormFillData& fill_data =
207       iter->second.fill_data;
208 
209   // If wait_for_username is false, we should have filled when the text changed.
210   if (!fill_data.wait_for_username)
211     return false;
212 
213   blink::WebInputElement password = iter->second.password_field;
214   if (!IsElementEditable(password))
215     return false;
216 
217   blink::WebInputElement username = element;  // We need a non-const.
218 
219   // Do not set selection when ending an editing session, otherwise it can
220   // mess with focus.
221   FillUserNameAndPassword(&username, &password, fill_data,
222                           true /* exact_username_match */,
223                           false /* set_selection */);
224   return true;
225 }
226 
TextDidChangeInTextField(const blink::WebInputElement & element)227 bool PasswordAutofillAgent::TextDidChangeInTextField(
228     const blink::WebInputElement& element) {
229   LoginToPasswordInfoMap::const_iterator iter =
230       login_to_password_info_.find(element);
231   if (iter == login_to_password_info_.end())
232     return false;
233 
234   // The input text is being changed, so any autofilled password is now
235   // outdated.
236   blink::WebInputElement username = element;  // We need a non-const.
237   blink::WebInputElement password = iter->second.password_field;
238   SetElementAutofilled(&username, false);
239   if (password.isAutofilled()) {
240     password.setValue(base::string16());
241     SetElementAutofilled(&password, false);
242   }
243 
244   // If wait_for_username is true we will fill when the username loses focus.
245   if (iter->second.fill_data.wait_for_username)
246     return false;
247 
248   if (!IsElementEditable(element) || !element.isText() ||
249       (!ShouldIgnoreAutocompleteOffForPasswordFields() &&
250        !element.autoComplete())) {
251     return false;
252   }
253 
254   // Don't inline autocomplete if the user is deleting, that would be confusing.
255   // But refresh the popup.  Note, since this is ours, return true to signal
256   // no further processing is required.
257   if (iter->second.backspace_pressed_last) {
258     ShowSuggestionPopup(iter->second.fill_data, username);
259     return true;
260   }
261 
262   blink::WebString name = element.nameForAutofill();
263   if (name.isEmpty())
264     return false;  // If the field has no name, then we won't have values.
265 
266   // Don't attempt to autofill with values that are too large.
267   if (element.value().length() > kMaximumTextSizeForAutocomplete)
268     return false;
269 
270   // The caret position should have already been updated.
271   PerformInlineAutocomplete(element, password, iter->second.fill_data);
272   return true;
273 }
274 
TextFieldHandlingKeyDown(const blink::WebInputElement & element,const blink::WebKeyboardEvent & event)275 bool PasswordAutofillAgent::TextFieldHandlingKeyDown(
276     const blink::WebInputElement& element,
277     const blink::WebKeyboardEvent& event) {
278   // If using the new Autofill UI that lives in the browser, it will handle
279   // keypresses before this function. This is not currently an issue but if
280   // the keys handled there or here change, this issue may appear.
281 
282   LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element);
283   if (iter == login_to_password_info_.end())
284     return false;
285 
286   int win_key_code = event.windowsKeyCode;
287   iter->second.backspace_pressed_last =
288       (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE);
289   return true;
290 }
291 
DidAcceptAutofillSuggestion(const blink::WebNode & node,const blink::WebString & username)292 bool PasswordAutofillAgent::DidAcceptAutofillSuggestion(
293     const blink::WebNode& node,
294     const blink::WebString& username) {
295   blink::WebInputElement input;
296   PasswordInfo password;
297   if (!FindLoginInfo(node, &input, &password))
298     return false;
299 
300   // Set the incoming |username| in the text field and |FillUserNameAndPassword|
301   // will do the rest.
302   input.setValue(username, true);
303   return FillUserNameAndPassword(&input, &password.password_field,
304                                  password.fill_data,
305                                  true /* exact_username_match */,
306                                  true /* set_selection */);
307 }
308 
DidClearAutofillSelection(const blink::WebNode & node)309 bool PasswordAutofillAgent::DidClearAutofillSelection(
310     const blink::WebNode& node) {
311   blink::WebInputElement input;
312   PasswordInfo password;
313   return FindLoginInfo(node, &input, &password);
314 }
315 
ShowSuggestions(const blink::WebInputElement & element)316 bool PasswordAutofillAgent::ShowSuggestions(
317     const blink::WebInputElement& element) {
318   LoginToPasswordInfoMap::const_iterator iter =
319       login_to_password_info_.find(element);
320   if (iter == login_to_password_info_.end())
321     return false;
322 
323   return ShowSuggestionPopup(iter->second.fill_data, element);
324 }
325 
OriginCanAccessPasswordManager(const blink::WebSecurityOrigin & origin)326 bool PasswordAutofillAgent::OriginCanAccessPasswordManager(
327     const blink::WebSecurityOrigin& origin) {
328   return origin.canAccessPasswordManager();
329 }
330 
OnDynamicFormsSeen(blink::WebFrame * frame)331 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) {
332   SendPasswordForms(frame, false /* only_visible */);
333 }
334 
SendPasswordForms(blink::WebFrame * frame,bool only_visible)335 void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame,
336                                               bool only_visible) {
337   // Make sure that this security origin is allowed to use password manager.
338   blink::WebSecurityOrigin origin = frame->document().securityOrigin();
339   if (!OriginCanAccessPasswordManager(origin))
340     return;
341 
342   // Checks whether the webpage is a redirect page or an empty page.
343   if (IsWebpageEmpty(frame))
344     return;
345 
346   blink::WebVector<blink::WebFormElement> forms;
347   frame->document().forms(forms);
348 
349   std::vector<PasswordForm> password_forms;
350   for (size_t i = 0; i < forms.size(); ++i) {
351     const blink::WebFormElement& form = forms[i];
352 
353     // If requested, ignore non-rendered forms, e.g. those styled with
354     // display:none.
355     if (only_visible && !IsWebNodeVisible(form))
356       continue;
357 
358     scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
359     if (password_form.get())
360       password_forms.push_back(*password_form);
361   }
362 
363   if (password_forms.empty() && !only_visible) {
364     // We need to send the PasswordFormsRendered message regardless of whether
365     // there are any forms visible, as this is also the code path that triggers
366     // showing the infobar.
367     return;
368   }
369 
370   if (only_visible) {
371     Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(),
372                                                    password_forms));
373   } else {
374     Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms));
375   }
376 }
377 
OnMessageReceived(const IPC::Message & message)378 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) {
379   bool handled = true;
380   IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message)
381     IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm)
382     IPC_MESSAGE_UNHANDLED(handled = false)
383   IPC_END_MESSAGE_MAP()
384   return handled;
385 }
386 
DidStartLoading()387 void PasswordAutofillAgent::DidStartLoading() {
388   if (usernames_usage_ != NOTHING_TO_AUTOFILL) {
389     UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage",
390                               usernames_usage_, OTHER_POSSIBLE_USERNAMES_MAX);
391     usernames_usage_ = NOTHING_TO_AUTOFILL;
392   }
393 }
394 
DidFinishDocumentLoad(blink::WebFrame * frame)395 void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebFrame* frame) {
396   // The |frame| contents have been parsed, but not yet rendered.  Let the
397   // PasswordManager know that forms are loaded, even though we can't yet tell
398   // whether they're visible.
399   SendPasswordForms(frame, false);
400 }
401 
DidFinishLoad(blink::WebFrame * frame)402 void PasswordAutofillAgent::DidFinishLoad(blink::WebFrame* frame) {
403   // The |frame| contents have been rendered.  Let the PasswordManager know
404   // which of the loaded frames are actually visible to the user.  This also
405   // triggers the "Save password?" infobar if the user just submitted a password
406   // form.
407   SendPasswordForms(frame, true);
408 }
409 
FrameDetached(blink::WebFrame * frame)410 void PasswordAutofillAgent::FrameDetached(blink::WebFrame* frame) {
411   FrameClosing(frame);
412 }
413 
FrameWillClose(blink::WebFrame * frame)414 void PasswordAutofillAgent::FrameWillClose(blink::WebFrame* frame) {
415   FrameClosing(frame);
416 }
417 
WillSendSubmitEvent(blink::WebFrame * frame,const blink::WebFormElement & form)418 void PasswordAutofillAgent::WillSendSubmitEvent(
419     blink::WebFrame* frame,
420     const blink::WebFormElement& form) {
421   // Some login forms have onSubmit handlers that put a hash of the password
422   // into a hidden field and then clear the password (http://crbug.com/28910).
423   // This method gets called before any of those handlers run, so save away
424   // a copy of the password in case it gets lost.
425   scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
426   if (password_form)
427     provisionally_saved_forms_[frame].reset(password_form.release());
428 }
429 
WillSubmitForm(blink::WebFrame * frame,const blink::WebFormElement & form)430 void PasswordAutofillAgent::WillSubmitForm(blink::WebFrame* frame,
431                                            const blink::WebFormElement& form) {
432   scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form);
433 
434   // If there is a provisionally saved password, copy over the previous
435   // password value so we get the user's typed password, not the value that
436   // may have been transformed for submit.
437   // TODO(gcasto): Do we need to have this action equality check? Is it trying
438   // to prevent accidentally copying over passwords from a different form?
439   if (submitted_form) {
440     if (provisionally_saved_forms_[frame].get() &&
441         submitted_form->action == provisionally_saved_forms_[frame]->action) {
442       submitted_form->password_value =
443           provisionally_saved_forms_[frame]->password_value;
444     }
445 
446     // Some observers depend on sending this information now instead of when
447     // the frame starts loading. If there are redirects that cause a new
448     // RenderView to be instantiated (such as redirects to the WebStore)
449     // we will never get to finish the load.
450     Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
451                                                    *submitted_form));
452     // Remove reference since we have already submitted this form.
453     provisionally_saved_forms_.erase(frame);
454   }
455 }
456 
CurrentOrChildFrameWithSavedForms(const blink::WebFrame * current_frame)457 blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms(
458     const blink::WebFrame* current_frame) {
459   for (FrameToPasswordFormMap::const_iterator it =
460            provisionally_saved_forms_.begin();
461        it != provisionally_saved_forms_.end();
462        ++it) {
463     blink::WebFrame* form_frame = it->first;
464     // The check that the returned frame is related to |current_frame| is mainly
465     // for double-checking. There should not be any unrelated frames in
466     // |provisionally_saved_forms_|, because the map is cleared after
467     // navigation. If there are reasons to remove this check in the future and
468     // keep just the first frame found, it might be a good idea to add a UMA
469     // statistic or a similar check on how many frames are here to choose from.
470     if (current_frame == form_frame ||
471         current_frame->findChildByName(form_frame->uniqueName())) {
472       return form_frame;
473     }
474   }
475   return NULL;
476 }
477 
DidStartProvisionalLoad(blink::WebFrame * frame)478 void PasswordAutofillAgent::DidStartProvisionalLoad(blink::WebFrame* frame) {
479   if (!frame->parent()) {
480     // If the navigation is not triggered by a user gesture, e.g. by some ajax
481     // callback, then inherit the submitted password form from the previous
482     // state. This fixes the no password save issue for ajax login, tracked in
483     // [http://crbug/43219]. Note that there are still some sites that this
484     // fails for because they use some element other than a submit button to
485     // trigger submission (which means WillSendSubmitEvent will not be called).
486     blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame);
487     if (!blink::WebUserGestureIndicator::isProcessingUserGesture() &&
488         provisionally_saved_forms_[form_frame].get()) {
489       Send(new AutofillHostMsg_PasswordFormSubmitted(
490           routing_id(),
491           *provisionally_saved_forms_[form_frame]));
492       provisionally_saved_forms_.erase(form_frame);
493     }
494     // Clear the whole map during main frame navigation.
495     provisionally_saved_forms_.clear();
496   }
497 }
498 
OnFillPasswordForm(const PasswordFormFillData & form_data)499 void PasswordAutofillAgent::OnFillPasswordForm(
500     const PasswordFormFillData& form_data) {
501   if (usernames_usage_ == NOTHING_TO_AUTOFILL) {
502     if (form_data.other_possible_usernames.size())
503       usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT;
504     else if (usernames_usage_ == NOTHING_TO_AUTOFILL)
505       usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT;
506   }
507 
508   FormElementsList forms;
509   // We own the FormElements* in forms.
510   FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms);
511   FormElementsList::iterator iter;
512   for (iter = forms.begin(); iter != forms.end(); ++iter) {
513     scoped_ptr<FormElements> form_elements(*iter);
514 
515     // Attach autocomplete listener to enable selecting alternate logins.
516     // First, get pointers to username element.
517     blink::WebInputElement username_element =
518         form_elements->input_elements[form_data.basic_data.fields[0].name];
519 
520     // Get pointer to password element. (We currently only support single
521     // password forms).
522     blink::WebInputElement password_element =
523         form_elements->input_elements[form_data.basic_data.fields[1].name];
524 
525     // If wait_for_username is true, we don't want to initially fill the form
526     // until the user types in a valid username.
527     if (!form_data.wait_for_username)
528       FillFormOnPasswordRecieved(form_data, username_element, password_element);
529 
530     // We might have already filled this form if there are two <form> elements
531     // with identical markup.
532     if (login_to_password_info_.find(username_element) !=
533         login_to_password_info_.end())
534       continue;
535 
536     PasswordInfo password_info;
537     password_info.fill_data = form_data;
538     password_info.password_field = password_element;
539     login_to_password_info_[username_element] = password_info;
540 
541     FormData form;
542     FormFieldData field;
543     FindFormAndFieldForInputElement(
544         username_element, &form, &field, REQUIRE_NONE);
545     Send(new AutofillHostMsg_AddPasswordFormMapping(
546         routing_id(),
547         field,
548         form_data));
549   }
550 }
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 // PasswordAutofillAgent, private:
554 
GetSuggestions(const PasswordFormFillData & fill_data,const base::string16 & input,std::vector<base::string16> * suggestions,std::vector<base::string16> * realms)555 void PasswordAutofillAgent::GetSuggestions(
556     const PasswordFormFillData& fill_data,
557     const base::string16& input,
558     std::vector<base::string16>* suggestions,
559     std::vector<base::string16>* realms) {
560   if (StartsWith(fill_data.basic_data.fields[0].value, input, false)) {
561     suggestions->push_back(fill_data.basic_data.fields[0].value);
562     realms->push_back(UTF8ToUTF16(fill_data.preferred_realm));
563   }
564 
565   for (PasswordFormFillData::LoginCollection::const_iterator iter =
566            fill_data.additional_logins.begin();
567        iter != fill_data.additional_logins.end(); ++iter) {
568     if (StartsWith(iter->first, input, false)) {
569       suggestions->push_back(iter->first);
570       realms->push_back(UTF8ToUTF16(iter->second.realm));
571     }
572   }
573 
574   for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
575            fill_data.other_possible_usernames.begin();
576        iter != fill_data.other_possible_usernames.end(); ++iter) {
577     for (size_t i = 0; i < iter->second.size(); ++i) {
578       if (StartsWith(iter->second[i], input, false)) {
579         usernames_usage_ = OTHER_POSSIBLE_USERNAME_SHOWN;
580         suggestions->push_back(iter->second[i]);
581         realms->push_back(UTF8ToUTF16(iter->first.realm));
582       }
583     }
584   }
585 }
586 
ShowSuggestionPopup(const PasswordFormFillData & fill_data,const blink::WebInputElement & user_input)587 bool PasswordAutofillAgent::ShowSuggestionPopup(
588     const PasswordFormFillData& fill_data,
589     const blink::WebInputElement& user_input) {
590   blink::WebFrame* frame = user_input.document().frame();
591   if (!frame)
592     return false;
593 
594   blink::WebView* webview = frame->view();
595   if (!webview)
596     return false;
597 
598   std::vector<base::string16> suggestions;
599   std::vector<base::string16> realms;
600   GetSuggestions(fill_data, user_input.value(), &suggestions, &realms);
601   DCHECK_EQ(suggestions.size(), realms.size());
602 
603   FormData form;
604   FormFieldData field;
605   FindFormAndFieldForInputElement(
606       user_input, &form, &field, REQUIRE_NONE);
607 
608   blink::WebInputElement selected_element = user_input;
609   gfx::Rect bounding_box(selected_element.boundsInViewportSpace());
610 
611   float scale = web_view_->pageScaleFactor();
612   gfx::RectF bounding_box_scaled(bounding_box.x() * scale,
613                                  bounding_box.y() * scale,
614                                  bounding_box.width() * scale,
615                                  bounding_box.height() * scale);
616   Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(),
617                                                    field,
618                                                    bounding_box_scaled,
619                                                    suggestions,
620                                                    realms));
621   return !suggestions.empty();
622 }
623 
FillFormOnPasswordRecieved(const PasswordFormFillData & fill_data,blink::WebInputElement username_element,blink::WebInputElement password_element)624 void PasswordAutofillAgent::FillFormOnPasswordRecieved(
625     const PasswordFormFillData& fill_data,
626     blink::WebInputElement username_element,
627     blink::WebInputElement password_element) {
628   // Do not fill if the password field is in an iframe.
629   DCHECK(password_element.document().frame());
630   if (password_element.document().frame()->parent())
631     return;
632 
633   if (!ShouldIgnoreAutocompleteOffForPasswordFields() &&
634       !username_element.form().autoComplete())
635     return;
636 
637   // If we can't modify the password, don't try to set the username
638   if (!IsElementEditable(password_element) ||
639       (!ShouldIgnoreAutocompleteOffForPasswordFields() &&
640        !password_element.autoComplete()))
641     return;
642 
643   // Try to set the username to the preferred name, but only if the field
644   // can be set and isn't prefilled.
645   if (IsElementEditable(username_element) &&
646       (ShouldIgnoreAutocompleteOffForPasswordFields() ||
647        username_element.autoComplete()) &&
648       username_element.value().isEmpty()) {
649     // TODO(tkent): Check maxlength and pattern.
650     username_element.setValue(fill_data.basic_data.fields[0].value);
651   }
652 
653   // Fill if we have an exact match for the username. Note that this sets
654   // username to autofilled.
655   FillUserNameAndPassword(&username_element, &password_element, fill_data,
656                           true /* exact_username_match */,
657                           false /* set_selection */);
658 }
659 
FillUserNameAndPassword(blink::WebInputElement * username_element,blink::WebInputElement * password_element,const PasswordFormFillData & fill_data,bool exact_username_match,bool set_selection)660 bool PasswordAutofillAgent::FillUserNameAndPassword(
661     blink::WebInputElement* username_element,
662     blink::WebInputElement* password_element,
663     const PasswordFormFillData& fill_data,
664     bool exact_username_match,
665     bool set_selection) {
666   base::string16 current_username = username_element->value();
667   // username and password will contain the match found if any.
668   base::string16 username;
669   base::string16 password;
670 
671   // Look for any suitable matches to current field text.
672   if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, current_username,
673                        exact_username_match)) {
674     username = fill_data.basic_data.fields[0].value;
675     password = fill_data.basic_data.fields[1].value;
676   } else {
677     // Scan additional logins for a match.
678     PasswordFormFillData::LoginCollection::const_iterator iter;
679     for (iter = fill_data.additional_logins.begin();
680          iter != fill_data.additional_logins.end(); ++iter) {
681       if (DoUsernamesMatch(iter->first, current_username,
682                            exact_username_match)) {
683         username = iter->first;
684         password = iter->second.password;
685         break;
686       }
687     }
688 
689     // Check possible usernames.
690     if (username.empty() && password.empty()) {
691       for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
692                fill_data.other_possible_usernames.begin();
693            iter != fill_data.other_possible_usernames.end(); ++iter) {
694         for (size_t i = 0; i < iter->second.size(); ++i) {
695           if (DoUsernamesMatch(iter->second[i], current_username,
696                                exact_username_match)) {
697             usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
698             username = iter->second[i];
699             password = iter->first.password;
700             break;
701           }
702         }
703         if (!username.empty() && !password.empty())
704           break;
705       }
706     }
707   }
708   if (password.empty())
709     return false;  // No match was found.
710 
711   // TODO(tkent): Check maxlength and pattern for both username and password
712   // fields.
713 
714   // Don't fill username if password can't be set.
715   if (!IsElementEditable(*password_element) ||
716       (!ShouldIgnoreAutocompleteOffForPasswordFields() &&
717        !password_element->autoComplete())) {
718     return false;
719   }
720 
721   // Input matches the username, fill in required values.
722   if (IsElementEditable(*username_element) &&
723       (ShouldIgnoreAutocompleteOffForPasswordFields() ||
724        username_element->autoComplete())) {
725     username_element->setValue(username);
726     SetElementAutofilled(username_element, true);
727 
728     if (set_selection) {
729       username_element->setSelectionRange(current_username.length(),
730                                           username.length());
731     }
732   } else if (current_username != username) {
733     // If the username can't be filled and it doesn't match a saved password
734     // as is, don't autofill a password.
735     return false;
736   }
737 
738   password_element->setValue(password);
739   SetElementAutofilled(password_element, true);
740   return true;
741 }
742 
PerformInlineAutocomplete(const blink::WebInputElement & username_input,const blink::WebInputElement & password_input,const PasswordFormFillData & fill_data)743 void PasswordAutofillAgent::PerformInlineAutocomplete(
744     const blink::WebInputElement& username_input,
745     const blink::WebInputElement& password_input,
746     const PasswordFormFillData& fill_data) {
747   DCHECK(!fill_data.wait_for_username);
748 
749   // We need non-const versions of the username and password inputs.
750   blink::WebInputElement username = username_input;
751   blink::WebInputElement password = password_input;
752 
753   // Don't inline autocomplete if the caret is not at the end.
754   // TODO(jcivelli): is there a better way to test the caret location?
755   if (username.selectionStart() != username.selectionEnd() ||
756       username.selectionEnd() != static_cast<int>(username.value().length())) {
757     return;
758   }
759 
760   // Show the popup with the list of available usernames.
761   ShowSuggestionPopup(fill_data, username);
762 
763 
764 #if !defined(OS_ANDROID)
765   // Fill the user and password field with the most relevant match. Android
766   // only fills in the fields after the user clicks on the suggestion popup.
767   FillUserNameAndPassword(&username, &password, fill_data,
768                           false /* exact_username_match */,
769                           true /* set_selection */);
770 #endif
771 }
772 
FrameClosing(const blink::WebFrame * frame)773 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) {
774   for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin();
775        iter != login_to_password_info_.end();) {
776     if (iter->first.document().frame() == frame)
777       login_to_password_info_.erase(iter++);
778     else
779       ++iter;
780   }
781   for (FrameToPasswordFormMap::iterator iter =
782            provisionally_saved_forms_.begin();
783        iter != provisionally_saved_forms_.end();) {
784     if (iter->first == frame)
785       provisionally_saved_forms_.erase(iter++);
786     else
787       ++iter;
788   }
789 }
790 
FindLoginInfo(const blink::WebNode & node,blink::WebInputElement * found_input,PasswordInfo * found_password)791 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node,
792                                           blink::WebInputElement* found_input,
793                                           PasswordInfo* found_password) {
794   if (!node.isElementNode())
795     return false;
796 
797   blink::WebElement element = node.toConst<blink::WebElement>();
798   if (!element.hasTagName("input"))
799     return false;
800 
801   blink::WebInputElement input = element.to<blink::WebInputElement>();
802   LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input);
803   if (iter == login_to_password_info_.end())
804     return false;
805 
806   *found_input = input;
807   *found_password = iter->second;
808   return true;
809 }
810 
811 }  // namespace autofill
812