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 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
185 // Returns |true| if the given element is both editable and has permission to be | 185 // Returns |true| if the given element is both editable and has permission to be |
186 // autocompleted. The latter can be either because there is no | 186 // autocompleted. The latter can be either because there is no |
187 // autocomplete='off' set for the element, or because the flag is set to ignore | 187 // autocomplete='off' set for the element, or because the flag is set to ignore |
188 // autocomplete='off'. Otherwise, returns |false|. | 188 // autocomplete='off'. Otherwise, returns |false|. |
189 bool IsElementAutocompletable(const blink::WebInputElement& element) { | 189 bool IsElementAutocompletable(const blink::WebInputElement& element) { |
190 return IsElementEditable(element) && | 190 return IsElementEditable(element) && |
191 (ShouldIgnoreAutocompleteOffForPasswordFields() || | 191 (ShouldIgnoreAutocompleteOffForPasswordFields() || |
192 element.autoComplete()); | 192 element.autoComplete()); |
193 } | 193 } |
194 | 194 |
195 // Returns |true| if element1 and element2 are IsElementAutocompletable. | |
196 // Otherwise returns |false|. | |
197 bool IsElementsAutocompletable(const blink::WebInputElement& element1, | |
Mike West
2014/09/18 10:25:14
Nit: _Are_ElementsAutocompletable.
| |
198 const blink::WebInputElement& element2) { | |
199 return IsElementAutocompletable(element1) && | |
200 IsElementAutocompletable(element2); | |
201 } | |
202 | |
195 // Returns true if the password specified in |form| is a default value. | 203 // Returns true if the password specified in |form| is a default value. |
196 bool PasswordValueIsDefault(const PasswordForm& form, | 204 bool PasswordValueIsDefault(const PasswordForm& form, |
197 blink::WebFormElement form_element) { | 205 blink::WebFormElement form_element) { |
198 blink::WebVector<blink::WebNode> temp_elements; | 206 blink::WebVector<blink::WebNode> temp_elements; |
199 form_element.getNamedElements(form.password_element, temp_elements); | 207 form_element.getNamedElements(form.password_element, temp_elements); |
200 | 208 |
201 // We are loose in our definition here and will return true if any of the | 209 // We are loose in our definition here and will return true if any of the |
202 // appropriately named elements match the element to be saved. Currently | 210 // appropriately named elements match the element to be saved. Currently |
203 // we ignore filling passwords where naming is ambigious anyway. | 211 // we ignore filling passwords where naming is ambigious anyway. |
204 for (size_t i = 0; i < temp_elements.size(); ++i) { | 212 for (size_t i = 0; i < temp_elements.size(); ++i) { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
348 blink::WebInputElement password = iter->second.password_field; | 356 blink::WebInputElement password = iter->second.password_field; |
349 if (password.isAutofilled()) { | 357 if (password.isAutofilled()) { |
350 password.setValue(base::string16(), true); | 358 password.setValue(base::string16(), true); |
351 password.setAutofilled(false); | 359 password.setAutofilled(false); |
352 } | 360 } |
353 | 361 |
354 // If wait_for_username is true we will fill when the username loses focus. | 362 // If wait_for_username is true we will fill when the username loses focus. |
355 if (iter->second.fill_data.wait_for_username) | 363 if (iter->second.fill_data.wait_for_username) |
356 return false; | 364 return false; |
357 | 365 |
358 if (!element.isText() || !IsElementAutocompletable(element) || | 366 if (!element.isText() || !IsElementsAutocompletable(element, password)) { |
359 !IsElementAutocompletable(password)) { | |
360 return false; | 367 return false; |
361 } | 368 } |
362 | 369 |
363 // Don't inline autocomplete if the user is deleting, that would be confusing. | 370 // Don't inline autocomplete if the user is deleting, that would be confusing. |
364 // But refresh the popup. Note, since this is ours, return true to signal | 371 // But refresh the popup. Note, since this is ours, return true to signal |
365 // no further processing is required. | 372 // no further processing is required. |
366 if (iter->second.backspace_pressed_last) { | 373 if (iter->second.backspace_pressed_last) { |
367 ShowSuggestionPopup(iter->second.fill_data, element, false); | 374 ShowSuggestionPopup(iter->second.fill_data, element, false); |
368 return true; | 375 return true; |
369 } | 376 } |
(...skipping 29 matching lines...) Expand all Loading... | |
399 } | 406 } |
400 | 407 |
401 bool PasswordAutofillAgent::FillSuggestion( | 408 bool PasswordAutofillAgent::FillSuggestion( |
402 const blink::WebNode& node, | 409 const blink::WebNode& node, |
403 const blink::WebString& username, | 410 const blink::WebString& username, |
404 const blink::WebString& password) { | 411 const blink::WebString& password) { |
405 blink::WebInputElement username_element; | 412 blink::WebInputElement username_element; |
406 PasswordInfo* password_info; | 413 PasswordInfo* password_info; |
407 | 414 |
408 if (!FindLoginInfo(node, &username_element, &password_info) || | 415 if (!FindLoginInfo(node, &username_element, &password_info) || |
409 !IsElementAutocompletable(username_element) || | 416 !IsElementsAutocompletable(username_element, |
410 !IsElementAutocompletable(password_info->password_field)) { | 417 password_info->password_field)) { |
411 return false; | 418 return false; |
412 } | 419 } |
413 | 420 |
414 password_info->password_was_edited_last = false; | 421 password_info->password_was_edited_last = false; |
415 username_element.setValue(username, true); | 422 username_element.setValue(username, true); |
416 username_element.setAutofilled(true); | 423 username_element.setAutofilled(true); |
417 username_element.setSelectionRange(username.length(), username.length()); | 424 username_element.setSelectionRange(username.length(), username.length()); |
418 | 425 |
419 password_info->password_field.setValue(password, true); | 426 password_info->password_field.setValue(password, true); |
420 password_info->password_field.setAutofilled(true); | 427 password_info->password_field.setAutofilled(true); |
421 | 428 |
422 return true; | 429 return true; |
423 } | 430 } |
424 | 431 |
425 bool PasswordAutofillAgent::PreviewSuggestion( | 432 bool PasswordAutofillAgent::PreviewSuggestion( |
426 const blink::WebNode& node, | 433 const blink::WebNode& node, |
427 const blink::WebString& username, | 434 const blink::WebString& username, |
428 const blink::WebString& password) { | 435 const blink::WebString& password) { |
429 blink::WebInputElement username_element; | 436 blink::WebInputElement username_element; |
430 PasswordInfo* password_info; | 437 PasswordInfo* password_info; |
431 | 438 |
432 if (!FindLoginInfo(node, &username_element, &password_info) || | 439 if (!FindLoginInfo(node, &username_element, &password_info) || |
433 !IsElementAutocompletable(username_element) || | 440 !IsElementsAutocompletable(username_element, |
434 !IsElementAutocompletable(password_info->password_field)) { | 441 password_info->password_field)) { |
435 return false; | 442 return false; |
436 } | 443 } |
437 | 444 |
438 was_username_autofilled_ = username_element.isAutofilled(); | 445 was_username_autofilled_ = username_element.isAutofilled(); |
439 username_selection_start_ = username_element.selectionStart(); | 446 username_selection_start_ = username_element.selectionStart(); |
440 username_element.setSuggestedValue(username); | 447 username_element.setSuggestedValue(username); |
441 username_element.setAutofilled(true); | 448 username_element.setAutofilled(true); |
442 username_element.setSelectionRange( | 449 username_element.setSelectionRange( |
443 username_selection_start_, | 450 username_selection_start_, |
444 username_element.suggestedValue().length()); | 451 username_element.suggestedValue().length()); |
(...skipping 21 matching lines...) Expand all Loading... | |
466 bool show_all) { | 473 bool show_all) { |
467 LoginToPasswordInfoMap::const_iterator iter = | 474 LoginToPasswordInfoMap::const_iterator iter = |
468 login_to_password_info_.find(element); | 475 login_to_password_info_.find(element); |
469 if (iter == login_to_password_info_.end()) | 476 if (iter == login_to_password_info_.end()) |
470 return false; | 477 return false; |
471 | 478 |
472 // If autocomplete='off' is set on the form elements, no suggestion dialog | 479 // If autocomplete='off' is set on the form elements, no suggestion dialog |
473 // should be shown. However, return |true| to indicate that this is a known | 480 // should be shown. However, return |true| to indicate that this is a known |
474 // password form and that the request to show suggestions has been handled (as | 481 // password form and that the request to show suggestions has been handled (as |
475 // a no-op). | 482 // a no-op). |
476 if (!IsElementAutocompletable(element) || | 483 if (!IsElementsAutocompletable(element, iter->second.password_field)) |
477 !IsElementAutocompletable(iter->second.password_field)) | |
478 return true; | 484 return true; |
479 | 485 |
480 return ShowSuggestionPopup(iter->second.fill_data, element, show_all); | 486 return ShowSuggestionPopup(iter->second.fill_data, element, show_all); |
481 } | 487 } |
482 | 488 |
483 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( | 489 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( |
484 const blink::WebSecurityOrigin& origin) { | 490 const blink::WebSecurityOrigin& origin) { |
485 return origin.canAccessPasswordManager(); | 491 return origin.canAccessPasswordManager(); |
486 } | 492 } |
487 | 493 |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
958 blink::WebInputElement* username_element, | 964 blink::WebInputElement* username_element, |
959 blink::WebInputElement* password_element, | 965 blink::WebInputElement* password_element, |
960 const PasswordFormFillData& fill_data, | 966 const PasswordFormFillData& fill_data, |
961 bool exact_username_match, | 967 bool exact_username_match, |
962 bool set_selection) { | 968 bool set_selection) { |
963 base::string16 current_username = username_element->value(); | 969 base::string16 current_username = username_element->value(); |
964 // username and password will contain the match found if any. | 970 // username and password will contain the match found if any. |
965 base::string16 username; | 971 base::string16 username; |
966 base::string16 password; | 972 base::string16 password; |
967 | 973 |
974 // Don't fill username if password can't be set. | |
975 if (!IsElementAutocompletable(*password_element)) | |
vabr (Chromium)
2014/09/18 09:14:24
Since you asked explicitly: yes, moving this check
Deepak
2014/09/18 09:35:13
Thanks.
| |
976 return false; | |
977 | |
968 // Look for any suitable matches to current field text. | 978 // Look for any suitable matches to current field text. |
969 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, | 979 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, |
970 current_username, | 980 current_username, |
971 exact_username_match)) { | 981 exact_username_match)) { |
972 username = fill_data.basic_data.fields[0].value; | 982 username = fill_data.basic_data.fields[0].value; |
973 password = fill_data.basic_data.fields[1].value; | 983 password = fill_data.basic_data.fields[1].value; |
974 } else { | 984 } else { |
975 // Scan additional logins for a match. | 985 // Scan additional logins for a match. |
976 PasswordFormFillData::LoginCollection::const_iterator iter; | 986 CheckLoginCollectionForMatch( |
977 for (iter = fill_data.additional_logins.begin(); | 987 fill_data, current_username, exact_username_match, username, password); |
978 iter != fill_data.additional_logins.end(); | 988 // Check possible usernames. |
979 ++iter) { | 989 if (username.empty() && password.empty()) |
980 if (DoUsernamesMatch( | 990 CheckUsernamesCollectionForMatch(fill_data, |
981 iter->first, current_username, exact_username_match)) { | 991 current_username, |
982 username = iter->first; | 992 exact_username_match, |
983 password = iter->second.password; | 993 username, |
984 break; | 994 password); |
985 } | 995 } |
986 } | |
987 | 996 |
988 // Check possible usernames. | |
989 if (username.empty() && password.empty()) { | |
990 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = | |
991 fill_data.other_possible_usernames.begin(); | |
992 iter != fill_data.other_possible_usernames.end(); | |
993 ++iter) { | |
994 for (size_t i = 0; i < iter->second.size(); ++i) { | |
995 if (DoUsernamesMatch( | |
996 iter->second[i], current_username, exact_username_match)) { | |
997 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; | |
998 username = iter->second[i]; | |
999 password = iter->first.password; | |
1000 break; | |
1001 } | |
1002 } | |
1003 if (!username.empty() && !password.empty()) | |
1004 break; | |
1005 } | |
1006 } | |
1007 } | |
1008 if (password.empty()) | 997 if (password.empty()) |
1009 return false; // No match was found. | 998 return false; // No match was found. |
1010 | 999 |
1011 // TODO(tkent): Check maxlength and pattern for both username and password | 1000 // TODO(tkent): Check maxlength and pattern for both username and password |
1012 // fields. | 1001 // fields. |
1013 | 1002 |
1014 // Don't fill username if password can't be set. | |
1015 if (!IsElementAutocompletable(*password_element)) { | |
1016 return false; | |
1017 } | |
1018 | |
1019 // Input matches the username, fill in required values. | 1003 // Input matches the username, fill in required values. |
1020 if (IsElementAutocompletable(*username_element)) { | 1004 if (IsElementAutocompletable(*username_element)) { |
1021 username_element->setValue(username, true); | 1005 username_element->setValue(username, true); |
1022 username_element->setAutofilled(true); | 1006 username_element->setAutofilled(true); |
1023 | 1007 |
1024 if (set_selection) { | 1008 if (set_selection) { |
1025 username_element->setSelectionRange(current_username.length(), | 1009 username_element->setSelectionRange(current_username.length(), |
1026 username.length()); | 1010 username.length()); |
1027 } | 1011 } |
1028 } else if (current_username != username) { | 1012 } else if (current_username != username) { |
1029 // If the username can't be filled and it doesn't match a saved password | 1013 // If the username can't be filled and it doesn't match a saved password |
1030 // as is, don't autofill a password. | 1014 // as is, don't autofill a password. |
1031 return false; | 1015 return false; |
1032 } | 1016 } |
1033 | |
1034 // Wait to fill in the password until a user gesture occurs. This is to make | 1017 // Wait to fill in the password until a user gesture occurs. This is to make |
1035 // sure that we do not fill in the DOM with a password until we believe the | 1018 // sure that we do not fill in the DOM with a password until we believe the |
1036 // user is intentionally interacting with the page. | 1019 // user is intentionally interacting with the page. |
1037 password_element->setSuggestedValue(password); | 1020 password_element->setSuggestedValue(password); |
1038 gatekeeper_.RegisterElement(password_element); | 1021 gatekeeper_.RegisterElement(password_element); |
1039 | 1022 |
1040 password_element->setAutofilled(true); | 1023 password_element->setAutofilled(true); |
1041 return true; | 1024 return true; |
1042 } | 1025 } |
1043 | 1026 |
1027 // Check additional names for match. | |
1028 void PasswordAutofillAgent::CheckLoginCollectionForMatch( | |
vabr (Chromium)
2014/09/18 09:14:24
Why separating the code into the two functions her
Deepak
2014/09/18 09:35:13
ok, I will make this again inline as earlier.
| |
1029 const PasswordFormFillData& fill_data, | |
1030 const base::string16 current_username, | |
1031 const bool exact_username_match, | |
1032 base::string16& username, | |
1033 base::string16& password) { | |
1034 for (PasswordFormFillData::LoginCollection::const_iterator iter = | |
1035 fill_data.additional_logins.begin(); | |
1036 iter != fill_data.additional_logins.end(); | |
1037 ++iter) { | |
1038 if (DoUsernamesMatch(iter->first, current_username, exact_username_match)) { | |
1039 username = iter->first; | |
1040 password = iter->second.password; | |
1041 break; | |
1042 } | |
1043 } | |
1044 } | |
1045 | |
1046 // Check possible usernames. | |
1047 void PasswordAutofillAgent::CheckUsernamesCollectionForMatch( | |
1048 const PasswordFormFillData& fill_data, | |
1049 const base::string16 current_username, | |
1050 const bool exact_username_match, | |
1051 base::string16& username, | |
1052 base::string16& password) { | |
1053 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = | |
1054 fill_data.other_possible_usernames.begin(); | |
1055 iter != fill_data.other_possible_usernames.end(); | |
1056 ++iter) { | |
1057 for (size_t i = 0; i < iter->second.size(); ++i) { | |
1058 if (DoUsernamesMatch( | |
1059 iter->second[i], current_username, exact_username_match)) { | |
1060 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; | |
1061 username = iter->second[i]; | |
1062 password = iter->first.password; | |
1063 break; | |
1064 } | |
1065 } | |
1066 if (!username.empty() && !password.empty()) | |
1067 break; | |
1068 } | |
1069 } | |
1070 | |
1044 void PasswordAutofillAgent::PerformInlineAutocomplete( | 1071 void PasswordAutofillAgent::PerformInlineAutocomplete( |
1045 const blink::WebInputElement& username_input, | 1072 const blink::WebInputElement& username_input, |
1046 const blink::WebInputElement& password_input, | 1073 const blink::WebInputElement& password_input, |
1047 const PasswordFormFillData& fill_data) { | 1074 const PasswordFormFillData& fill_data) { |
1048 DCHECK(!fill_data.wait_for_username); | 1075 DCHECK(!fill_data.wait_for_username); |
1049 | 1076 |
1050 // We need non-const versions of the username and password inputs. | 1077 // We need non-const versions of the username and password inputs. |
1051 blink::WebInputElement username = username_input; | 1078 blink::WebInputElement username = username_input; |
1052 blink::WebInputElement password = password_input; | 1079 blink::WebInputElement password = password_input; |
1053 | 1080 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1135 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); | 1162 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); |
1136 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && | 1163 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && |
1137 password_form->password_value.empty() && | 1164 password_form->password_value.empty() && |
1138 password_form->new_password_value.empty())) { | 1165 password_form->new_password_value.empty())) { |
1139 return; | 1166 return; |
1140 } | 1167 } |
1141 provisionally_saved_forms_[frame].reset(password_form.release()); | 1168 provisionally_saved_forms_[frame].reset(password_form.release()); |
1142 } | 1169 } |
1143 | 1170 |
1144 } // namespace autofill | 1171 } // namespace autofill |
OLD | NEW |