Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(699)

Side by Side Diff: components/autofill/content/renderer/password_autofill_agent.cc

Issue 548953002: [Password Manager] Modified to support saving passwords on forms without username fields. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporated input comments. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 FormInputElementMap input_elements; 60 FormInputElementMap input_elements;
61 }; 61 };
62 62
63 typedef std::vector<FormElements*> FormElementsList; 63 typedef std::vector<FormElements*> FormElementsList;
64 64
65 // Helper to search the given form element for the specified input elements 65 // Helper to search the given form element for the specified input elements
66 // in |data|, and add results to |result|. 66 // in |data|, and add results to |result|.
67 static bool FindFormInputElements(blink::WebFormElement* fe, 67 static bool FindFormInputElements(blink::WebFormElement* fe,
68 const FormData& data, 68 const FormData& data,
69 FormElements* result) { 69 FormElements* result) {
70 const bool username_is_present = !data.fields[0].name.empty();
71
70 // Loop through the list of elements we need to find on the form in order to 72 // 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 73 // autofill it. If we don't find any one of them, abort processing this
72 // form; it can't be the right one. 74 // form; it can't be the right one.
73 for (size_t j = 0; j < data.fields.size(); j++) { 75 // First field is the username, skip it if not present.
76 for (size_t j = (username_is_present ? 1 : 0); j < data.fields.size(); ++j) {
74 blink::WebVector<blink::WebNode> temp_elements; 77 blink::WebVector<blink::WebNode> temp_elements;
75 fe->getNamedElements(data.fields[j].name, temp_elements); 78 fe->getNamedElements(data.fields[j].name, temp_elements);
76 79
77 // Match the first input element, if any. 80 // Match the first input element, if any.
78 // |getNamedElements| may return non-input elements where the names match, 81 // |getNamedElements| may return non-input elements where the names match,
79 // so the results are filtered for input elements. 82 // so the results are filtered for input elements.
80 // If more than one match is made, then we have ambiguity (due to misuse 83 // If more than one match is made, then we have ambiguity (due to misuse
81 // of "name" attribute) so is it considered not found. 84 // of "name" attribute) so is it considered not found.
82 bool found_input = false; 85 bool found_input = false;
83 for (size_t i = 0; i < temp_elements.size(); ++i) { 86 for (size_t i = 0; i < temp_elements.size(); ++i) {
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 214
212 // Log a message including the name, method and action of |form|. 215 // Log a message including the name, method and action of |form|.
213 void LogHTMLForm(SavePasswordProgressLogger* logger, 216 void LogHTMLForm(SavePasswordProgressLogger* logger,
214 SavePasswordProgressLogger::StringID message_id, 217 SavePasswordProgressLogger::StringID message_id,
215 const blink::WebFormElement& form) { 218 const blink::WebFormElement& form) {
216 logger->LogHTMLForm(message_id, 219 logger->LogHTMLForm(message_id,
217 form.name().utf8(), 220 form.name().utf8(),
218 GURL(form.action().utf8())); 221 GURL(form.action().utf8()));
219 } 222 }
220 223
224 bool FillDataContainsUsername(const PasswordFormFillData& fill_data) {
225 return !fill_data.basic_data.fields[0].name.empty();
226 }
227
221 } // namespace 228 } // namespace
222 229
223 //////////////////////////////////////////////////////////////////////////////// 230 ////////////////////////////////////////////////////////////////////////////////
224 // PasswordAutofillAgent, public: 231 // PasswordAutofillAgent, public:
225 232
226 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) 233 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
227 : content::RenderViewObserver(render_view), 234 : content::RenderViewObserver(render_view),
228 usernames_usage_(NOTHING_TO_AUTOFILL), 235 usernames_usage_(NOTHING_TO_AUTOFILL),
229 web_view_(render_view->GetWebView()), 236 web_view_(render_view->GetWebView()),
230 logging_state_active_(false), 237 logging_state_active_(false),
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 } 802 }
796 803
797 FormElementsList forms; 804 FormElementsList forms;
798 // We own the FormElements* in forms. 805 // We own the FormElements* in forms.
799 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); 806 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms);
800 FormElementsList::iterator iter; 807 FormElementsList::iterator iter;
801 for (iter = forms.begin(); iter != forms.end(); ++iter) { 808 for (iter = forms.begin(); iter != forms.end(); ++iter) {
802 scoped_ptr<FormElements> form_elements(*iter); 809 scoped_ptr<FormElements> form_elements(*iter);
803 810
804 // Attach autocomplete listener to enable selecting alternate logins. 811 // Attach autocomplete listener to enable selecting alternate logins.
805 // First, get pointers to username element. 812 blink::WebInputElement username_element, password_element;
806 blink::WebInputElement username_element = 813
807 form_elements->input_elements[form_data.basic_data.fields[0].name]; 814 // Check whether the password form has a username input field.
815 bool form_contains_username_field = FillDataContainsUsername(form_data);
816 if (form_contains_username_field) {
817 username_element =
818 form_elements->input_elements[form_data.basic_data.fields[0].name];
819 }
820
821 // No password field, bail out.
822 if (form_data.basic_data.fields[1].name.empty())
823 break;
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 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 FillFormOnPasswordRecieved(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;
828 login_to_password_info_[username_element] = password_info; 844 login_to_password_info_[username_element] = password_info;
829 password_to_username_[password_element] = username_element; 845 password_to_username_[password_element] = username_element;
830 846
831 FormData form; 847 FormData form;
832 FormFieldData field; 848 FormFieldData field;
833 FindFormAndFieldForFormControlElement( 849 if (form_contains_username_field) {
834 username_element, &form, &field, REQUIRE_NONE); 850 FindFormAndFieldForFormControlElement(
851 username_element, &form, &field, REQUIRE_NONE);
852 }
853
835 Send(new AutofillHostMsg_AddPasswordFormMapping( 854 Send(new AutofillHostMsg_AddPasswordFormMapping(
836 routing_id(), field, form_data)); 855 routing_id(), field, form_data));
837 } 856 }
838 } 857 }
839 858
840 void PasswordAutofillAgent::OnSetLoggingState(bool active) { 859 void PasswordAutofillAgent::OnSetLoggingState(bool active) {
841 logging_state_active_ = active; 860 logging_state_active_ = active;
842 } 861 }
843 862
844 //////////////////////////////////////////////////////////////////////////////// 863 ////////////////////////////////////////////////////////////////////////////////
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 941
923 void PasswordAutofillAgent::FillFormOnPasswordRecieved( 942 void PasswordAutofillAgent::FillFormOnPasswordRecieved(
924 const PasswordFormFillData& fill_data, 943 const PasswordFormFillData& fill_data,
925 blink::WebInputElement username_element, 944 blink::WebInputElement username_element,
926 blink::WebInputElement password_element) { 945 blink::WebInputElement password_element) {
927 // Do not fill if the password field is in an iframe. 946 // Do not fill if the password field is in an iframe.
928 DCHECK(password_element.document().frame()); 947 DCHECK(password_element.document().frame());
929 if (password_element.document().frame()->parent()) 948 if (password_element.document().frame()->parent())
930 return; 949 return;
931 950
951 bool form_contains_username_field = FillDataContainsUsername(fill_data);
932 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && 952 if (!ShouldIgnoreAutocompleteOffForPasswordFields() &&
933 !username_element.form().autoComplete()) 953 form_contains_username_field && !username_element.form().autoComplete())
Garrett Casto 2014/09/25 20:34:38 nit: Line break after "&&"
Pritam Nikam 2014/09/26 04:07:14 "git cl format" restores it in-line. Does not resp
vabr (Chromium) 2014/09/26 12:32:39 Garrett, you are the OWNER here, but I suggest goi
Garrett Casto 2014/09/26 17:41:22 Keeping this as is is fine. I haven't been using c
934 return; 954 return;
935 955
936 // If we can't modify the password, don't try to set the username 956 // If we can't modify the password, don't try to set the username
937 if (!IsElementAutocompletable(password_element)) 957 if (!IsElementAutocompletable(password_element))
938 return; 958 return;
939 959
940 // Try to set the username to the preferred name, but only if the field 960 // Try to set the username to the preferred name, but only if the field
941 // can be set and isn't prefilled. 961 // can be set and isn't prefilled.
942 if (IsElementAutocompletable(username_element) && 962 if (form_contains_username_field &&
963 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(&username_element,
951 &password_element, 972 &password_element,
952 fill_data, 973 fill_data,
953 true /* exact_username_match */, 974 true /* exact_username_match */,
954 false /* set_selection */); 975 false /* set_selection */);
955 } 976 }
956 977
957 bool PasswordAutofillAgent::FillUserNameAndPassword( 978 bool PasswordAutofillAgent::FillUserNameAndPassword(
958 blink::WebInputElement* username_element, 979 blink::WebInputElement* username_element,
959 blink::WebInputElement* password_element, 980 blink::WebInputElement* password_element,
960 const PasswordFormFillData& fill_data, 981 const PasswordFormFillData& fill_data,
961 bool exact_username_match, 982 bool exact_username_match,
962 bool set_selection) { 983 bool set_selection) {
963 base::string16 current_username = username_element->value(); 984 // Don't fill username if password can't be set.
985 if (!IsElementAutocompletable(*password_element))
986 return false;
987
988 base::string16 current_username;
989 if (!username_element->isNull()) {
990 current_username = username_element->value();
991 }
992
964 // username and password will contain the match found if any. 993 // username and password will contain the match found if any.
965 base::string16 username; 994 base::string16 username;
966 base::string16 password; 995 base::string16 password;
967 996
968 // Don't fill username if password can't be set.
969 if (!IsElementAutocompletable(*password_element))
970 return false;
971
972 // Look for any suitable matches to current field text. 997 // Look for any suitable matches to current field text.
973 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, 998 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value,
974 current_username, 999 current_username,
975 exact_username_match)) { 1000 exact_username_match)) {
976 username = fill_data.basic_data.fields[0].value; 1001 username = fill_data.basic_data.fields[0].value;
977 password = fill_data.basic_data.fields[1].value; 1002 password = fill_data.basic_data.fields[1].value;
978 } else { 1003 } else {
979 // Scan additional logins for a match. 1004 // Scan additional logins for a match.
980 PasswordFormFillData::LoginCollection::const_iterator iter; 1005 PasswordFormFillData::LoginCollection::const_iterator iter;
981 for (iter = fill_data.additional_logins.begin(); 1006 for (iter = fill_data.additional_logins.begin();
(...skipping 27 matching lines...) Expand all
1009 } 1034 }
1010 } 1035 }
1011 } 1036 }
1012 if (password.empty()) 1037 if (password.empty())
1013 return false; // No match was found. 1038 return false; // No match was found.
1014 1039
1015 // TODO(tkent): Check maxlength and pattern for both username and password 1040 // TODO(tkent): Check maxlength and pattern for both username and password
1016 // fields. 1041 // fields.
1017 1042
1018 // Input matches the username, fill in required values. 1043 // Input matches the username, fill in required values.
1019 if (IsElementAutocompletable(*username_element)) { 1044 if (!username_element->isNull() &&
1045 IsElementAutocompletable(*username_element)) {
1020 username_element->setValue(username, true); 1046 username_element->setValue(username, true);
1021 username_element->setAutofilled(true); 1047 username_element->setAutofilled(true);
1022 1048
1023 if (set_selection) { 1049 if (set_selection) {
1024 username_element->setSelectionRange(current_username.length(), 1050 username_element->setSelectionRange(current_username.length(),
1025 username.length()); 1051 username.length());
1026 } 1052 }
1027 } else if (current_username != username) { 1053 } else if (current_username != username) {
1028 // If the username can't be filled and it doesn't match a saved password 1054 // If the username can't be filled and it doesn't match a saved password
1029 // as is, don't autofill a password. 1055 // as is, don't autofill a password.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 &password, 1093 &password,
1068 fill_data, 1094 fill_data,
1069 false /* exact_username_match */, 1095 false /* exact_username_match */,
1070 true /* set_selection */); 1096 true /* set_selection */);
1071 #endif 1097 #endif
1072 } 1098 }
1073 1099
1074 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { 1100 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) {
1075 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); 1101 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin();
1076 iter != login_to_password_info_.end();) { 1102 iter != login_to_password_info_.end();) {
1077 if (iter->first.document().frame() == frame) { 1103 // There may not be a username field, so get the frame from the password
1104 // field.
1105 if (iter->second.password_field.document().frame() == frame) {
1078 password_to_username_.erase(iter->second.password_field); 1106 password_to_username_.erase(iter->second.password_field);
1079 login_to_password_info_.erase(iter++); 1107 login_to_password_info_.erase(iter++);
1080 } else { 1108 } else {
1081 ++iter; 1109 ++iter;
1082 } 1110 }
1083 } 1111 }
1084 for (FrameToPasswordFormMap::iterator iter = 1112 for (FrameToPasswordFormMap::iterator iter =
1085 provisionally_saved_forms_.begin(); 1113 provisionally_saved_forms_.begin();
1086 iter != provisionally_saved_forms_.end();) { 1114 iter != provisionally_saved_forms_.end();) {
1087 if (iter->first == frame) 1115 if (iter->first == frame)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1134 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 1162 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
1135 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && 1163 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD &&
1136 password_form->password_value.empty() && 1164 password_form->password_value.empty() &&
1137 password_form->new_password_value.empty())) { 1165 password_form->new_password_value.empty())) {
1138 return; 1166 return;
1139 } 1167 }
1140 provisionally_saved_forms_[frame].reset(password_form.release()); 1168 provisionally_saved_forms_[frame].reset(password_form.release());
1141 } 1169 }
1142 1170
1143 } // namespace autofill 1171 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698