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/command_line.h" | |
| 8 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 10 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 12 #include "components/autofill/content/common/autofill_messages.h" | 13 #include "components/autofill/content/common/autofill_messages.h" |
| 13 #include "components/autofill/content/renderer/form_autofill_util.h" | 14 #include "components/autofill/content/renderer/form_autofill_util.h" |
| 14 #include "components/autofill/content/renderer/password_form_conversion_utils.h" | 15 #include "components/autofill/content/renderer/password_form_conversion_utils.h" |
| 15 #include "components/autofill/content/renderer/renderer_save_password_progress_l ogger.h" | 16 #include "components/autofill/content/renderer/renderer_save_password_progress_l ogger.h" |
| 17 #include "components/autofill/core/common/autofill_switches.h" | |
| 16 #include "components/autofill/core/common/form_field_data.h" | 18 #include "components/autofill/core/common/form_field_data.h" |
| 17 #include "components/autofill/core/common/password_autofill_util.h" | 19 #include "components/autofill/core/common/password_autofill_util.h" |
| 18 #include "components/autofill/core/common/password_form.h" | 20 #include "components/autofill/core/common/password_form.h" |
| 19 #include "components/autofill/core/common/password_form_fill_data.h" | 21 #include "components/autofill/core/common/password_form_fill_data.h" |
| 20 #include "content/public/common/page_transition_types.h" | 22 #include "content/public/common/page_transition_types.h" |
| 21 #include "content/public/renderer/document_state.h" | 23 #include "content/public/renderer/document_state.h" |
| 22 #include "content/public/renderer/navigation_state.h" | 24 #include "content/public/renderer/navigation_state.h" |
| 23 #include "content/public/renderer/render_view.h" | 25 #include "content/public/renderer/render_view.h" |
| 24 #include "third_party/WebKit/public/platform/WebVector.h" | 26 #include "third_party/WebKit/public/platform/WebVector.h" |
| 25 #include "third_party/WebKit/public/web/WebAutofillClient.h" | 27 #include "third_party/WebKit/public/web/WebAutofillClient.h" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 55 // necessary form elements. To avoid having to look these up again when we want | 57 // necessary form elements. To avoid having to look these up again when we want |
| 56 // to fill the form, the FindFormElements function stores the pointers | 58 // to fill the form, the FindFormElements function stores the pointers |
| 57 // in a FormElements* result, referenced to ensure they are safe to use. | 59 // in a FormElements* result, referenced to ensure they are safe to use. |
| 58 struct FormElements { | 60 struct FormElements { |
| 59 blink::WebFormElement form_element; | 61 blink::WebFormElement form_element; |
| 60 FormInputElementMap input_elements; | 62 FormInputElementMap input_elements; |
| 61 }; | 63 }; |
| 62 | 64 |
| 63 typedef std::vector<FormElements*> FormElementsList; | 65 typedef std::vector<FormElements*> FormElementsList; |
| 64 | 66 |
| 67 bool ShouldFillOnAccountSelect() { | |
| 68 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 69 switches::kEnableFillOnAccountSelect)) { | |
| 70 return true; | |
| 71 } | |
| 72 | |
| 73 // This is made explicit in anticiption of experimental groups being added. | |
| 74 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 75 switches::kDisableFillOnAccountSelect)) { | |
| 76 return false; | |
| 77 } | |
| 78 | |
| 79 // TODO(jww): Add experimental groups check here. | |
| 80 | |
| 81 return false; | |
| 82 } | |
| 83 | |
| 65 // Helper to search the given form element for the specified input elements | 84 // Helper to search the given form element for the specified input elements |
| 66 // in |data|, and add results to |result|. | 85 // in |data|, and add results to |result|. |
| 67 static bool FindFormInputElements(blink::WebFormElement* fe, | 86 static bool FindFormInputElements(blink::WebFormElement* fe, |
| 68 const FormData& data, | 87 const FormData& data, |
| 69 FormElements* result) { | 88 FormElements* result) { |
| 70 // Loop through the list of elements we need to find on the form in order to | 89 // Loop through the list of elements we need to find on the form in order to |
| 71 // autofill it. If we don't find any one of them, abort processing this | 90 // autofill it. If we don't find any one of them, abort processing this |
| 72 // form; it can't be the right one. | 91 // form; it can't be the right one. |
| 73 for (size_t j = 0; j < data.fields.size(); j++) { | 92 for (size_t j = 0; j < data.fields.size(); j++) { |
| 74 blink::WebVector<blink::WebNode> temp_elements; | 93 blink::WebVector<blink::WebNode> temp_elements; |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 return false; | 315 return false; |
| 297 | 316 |
| 298 blink::WebInputElement password = password_info.password_field; | 317 blink::WebInputElement password = password_info.password_field; |
| 299 if (!IsElementEditable(password)) | 318 if (!IsElementEditable(password)) |
| 300 return false; | 319 return false; |
| 301 | 320 |
| 302 blink::WebInputElement username = element; // We need a non-const. | 321 blink::WebInputElement username = element; // We need a non-const. |
| 303 | 322 |
| 304 // Do not set selection when ending an editing session, otherwise it can | 323 // Do not set selection when ending an editing session, otherwise it can |
| 305 // mess with focus. | 324 // mess with focus. |
| 306 FillUserNameAndPassword(&username, | 325 FillUserNameAndPassword( |
| 307 &password, | 326 &username, &password, fill_data, EXACT_USERNAME_MATCH); |
| 308 fill_data, | |
| 309 true /* exact_username_match */, | |
| 310 false /* set_selection */); | |
| 311 return true; | 327 return true; |
| 312 } | 328 } |
| 313 | 329 |
| 314 bool PasswordAutofillAgent::TextDidChangeInTextField( | 330 bool PasswordAutofillAgent::TextDidChangeInTextField( |
| 315 const blink::WebInputElement& element) { | 331 const blink::WebInputElement& element) { |
| 316 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 | 332 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 |
| 317 blink::WebInputElement mutable_element = element; // We need a non-const. | 333 blink::WebInputElement mutable_element = element; // We need a non-const. |
| 318 | 334 |
| 319 if (element.isPasswordField()) { | 335 if (element.isPasswordField()) { |
| 320 // Some login forms have event handlers that put a hash of the password into | 336 // Some login forms have event handlers that put a hash of the password into |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 807 form_elements->input_elements[form_data.basic_data.fields[0].name]; | 823 form_elements->input_elements[form_data.basic_data.fields[0].name]; |
| 808 | 824 |
| 809 // Get pointer to password element. (We currently only support single | 825 // Get pointer to password element. (We currently only support single |
| 810 // password forms). | 826 // password forms). |
| 811 blink::WebInputElement password_element = | 827 blink::WebInputElement password_element = |
| 812 form_elements->input_elements[form_data.basic_data.fields[1].name]; | 828 form_elements->input_elements[form_data.basic_data.fields[1].name]; |
| 813 | 829 |
| 814 // If wait_for_username is true, we don't want to initially fill the form | 830 // If wait_for_username is true, we don't want to initially fill the form |
| 815 // until the user types in a valid username. | 831 // until the user types in a valid username. |
| 816 if (!form_data.wait_for_username) | 832 if (!form_data.wait_for_username) |
| 817 FillFormOnPasswordRecieved(form_data, username_element, password_element); | 833 FillFormOnPasswordReceived(form_data, username_element, password_element); |
| 818 | 834 |
| 819 // We might have already filled this form if there are two <form> elements | 835 // We might have already filled this form if there are two <form> elements |
| 820 // with identical markup. | 836 // with identical markup. |
| 821 if (login_to_password_info_.find(username_element) != | 837 if (login_to_password_info_.find(username_element) != |
| 822 login_to_password_info_.end()) | 838 login_to_password_info_.end()) |
| 823 continue; | 839 continue; |
| 824 | 840 |
| 825 PasswordInfo password_info; | 841 PasswordInfo password_info; |
| 826 password_info.fill_data = form_data; | 842 password_info.fill_data = form_data; |
| 827 password_info.password_field = password_element; | 843 password_info.password_field = password_element; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 913 float scale = web_view_->pageScaleFactor(); | 929 float scale = web_view_->pageScaleFactor(); |
| 914 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, | 930 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, |
| 915 bounding_box.y() * scale, | 931 bounding_box.y() * scale, |
| 916 bounding_box.width() * scale, | 932 bounding_box.width() * scale, |
| 917 bounding_box.height() * scale); | 933 bounding_box.height() * scale); |
| 918 Send(new AutofillHostMsg_ShowPasswordSuggestions( | 934 Send(new AutofillHostMsg_ShowPasswordSuggestions( |
| 919 routing_id(), field, bounding_box_scaled, suggestions, realms)); | 935 routing_id(), field, bounding_box_scaled, suggestions, realms)); |
| 920 return !suggestions.empty(); | 936 return !suggestions.empty(); |
| 921 } | 937 } |
| 922 | 938 |
| 923 void PasswordAutofillAgent::FillFormOnPasswordRecieved( | 939 void PasswordAutofillAgent::FillFormOnPasswordReceived( |
| 924 const PasswordFormFillData& fill_data, | 940 const PasswordFormFillData& fill_data, |
| 925 blink::WebInputElement username_element, | 941 blink::WebInputElement username_element, |
| 926 blink::WebInputElement password_element) { | 942 blink::WebInputElement password_element) { |
| 927 // Do not fill if the password field is in an iframe. | 943 // Do not fill if the password field is in an iframe. |
| 928 DCHECK(password_element.document().frame()); | 944 DCHECK(password_element.document().frame()); |
| 929 if (password_element.document().frame()->parent()) | 945 if (password_element.document().frame()->parent()) |
| 930 return; | 946 return; |
| 931 | 947 |
| 932 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && | 948 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && |
| 933 !username_element.form().autoComplete()) | 949 !username_element.form().autoComplete()) |
| 934 return; | 950 return; |
| 935 | 951 |
| 936 // If we can't modify the password, don't try to set the username | 952 // If we can't modify the password, don't try to set the username |
| 937 if (!IsElementAutocompletable(password_element)) | 953 if (!IsElementAutocompletable(password_element)) |
| 938 return; | 954 return; |
| 939 | 955 |
| 940 // Try to set the username to the preferred name, but only if the field | 956 if (ShouldFillOnAccountSelect()) { |
| 941 // can be set and isn't prefilled. | 957 username_element.setAutofilled(true); |
| 958 return; | |
| 959 } | |
|
Garrett Casto
2014/09/12 19:08:28
This is going to break sites that hide the usernam
jww
2014/09/15 22:48:00
Hm, this is a tough one. I don't think this is saf
| |
| 960 | |
| 961 // Try to set the username to the preferred name, but only if the field can be | |
| 962 // set and isn't prefilled. | |
| 942 if (IsElementAutocompletable(username_element) && | 963 if (IsElementAutocompletable(username_element) && |
| 943 username_element.value().isEmpty()) { | 964 username_element.value().isEmpty()) { |
| 944 // TODO(tkent): Check maxlength and pattern. | 965 // TODO(tkent): Check maxlength and pattern. |
| 945 username_element.setValue(fill_data.basic_data.fields[0].value, true); | 966 username_element.setValue(fill_data.basic_data.fields[0].value, true); |
| 946 } | 967 } |
| 947 | 968 |
| 948 // Fill if we have an exact match for the username. Note that this sets | 969 // Fill if we have an exact match for the username. Note that this sets |
| 949 // username to autofilled. | 970 // username to autofilled. |
| 950 FillUserNameAndPassword(&username_element, | 971 FillUserNameAndPassword( |
| 951 &password_element, | 972 &username_element, &password_element, fill_data, EXACT_USERNAME_MATCH); |
| 952 fill_data, | |
| 953 true /* exact_username_match */, | |
| 954 false /* set_selection */); | |
| 955 } | 973 } |
| 956 | 974 |
| 957 bool PasswordAutofillAgent::FillUserNameAndPassword( | 975 bool PasswordAutofillAgent::FillUserNameAndPassword( |
| 958 blink::WebInputElement* username_element, | 976 blink::WebInputElement* username_element, |
| 959 blink::WebInputElement* password_element, | 977 blink::WebInputElement* password_element, |
| 960 const PasswordFormFillData& fill_data, | 978 const PasswordFormFillData& fill_data, |
| 961 bool exact_username_match, | 979 const int options) { |
| 962 bool set_selection) { | 980 bool exact_username_match = (options & EXACT_USERNAME_MATCH) != 0; |
| 981 bool set_selection = (options & SET_SELECTION) != 0; | |
| 963 base::string16 current_username = username_element->value(); | 982 base::string16 current_username = username_element->value(); |
| 964 // username and password will contain the match found if any. | 983 // username and password will contain the match found if any. |
| 965 base::string16 username; | 984 base::string16 username; |
| 966 base::string16 password; | 985 base::string16 password; |
| 967 | 986 |
| 968 // Look for any suitable matches to current field text. | 987 // Look for any suitable matches to current field text. |
| 969 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, | 988 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, |
| 970 current_username, | 989 current_username, |
| 971 exact_username_match)) { | 990 exact_username_match)) { |
| 972 username = fill_data.basic_data.fields[0].value; | 991 username = fill_data.basic_data.fields[0].value; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1057 username.selectionEnd() != static_cast<int>(username.value().length())) { | 1076 username.selectionEnd() != static_cast<int>(username.value().length())) { |
| 1058 return; | 1077 return; |
| 1059 } | 1078 } |
| 1060 | 1079 |
| 1061 // Show the popup with the list of available usernames. | 1080 // Show the popup with the list of available usernames. |
| 1062 ShowSuggestionPopup(fill_data, username, false); | 1081 ShowSuggestionPopup(fill_data, username, false); |
| 1063 | 1082 |
| 1064 #if !defined(OS_ANDROID) | 1083 #if !defined(OS_ANDROID) |
| 1065 // Fill the user and password field with the most relevant match. Android | 1084 // Fill the user and password field with the most relevant match. Android |
| 1066 // only fills in the fields after the user clicks on the suggestion popup. | 1085 // only fills in the fields after the user clicks on the suggestion popup. |
| 1067 FillUserNameAndPassword(&username, | 1086 FillUserNameAndPassword(&username, &password, fill_data, SET_SELECTION); |
| 1068 &password, | |
| 1069 fill_data, | |
| 1070 false /* exact_username_match */, | |
| 1071 true /* set_selection */); | |
| 1072 #endif | 1087 #endif |
| 1073 } | 1088 } |
| 1074 | 1089 |
| 1075 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { | 1090 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { |
| 1076 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); | 1091 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); |
| 1077 iter != login_to_password_info_.end();) { | 1092 iter != login_to_password_info_.end();) { |
| 1078 if (iter->first.document().frame() == frame) { | 1093 if (iter->first.document().frame() == frame) { |
| 1079 password_to_username_.erase(iter->second.password_field); | 1094 password_to_username_.erase(iter->second.password_field); |
| 1080 login_to_password_info_.erase(iter++); | 1095 login_to_password_info_.erase(iter++); |
| 1081 } else { | 1096 } else { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1135 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); | 1150 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); |
| 1136 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && | 1151 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && |
| 1137 password_form->password_value.empty() && | 1152 password_form->password_value.empty() && |
| 1138 password_form->new_password_value.empty())) { | 1153 password_form->new_password_value.empty())) { |
| 1139 return; | 1154 return; |
| 1140 } | 1155 } |
| 1141 provisionally_saved_forms_[frame].reset(password_form.release()); | 1156 provisionally_saved_forms_[frame].reset(password_form.release()); |
| 1142 } | 1157 } |
| 1143 | 1158 |
| 1144 } // namespace autofill | 1159 } // namespace autofill |
| OLD | NEW |