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

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 review changes and code refactoring. 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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 // Loop through the list of elements we need to find on the form in order to 70 // 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 71 // autofill it. If we don't find any one of them, abort processing this
72 // form; it can't be the right one. 72 // form; it can't be the right one.
73 for (size_t j = 0; j < data.fields.size(); j++) { 73 for (size_t j = 0; j < data.fields.size(); ++j) {
74 blink::WebVector<blink::WebNode> temp_elements; 74 blink::WebVector<blink::WebNode> temp_elements;
75 fe->getNamedElements(data.fields[j].name, temp_elements); 75 fe->getNamedElements(data.fields[j].name, temp_elements);
76 76
77 // Match the first input element, if any. 77 // Match the first input element, if any.
78 // |getNamedElements| may return non-input elements where the names match, 78 // |getNamedElements| may return non-input elements where the names match,
79 // so the results are filtered for input elements. 79 // so the results are filtered for input elements.
80 // If more than one match is made, then we have ambiguity (due to misuse 80 // If more than one match is made, then we have ambiguity (due to misuse
81 // of "name" attribute) so is it considered not found. 81 // of "name" attribute) so is it considered not found.
82 bool found_input = false; 82 bool found_input = false;
83 for (size_t i = 0; i < temp_elements.size(); ++i) { 83 for (size_t i = 0; i < temp_elements.size(); ++i) {
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 211
212 // Log a message including the name, method and action of |form|. 212 // Log a message including the name, method and action of |form|.
213 void LogHTMLForm(SavePasswordProgressLogger* logger, 213 void LogHTMLForm(SavePasswordProgressLogger* logger,
214 SavePasswordProgressLogger::StringID message_id, 214 SavePasswordProgressLogger::StringID message_id,
215 const blink::WebFormElement& form) { 215 const blink::WebFormElement& form) {
216 logger->LogHTMLForm(message_id, 216 logger->LogHTMLForm(message_id,
217 form.name().utf8(), 217 form.name().utf8(),
218 GURL(form.action().utf8())); 218 GURL(form.action().utf8()));
219 } 219 }
220 220
221 bool FillDataContainsUsername(const PasswordFormFillData& fill_data) {
222 return (fill_data.basic_data.fields.size() == 2);
223 }
224
221 } // namespace 225 } // namespace
222 226
223 //////////////////////////////////////////////////////////////////////////////// 227 ////////////////////////////////////////////////////////////////////////////////
224 // PasswordAutofillAgent, public: 228 // PasswordAutofillAgent, public:
225 229
226 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) 230 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
227 : content::RenderViewObserver(render_view), 231 : content::RenderViewObserver(render_view),
228 usernames_usage_(NOTHING_TO_AUTOFILL), 232 usernames_usage_(NOTHING_TO_AUTOFILL),
229 web_view_(render_view->GetWebView()), 233 web_view_(render_view->GetWebView()),
230 logging_state_active_(false), 234 logging_state_active_(false),
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 } 799 }
796 800
797 FormElementsList forms; 801 FormElementsList forms;
798 // We own the FormElements* in forms. 802 // We own the FormElements* in forms.
799 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); 803 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms);
800 FormElementsList::iterator iter; 804 FormElementsList::iterator iter;
801 for (iter = forms.begin(); iter != forms.end(); ++iter) { 805 for (iter = forms.begin(); iter != forms.end(); ++iter) {
802 scoped_ptr<FormElements> form_elements(*iter); 806 scoped_ptr<FormElements> form_elements(*iter);
803 807
804 // Attach autocomplete listener to enable selecting alternate logins. 808 // Attach autocomplete listener to enable selecting alternate logins.
805 // First, get pointers to username element. 809 blink::WebInputElement username_element, password_element;
806 blink::WebInputElement username_element = 810
807 form_elements->input_elements[form_data.basic_data.fields[0].name]; 811 // Check whether the password form has a username input field.
812 bool form_contains_username_field = FillDataContainsUsername(form_data);
813 size_t field_index = 0;
814 if (form_contains_username_field) {
815 username_element =
816 form_elements
817 ->input_elements[form_data.basic_data.fields[field_index].name];
818
819 ++field_index;
820 }
821
822 // No password field, bail out.
823 if (form_data.basic_data.fields[field_index].name.empty())
824 break;
808 825
809 // Get pointer to password element. (We currently only support single 826 // Get pointer to password element. (We currently only support single
810 // password forms). 827 // password forms).
811 blink::WebInputElement password_element = 828 password_element =
812 form_elements->input_elements[form_data.basic_data.fields[1].name]; 829 form_elements
830 ->input_elements[form_data.basic_data.fields[field_index].name];
813 831
814 // If wait_for_username is true, we don't want to initially fill the form 832 // If wait_for_username is true, we don't want to initially fill the form
815 // until the user types in a valid username. 833 // until the user types in a valid username.
816 if (!form_data.wait_for_username) 834 if (!form_data.wait_for_username)
817 FillFormOnPasswordRecieved(form_data, username_element, password_element); 835 FillFormOnPasswordRecieved(form_data, username_element, password_element);
818 836
819 // We might have already filled this form if there are two <form> elements 837 // We might have already filled this form if there are two <form> elements
820 // with identical markup. 838 // with identical markup.
821 if (login_to_password_info_.find(username_element) != 839 if (login_to_password_info_.find(username_element) !=
822 login_to_password_info_.end()) 840 login_to_password_info_.end())
823 continue; 841 continue;
824 842
825 PasswordInfo password_info; 843 PasswordInfo password_info;
826 password_info.fill_data = form_data; 844 password_info.fill_data = form_data;
827 password_info.password_field = password_element; 845 password_info.password_field = password_element;
828 login_to_password_info_[username_element] = password_info; 846 login_to_password_info_[username_element] = password_info;
829 password_to_username_[password_element] = username_element; 847 password_to_username_[password_element] = username_element;
830 848
831 FormData form; 849 FormData form;
832 FormFieldData field; 850 FormFieldData field;
833 FindFormAndFieldForFormControlElement( 851 if (form_contains_username_field) {
834 username_element, &form, &field, REQUIRE_NONE); 852 FindFormAndFieldForFormControlElement(
853 username_element, &form, &field, REQUIRE_NONE);
854 }
855
835 Send(new AutofillHostMsg_AddPasswordFormMapping( 856 Send(new AutofillHostMsg_AddPasswordFormMapping(
836 routing_id(), field, form_data)); 857 routing_id(), field, form_data));
837 } 858 }
838 } 859 }
839 860
840 void PasswordAutofillAgent::OnSetLoggingState(bool active) { 861 void PasswordAutofillAgent::OnSetLoggingState(bool active) {
841 logging_state_active_ = active; 862 logging_state_active_ = active;
842 } 863 }
843 864
844 //////////////////////////////////////////////////////////////////////////////// 865 ////////////////////////////////////////////////////////////////////////////////
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 943
923 void PasswordAutofillAgent::FillFormOnPasswordRecieved( 944 void PasswordAutofillAgent::FillFormOnPasswordRecieved(
924 const PasswordFormFillData& fill_data, 945 const PasswordFormFillData& fill_data,
925 blink::WebInputElement username_element, 946 blink::WebInputElement username_element,
926 blink::WebInputElement password_element) { 947 blink::WebInputElement password_element) {
927 // Do not fill if the password field is in an iframe. 948 // Do not fill if the password field is in an iframe.
928 DCHECK(password_element.document().frame()); 949 DCHECK(password_element.document().frame());
929 if (password_element.document().frame()->parent()) 950 if (password_element.document().frame()->parent())
930 return; 951 return;
931 952
953 bool form_contains_username_field = FillDataContainsUsername(fill_data);
932 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && 954 if (!ShouldIgnoreAutocompleteOffForPasswordFields() &&
933 !username_element.form().autoComplete()) 955 form_contains_username_field && !username_element.form().autoComplete())
934 return; 956 return;
935 957
936 // If we can't modify the password, don't try to set the username 958 // If we can't modify the password, don't try to set the username
937 if (!IsElementAutocompletable(password_element)) 959 if (!IsElementAutocompletable(password_element))
938 return; 960 return;
939 961
940 // Try to set the username to the preferred name, but only if the field 962 // Try to set the username to the preferred name, but only if the field
941 // can be set and isn't prefilled. 963 // can be set and isn't prefilled.
942 if (IsElementAutocompletable(username_element) && 964 if (form_contains_username_field &&
965 IsElementAutocompletable(username_element) &&
943 username_element.value().isEmpty()) { 966 username_element.value().isEmpty()) {
944 // TODO(tkent): Check maxlength and pattern. 967 // TODO(tkent): Check maxlength and pattern.
945 username_element.setValue(fill_data.basic_data.fields[0].value, true); 968 username_element.setValue(fill_data.basic_data.fields[0].value, true);
946 } 969 }
947 970
948 // Fill if we have an exact match for the username. Note that this sets 971 // Fill if we have an exact match for the username. Note that this sets
949 // username to autofilled. 972 // username to autofilled.
950 FillUserNameAndPassword(&username_element, 973 FillUserNameAndPassword(&username_element,
951 &password_element, 974 &password_element,
952 fill_data, 975 fill_data,
953 true /* exact_username_match */, 976 true /* exact_username_match */,
954 false /* set_selection */); 977 false /* set_selection */);
955 } 978 }
956 979
957 bool PasswordAutofillAgent::FillUserNameAndPassword( 980 bool PasswordAutofillAgent::FillUserNameAndPassword(
958 blink::WebInputElement* username_element, 981 blink::WebInputElement* username_element,
959 blink::WebInputElement* password_element, 982 blink::WebInputElement* password_element,
960 const PasswordFormFillData& fill_data, 983 const PasswordFormFillData& fill_data,
961 bool exact_username_match, 984 bool exact_username_match,
962 bool set_selection) { 985 bool set_selection) {
963 base::string16 current_username = username_element->value();
964 // username and password will contain the match found if any.
965 base::string16 username;
966 base::string16 password;
967
968 // Don't fill username if password can't be set. 986 // Don't fill username if password can't be set.
969 if (!IsElementAutocompletable(*password_element)) 987 if (!IsElementAutocompletable(*password_element))
970 return false; 988 return false;
971 989
990 // username and password will contain the match found if any.
991 base::string16 username;
992 base::string16 password;
993 base::string16 current_username;
994 if (!username_element->isNull()) {
995 current_username = username_element->value();
996 } else {
997 password = fill_data.basic_data.fields[0].value;
998 }
999
972 // Look for any suitable matches to current field text. 1000 // Look for any suitable matches to current field text.
973 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, 1001 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value,
vabr (Chromium) 2014/09/25 10:39:59 This potentially tries to match |current_username|
Pritam Nikam 2014/09/25 11:22:46 Done. Reverted refactoring.
974 current_username, 1002 current_username,
975 exact_username_match)) { 1003 exact_username_match)) {
976 username = fill_data.basic_data.fields[0].value; 1004 username = fill_data.basic_data.fields[0].value;
977 password = fill_data.basic_data.fields[1].value; 1005 password = fill_data.basic_data.fields[1].value;
978 } else { 1006 } else {
979 // Scan additional logins for a match. 1007 // Scan additional logins for a match.
vabr (Chromium) 2014/09/25 10:39:59 This branch is entered for all forms without usern
Pritam Nikam 2014/09/25 11:22:45 Done. Reverted refactoring.
980 PasswordFormFillData::LoginCollection::const_iterator iter; 1008 PasswordFormFillData::LoginCollection::const_iterator iter;
981 for (iter = fill_data.additional_logins.begin(); 1009 for (iter = fill_data.additional_logins.begin();
982 iter != fill_data.additional_logins.end(); 1010 iter != fill_data.additional_logins.end();
983 ++iter) { 1011 ++iter) {
984 if (DoUsernamesMatch( 1012 if (DoUsernamesMatch(
985 iter->first, current_username, exact_username_match)) { 1013 iter->first, current_username, exact_username_match)) {
986 username = iter->first; 1014 username = iter->first;
987 password = iter->second.password; 1015 password = iter->second.password;
988 break; 1016 break;
989 } 1017 }
(...skipping 19 matching lines...) Expand all
1009 } 1037 }
1010 } 1038 }
1011 } 1039 }
1012 if (password.empty()) 1040 if (password.empty())
1013 return false; // No match was found. 1041 return false; // No match was found.
1014 1042
1015 // TODO(tkent): Check maxlength and pattern for both username and password 1043 // TODO(tkent): Check maxlength and pattern for both username and password
1016 // fields. 1044 // fields.
1017 1045
1018 // Input matches the username, fill in required values. 1046 // Input matches the username, fill in required values.
1019 if (IsElementAutocompletable(*username_element)) { 1047 if (!username_element->isNull() &&
1048 IsElementAutocompletable(*username_element)) {
1020 username_element->setValue(username, true); 1049 username_element->setValue(username, true);
1021 username_element->setAutofilled(true); 1050 username_element->setAutofilled(true);
1022 1051
1023 if (set_selection) { 1052 if (set_selection) {
1024 username_element->setSelectionRange(current_username.length(), 1053 username_element->setSelectionRange(current_username.length(),
1025 username.length()); 1054 username.length());
1026 } 1055 }
1027 } else if (current_username != username) { 1056 } else if (current_username != username) {
1028 // If the username can't be filled and it doesn't match a saved password 1057 // If the username can't be filled and it doesn't match a saved password
1029 // as is, don't autofill a password. 1058 // as is, don't autofill a password.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 &password, 1096 &password,
1068 fill_data, 1097 fill_data,
1069 false /* exact_username_match */, 1098 false /* exact_username_match */,
1070 true /* set_selection */); 1099 true /* set_selection */);
1071 #endif 1100 #endif
1072 } 1101 }
1073 1102
1074 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { 1103 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) {
1075 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); 1104 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin();
1076 iter != login_to_password_info_.end();) { 1105 iter != login_to_password_info_.end();) {
1077 if (iter->first.document().frame() == frame) { 1106 // There may not be a username field, so get the frame from the password
1107 // field.
1108 if (iter->second.password_field.document().frame() == frame) {
1078 password_to_username_.erase(iter->second.password_field); 1109 password_to_username_.erase(iter->second.password_field);
1079 login_to_password_info_.erase(iter++); 1110 login_to_password_info_.erase(iter++);
1080 } else { 1111 } else {
1081 ++iter; 1112 ++iter;
1082 } 1113 }
1083 } 1114 }
1084 for (FrameToPasswordFormMap::iterator iter = 1115 for (FrameToPasswordFormMap::iterator iter =
1085 provisionally_saved_forms_.begin(); 1116 provisionally_saved_forms_.begin();
1086 iter != provisionally_saved_forms_.end();) { 1117 iter != provisionally_saved_forms_.end();) {
1087 if (iter->first == frame) 1118 if (iter->first == frame)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1134 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 1165 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
1135 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && 1166 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD &&
1136 password_form->password_value.empty() && 1167 password_form->password_value.empty() &&
1137 password_form->new_password_value.empty())) { 1168 password_form->new_password_value.empty())) {
1138 return; 1169 return;
1139 } 1170 }
1140 provisionally_saved_forms_[frame].reset(password_form.release()); 1171 provisionally_saved_forms_[frame].reset(password_form.release());
1141 } 1172 }
1142 1173
1143 } // namespace autofill 1174 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698