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_autofill_agent.h" | 5 #include "components/autofill/content/renderer/password_autofill_agent.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 curr_elements->form_element = fe; | 157 curr_elements->form_element = fe; |
| 158 results->push_back(curr_elements.release()); | 158 results->push_back(curr_elements.release()); |
| 159 } | 159 } |
| 160 } | 160 } |
| 161 } | 161 } |
| 162 | 162 |
| 163 bool IsElementEditable(const WebKit::WebInputElement& element) { | 163 bool IsElementEditable(const WebKit::WebInputElement& element) { |
| 164 return element.isEnabled() && !element.isReadOnly(); | 164 return element.isEnabled() && !element.isReadOnly(); |
| 165 } | 165 } |
| 166 | 166 |
| 167 void FillForm(FormElements* fe, const FormData& data) { | |
| 168 if (!fe->form_element.autoComplete()) | |
| 169 return; | |
| 170 | |
| 171 std::map<base::string16, base::string16> data_map; | |
| 172 for (size_t i = 0; i < data.fields.size(); i++) | |
| 173 data_map[data.fields[i].name] = data.fields[i].value; | |
| 174 | |
| 175 for (FormInputElementMap::iterator it = fe->input_elements.begin(); | |
| 176 it != fe->input_elements.end(); ++it) { | |
| 177 WebKit::WebInputElement element = it->second; | |
| 178 // Don't fill a form that has pre-filled values distinct from the ones we | |
| 179 // want to fill with. | |
| 180 if (!element.value().isEmpty() && element.value() != data_map[it->first]) | |
| 181 return; | |
| 182 | |
| 183 // Don't fill forms with uneditable fields or fields with autocomplete | |
| 184 // disabled. | |
| 185 if (!IsElementEditable(element) || !element.autoComplete()) | |
| 186 return; | |
| 187 } | |
| 188 | |
| 189 for (FormInputElementMap::iterator it = fe->input_elements.begin(); | |
| 190 it != fe->input_elements.end(); ++it) { | |
| 191 WebKit::WebInputElement element = it->second; | |
| 192 | |
| 193 // TODO(tkent): Check maxlength and pattern. | |
| 194 element.setValue(data_map[it->first]); | |
| 195 element.setAutofilled(true); | |
| 196 element.dispatchFormControlChangeEvent(); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 void SetElementAutofilled(WebKit::WebInputElement* element, bool autofilled) { | 167 void SetElementAutofilled(WebKit::WebInputElement* element, bool autofilled) { |
| 201 if (element->isAutofilled() == autofilled) | 168 if (element->isAutofilled() == autofilled) |
| 202 return; | 169 return; |
| 203 element->setAutofilled(autofilled); | 170 element->setAutofilled(autofilled); |
| 204 // Notify any changeEvent listeners. | 171 // Notify any changeEvent listeners. |
| 205 element->dispatchFormControlChangeEvent(); | 172 element->dispatchFormControlChangeEvent(); |
| 206 } | 173 } |
| 207 | 174 |
| 208 bool DoUsernamesMatch(const base::string16& username1, | 175 bool DoUsernamesMatch(const base::string16& username1, |
| 209 const base::string16& username2, | 176 const base::string16& username2, |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 509 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; | 476 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; |
| 510 } | 477 } |
| 511 | 478 |
| 512 FormElementsList forms; | 479 FormElementsList forms; |
| 513 // We own the FormElements* in forms. | 480 // We own the FormElements* in forms. |
| 514 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); | 481 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); |
| 515 FormElementsList::iterator iter; | 482 FormElementsList::iterator iter; |
| 516 for (iter = forms.begin(); iter != forms.end(); ++iter) { | 483 for (iter = forms.begin(); iter != forms.end(); ++iter) { |
| 517 scoped_ptr<FormElements> form_elements(*iter); | 484 scoped_ptr<FormElements> form_elements(*iter); |
| 518 | 485 |
| 519 // If wait_for_username is true, we don't want to initially fill the form | |
| 520 // until the user types in a valid username. | |
| 521 if (!form_data.wait_for_username) | |
| 522 FillForm(form_elements.get(), form_data.basic_data); | |
| 523 | |
| 524 // Attach autocomplete listener to enable selecting alternate logins. | 486 // Attach autocomplete listener to enable selecting alternate logins. |
| 525 // First, get pointers to username element. | 487 // First, get pointers to username element. |
| 526 WebKit::WebInputElement username_element = | 488 WebKit::WebInputElement username_element = |
| 527 form_elements->input_elements[form_data.basic_data.fields[0].name]; | 489 form_elements->input_elements[form_data.basic_data.fields[0].name]; |
| 528 | 490 |
| 529 // Get pointer to password element. (We currently only support single | 491 // Get pointer to password element. (We currently only support single |
| 530 // password forms). | 492 // password forms). |
| 531 WebKit::WebInputElement password_element = | 493 WebKit::WebInputElement password_element = |
| 532 form_elements->input_elements[form_data.basic_data.fields[1].name]; | 494 form_elements->input_elements[form_data.basic_data.fields[1].name]; |
| 533 | 495 |
| 496 // If wait_for_username is true, we don't want to initially fill the form | |
| 497 // until the user types in a valid username. | |
| 498 if (!form_data.wait_for_username) | |
| 499 FillFormOnPasswordRecieved(form_data, form_elements->form_element, | |
| 500 username_element, password_element); | |
|
Ilya Sherman
2013/11/04 23:10:48
nit: Please use curly braces to enclose the if-stm
Garrett Casto
2013/11/05 00:40:35
Do you know where this is spelled out? I was actua
Ilya Sherman
2013/11/05 01:25:11
The style guide is pretty flexible: "In general, c
| |
| 501 | |
| 534 // We might have already filled this form if there are two <form> elements | 502 // We might have already filled this form if there are two <form> elements |
| 535 // with identical markup. | 503 // with identical markup. |
| 536 if (login_to_password_info_.find(username_element) != | 504 if (login_to_password_info_.find(username_element) != |
| 537 login_to_password_info_.end()) | 505 login_to_password_info_.end()) |
| 538 continue; | 506 continue; |
| 539 | 507 |
| 540 PasswordInfo password_info; | 508 PasswordInfo password_info; |
| 541 password_info.fill_data = form_data; | 509 password_info.fill_data = form_data; |
| 542 password_info.password_field = password_element; | 510 password_info.password_field = password_element; |
| 543 login_to_password_info_[username_element] = password_info; | 511 login_to_password_info_[username_element] = password_info; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 618 bounding_box.width() * scale, | 586 bounding_box.width() * scale, |
| 619 bounding_box.height() * scale); | 587 bounding_box.height() * scale); |
| 620 Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(), | 588 Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(), |
| 621 field, | 589 field, |
| 622 bounding_box_scaled, | 590 bounding_box_scaled, |
| 623 suggestions, | 591 suggestions, |
| 624 realms)); | 592 realms)); |
| 625 return !suggestions.empty(); | 593 return !suggestions.empty(); |
| 626 } | 594 } |
| 627 | 595 |
| 596 void PasswordAutofillAgent::FillFormOnPasswordRecieved( | |
| 597 const PasswordFormFillData& fill_data, | |
| 598 const WebKit::WebFormElement& form_element, | |
| 599 WebKit::WebInputElement username_element, | |
| 600 WebKit::WebInputElement password_element) { | |
| 601 if (!form_element.autoComplete()) | |
| 602 return; | |
| 603 | |
| 604 // If we can't modify the password, don't try to set the username | |
| 605 if (!IsElementEditable(password_element) || !password_element.autoComplete()) | |
| 606 return; | |
| 607 | |
| 608 // Try and set the username to the preferred name, but only if the field | |
| 609 // can be set and isn't prefilled. | |
| 610 if (IsElementEditable(username_element) && | |
| 611 username_element.autoComplete() && | |
| 612 username_element.value().isEmpty()) { | |
| 613 username_element.setValue(fill_data.basic_data.fields[0].value); | |
|
Ilya Sherman
2013/11/04 23:10:48
What happened to setAutofilled(), dispatchFormCont
Garrett Casto
2013/11/05 00:40:35
The TODO got lost, I'll add it back somewhere. The
Ilya Sherman
2013/11/05 01:25:11
Ah, sorry, I didn't read the SetElementAutofilled
| |
| 614 } | |
| 615 | |
| 616 // Fill if we have an exact match for the username. | |
| 617 FillUserNameAndPassword(&username_element, &password_element, fill_data, | |
| 618 true, false); | |
|
Ilya Sherman
2013/11/04 23:10:48
nit: The semantics of "true" and "false" are reall
Garrett Casto
2013/11/05 00:40:35
Done with comments for now.
Ilya Sherman
2013/11/05 01:25:11
Thanks :)
| |
| 619 } | |
| 620 | |
| 628 bool PasswordAutofillAgent::FillUserNameAndPassword( | 621 bool PasswordAutofillAgent::FillUserNameAndPassword( |
| 629 WebKit::WebInputElement* username_element, | 622 WebKit::WebInputElement* username_element, |
| 630 WebKit::WebInputElement* password_element, | 623 WebKit::WebInputElement* password_element, |
| 631 const PasswordFormFillData& fill_data, | 624 const PasswordFormFillData& fill_data, |
| 632 bool exact_username_match, | 625 bool exact_username_match, |
| 633 bool set_selection) { | 626 bool set_selection) { |
| 634 base::string16 current_username = username_element->value(); | 627 base::string16 current_username = username_element->value(); |
| 635 // username and password will contain the match found if any. | 628 // username and password will contain the match found if any. |
| 636 base::string16 username; | 629 base::string16 username; |
| 637 base::string16 password; | 630 base::string16 password; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 670 } | 663 } |
| 671 if (!username.empty() && !password.empty()) | 664 if (!username.empty() && !password.empty()) |
| 672 break; | 665 break; |
| 673 } | 666 } |
| 674 } | 667 } |
| 675 } | 668 } |
| 676 if (password.empty()) | 669 if (password.empty()) |
| 677 return false; // No match was found. | 670 return false; // No match was found. |
| 678 | 671 |
| 679 // Input matches the username, fill in required values. | 672 // Input matches the username, fill in required values. |
| 680 username_element->setValue(username); | 673 username_element->setValue(username); |
|
Ilya Sherman
2013/11/04 23:10:48
Is this safe for a potentially non-modifiable elem
Garrett Casto
2013/11/05 00:40:35
Depends on what you mean by safe. There is nothing
Ilya Sherman
2013/11/05 01:25:11
I'm not convinced that it's safe to assume that th
Garrett Casto
2013/11/05 01:56:39
Fixed.
| |
| 681 | 674 |
| 682 if (set_selection) { | 675 if (set_selection) { |
| 683 username_element->setSelectionRange(current_username.length(), | 676 username_element->setSelectionRange(current_username.length(), |
| 684 username.length()); | 677 username.length()); |
| 685 } | 678 } |
| 686 | 679 |
| 687 SetElementAutofilled(username_element, true); | 680 SetElementAutofilled(username_element, true); |
|
Ilya Sherman
2013/11/04 23:10:48
Likewise, is this safe for a potentially non-modif
Garrett Casto
2013/11/05 00:40:35
Similar to above, though it looks like this curren
Ilya Sherman
2013/11/05 01:25:11
It looks like an oversight to me too. And it defi
Garrett Casto
2013/11/05 01:56:39
Fixed.
| |
| 688 if (IsElementEditable(*password_element)) | 681 if (IsElementEditable(*password_element)) |
| 689 password_element->setValue(password); | 682 password_element->setValue(password); |
| 690 SetElementAutofilled(password_element, true); | 683 SetElementAutofilled(password_element, true); |
| 691 return true; | 684 return true; |
| 692 } | 685 } |
| 693 | 686 |
| 694 void PasswordAutofillAgent::PerformInlineAutocomplete( | 687 void PasswordAutofillAgent::PerformInlineAutocomplete( |
| 695 const WebKit::WebInputElement& username_input, | 688 const WebKit::WebInputElement& username_input, |
| 696 const WebKit::WebInputElement& password_input, | 689 const WebKit::WebInputElement& password_input, |
| 697 const PasswordFormFillData& fill_data) { | 690 const PasswordFormFillData& fill_data) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); | 736 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); |
| 744 if (iter == login_to_password_info_.end()) | 737 if (iter == login_to_password_info_.end()) |
| 745 return false; | 738 return false; |
| 746 | 739 |
| 747 *found_input = input; | 740 *found_input = input; |
| 748 *found_password = iter->second; | 741 *found_password = iter->second; |
| 749 return true; | 742 return true; |
| 750 } | 743 } |
| 751 | 744 |
| 752 } // namespace autofill | 745 } // namespace autofill |
| OLD | NEW |