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 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 elements_.clear(); | 266 elements_.clear(); |
267 } | 267 } |
268 | 268 |
269 void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() { | 269 void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() { |
270 was_user_gesture_seen_ = false; | 270 was_user_gesture_seen_ = false; |
271 elements_.clear(); | 271 elements_.clear(); |
272 } | 272 } |
273 | 273 |
274 void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue( | 274 void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue( |
275 blink::WebInputElement* element) { | 275 blink::WebInputElement* element) { |
276 if (!element->isNull() && !element->suggestedValue().isNull()) | 276 if (!element->isNull() && !element->suggestedValue().isEmpty()) |
277 element->setValue(element->suggestedValue(), true); | 277 element->setValue(element->suggestedValue(), true); |
278 } | 278 } |
279 | 279 |
280 bool PasswordAutofillAgent::TextFieldDidEndEditing( | 280 bool PasswordAutofillAgent::TextFieldDidEndEditing( |
281 const blink::WebInputElement& element) { | 281 const blink::WebInputElement& element) { |
282 LoginToPasswordInfoMap::const_iterator iter = | 282 LoginToPasswordInfoMap::const_iterator iter = |
283 login_to_password_info_.find(element); | 283 login_to_password_info_.find(element); |
284 if (iter == login_to_password_info_.end()) | 284 if (iter == login_to_password_info_.end()) |
285 return false; | 285 return false; |
286 | 286 |
287 const PasswordFormFillData& fill_data = iter->second.fill_data; | 287 const PasswordInfo& password_info = iter->second; |
| 288 // Don't let autofill overwrite an explicit change made by the user. |
| 289 if (password_info.password_was_edited_last) |
| 290 return false; |
| 291 |
| 292 const PasswordFormFillData& fill_data = password_info.fill_data; |
288 | 293 |
289 // If wait_for_username is false, we should have filled when the text changed. | 294 // If wait_for_username is false, we should have filled when the text changed. |
290 if (!fill_data.wait_for_username) | 295 if (!fill_data.wait_for_username) |
291 return false; | 296 return false; |
292 | 297 |
293 blink::WebInputElement password = iter->second.password_field; | 298 blink::WebInputElement password = password_info.password_field; |
294 if (!IsElementEditable(password)) | 299 if (!IsElementEditable(password)) |
295 return false; | 300 return false; |
296 | 301 |
297 blink::WebInputElement username = element; // We need a non-const. | 302 blink::WebInputElement username = element; // We need a non-const. |
298 | 303 |
299 // Do not set selection when ending an editing session, otherwise it can | 304 // Do not set selection when ending an editing session, otherwise it can |
300 // mess with focus. | 305 // mess with focus. |
301 FillUserNameAndPassword(&username, | 306 FillUserNameAndPassword(&username, |
302 &password, | 307 &password, |
303 fill_data, | 308 fill_data, |
304 true /* exact_username_match */, | 309 true /* exact_username_match */, |
305 false /* set_selection */); | 310 false /* set_selection */); |
306 return true; | 311 return true; |
307 } | 312 } |
308 | 313 |
309 bool PasswordAutofillAgent::TextDidChangeInTextField( | 314 bool PasswordAutofillAgent::TextDidChangeInTextField( |
310 const blink::WebInputElement& element) { | 315 const blink::WebInputElement& element) { |
| 316 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 |
| 317 blink::WebInputElement mutable_element = element; // We need a non-const. |
| 318 |
311 if (element.isPasswordField()) { | 319 if (element.isPasswordField()) { |
312 // Some login forms have event handlers that put a hash of the password into | 320 // Some login forms have event handlers that put a hash of the password into |
313 // a hidden field and then clear the password (http://crbug.com/28910, | 321 // a hidden field and then clear the password (http://crbug.com/28910, |
314 // http://crbug.com/391693). This method gets called before any of those | 322 // http://crbug.com/391693). This method gets called before any of those |
315 // handlers run, so save away a copy of the password in case it gets lost. | 323 // handlers run, so save away a copy of the password in case it gets lost. |
316 // To honor the user having explicitly cleared the password, even an empty | 324 // To honor the user having explicitly cleared the password, even an empty |
317 // password will be saved here. | 325 // password will be saved here. |
318 ProvisionallySavePassword( | 326 ProvisionallySavePassword( |
319 element.document().frame(), element.form(), RESTRICTION_NONE); | 327 element.document().frame(), element.form(), RESTRICTION_NONE); |
| 328 |
| 329 PasswordToLoginMap::iterator iter = password_to_username_.find(element); |
| 330 if (iter != password_to_username_.end()) { |
| 331 login_to_password_info_[iter->second].password_was_edited_last = true; |
| 332 // Note that the suggested value of |mutable_element| was reset when its |
| 333 // value changed. |
| 334 mutable_element.setAutofilled(false); |
| 335 } |
320 return false; | 336 return false; |
321 } | 337 } |
322 | 338 |
323 LoginToPasswordInfoMap::const_iterator iter = | 339 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element); |
324 login_to_password_info_.find(element); | |
325 if (iter == login_to_password_info_.end()) | 340 if (iter == login_to_password_info_.end()) |
326 return false; | 341 return false; |
327 | 342 |
328 // The input text is being changed, so any autofilled password is now | 343 // The input text is being changed, so any autofilled password is now |
329 // outdated. | 344 // outdated. |
330 blink::WebInputElement username = element; // We need a non-const. | 345 mutable_element.setAutofilled(false); |
331 username.setAutofilled(false); | 346 iter->second.password_was_edited_last = false; |
332 | 347 |
333 blink::WebInputElement password = iter->second.password_field; | 348 blink::WebInputElement password = iter->second.password_field; |
334 if (password.isAutofilled()) { | 349 if (password.isAutofilled()) { |
335 password.setValue(base::string16(), true); | 350 password.setValue(base::string16(), true); |
336 password.setAutofilled(false); | 351 password.setAutofilled(false); |
337 } | 352 } |
338 | 353 |
339 // If wait_for_username is true we will fill when the username loses focus. | 354 // If wait_for_username is true we will fill when the username loses focus. |
340 if (iter->second.fill_data.wait_for_username) | 355 if (iter->second.fill_data.wait_for_username) |
341 return false; | 356 return false; |
342 | 357 |
343 if (!element.isText() || !IsElementAutocompletable(element) || | 358 if (!element.isText() || !IsElementAutocompletable(element) || |
344 !IsElementAutocompletable(password)) { | 359 !IsElementAutocompletable(password)) { |
345 return false; | 360 return false; |
346 } | 361 } |
347 | 362 |
348 // Don't inline autocomplete if the user is deleting, that would be confusing. | 363 // Don't inline autocomplete if the user is deleting, that would be confusing. |
349 // But refresh the popup. Note, since this is ours, return true to signal | 364 // But refresh the popup. Note, since this is ours, return true to signal |
350 // no further processing is required. | 365 // no further processing is required. |
351 if (iter->second.backspace_pressed_last) { | 366 if (iter->second.backspace_pressed_last) { |
352 ShowSuggestionPopup(iter->second.fill_data, username, false); | 367 ShowSuggestionPopup(iter->second.fill_data, element, false); |
353 return true; | 368 return true; |
354 } | 369 } |
355 | 370 |
356 blink::WebString name = element.nameForAutofill(); | 371 blink::WebString name = element.nameForAutofill(); |
357 if (name.isEmpty()) | 372 if (name.isEmpty()) |
358 return false; // If the field has no name, then we won't have values. | 373 return false; // If the field has no name, then we won't have values. |
359 | 374 |
360 // Don't attempt to autofill with values that are too large. | 375 // Don't attempt to autofill with values that are too large. |
361 if (element.value().length() > kMaximumTextSizeForAutocomplete) | 376 if (element.value().length() > kMaximumTextSizeForAutocomplete) |
362 return false; | 377 return false; |
(...skipping 18 matching lines...) Expand all Loading... |
381 iter->second.backspace_pressed_last = | 396 iter->second.backspace_pressed_last = |
382 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE); | 397 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE); |
383 return true; | 398 return true; |
384 } | 399 } |
385 | 400 |
386 bool PasswordAutofillAgent::FillSuggestion( | 401 bool PasswordAutofillAgent::FillSuggestion( |
387 const blink::WebNode& node, | 402 const blink::WebNode& node, |
388 const blink::WebString& username, | 403 const blink::WebString& username, |
389 const blink::WebString& password) { | 404 const blink::WebString& password) { |
390 blink::WebInputElement username_element; | 405 blink::WebInputElement username_element; |
391 PasswordInfo password_info; | 406 PasswordInfo* password_info; |
392 | 407 |
393 if (!FindLoginInfo(node, &username_element, &password_info) || | 408 if (!FindLoginInfo(node, &username_element, &password_info) || |
394 !IsElementAutocompletable(username_element) || | 409 !IsElementAutocompletable(username_element) || |
395 !IsElementAutocompletable(password_info.password_field)) { | 410 !IsElementAutocompletable(password_info->password_field)) { |
396 return false; | 411 return false; |
397 } | 412 } |
398 | 413 |
399 base::string16 current_username = username_element.value(); | 414 password_info->password_was_edited_last = false; |
400 username_element.setValue(username, true); | 415 username_element.setValue(username, true); |
401 username_element.setAutofilled(true); | 416 username_element.setAutofilled(true); |
402 username_element.setSelectionRange(username.length(), username.length()); | 417 username_element.setSelectionRange(username.length(), username.length()); |
403 | 418 |
404 password_info.password_field.setValue(password, true); | 419 password_info->password_field.setValue(password, true); |
405 password_info.password_field.setAutofilled(true); | 420 password_info->password_field.setAutofilled(true); |
406 | 421 |
407 return true; | 422 return true; |
408 } | 423 } |
409 | 424 |
410 bool PasswordAutofillAgent::PreviewSuggestion( | 425 bool PasswordAutofillAgent::PreviewSuggestion( |
411 const blink::WebNode& node, | 426 const blink::WebNode& node, |
412 const blink::WebString& username, | 427 const blink::WebString& username, |
413 const blink::WebString& password) { | 428 const blink::WebString& password) { |
414 blink::WebInputElement username_element; | 429 blink::WebInputElement username_element; |
415 PasswordInfo password_info; | 430 PasswordInfo* password_info; |
416 | 431 |
417 if (!FindLoginInfo(node, &username_element, &password_info) || | 432 if (!FindLoginInfo(node, &username_element, &password_info) || |
418 !IsElementAutocompletable(username_element) || | 433 !IsElementAutocompletable(username_element) || |
419 !IsElementAutocompletable(password_info.password_field)) { | 434 !IsElementAutocompletable(password_info->password_field)) { |
420 return false; | 435 return false; |
421 } | 436 } |
422 | 437 |
423 was_username_autofilled_ = username_element.isAutofilled(); | 438 was_username_autofilled_ = username_element.isAutofilled(); |
424 username_selection_start_ = username_element.selectionStart(); | 439 username_selection_start_ = username_element.selectionStart(); |
425 username_element.setSuggestedValue(username); | 440 username_element.setSuggestedValue(username); |
426 username_element.setAutofilled(true); | 441 username_element.setAutofilled(true); |
427 username_element.setSelectionRange( | 442 username_element.setSelectionRange( |
428 username_selection_start_, | 443 username_selection_start_, |
429 username_element.suggestedValue().length()); | 444 username_element.suggestedValue().length()); |
430 | 445 |
431 was_password_autofilled_ = password_info.password_field.isAutofilled(); | 446 was_password_autofilled_ = password_info->password_field.isAutofilled(); |
432 password_info.password_field.setSuggestedValue(password); | 447 password_info->password_field.setSuggestedValue(password); |
433 password_info.password_field.setAutofilled(true); | 448 password_info->password_field.setAutofilled(true); |
434 | 449 |
435 return true; | 450 return true; |
436 } | 451 } |
437 | 452 |
438 bool PasswordAutofillAgent::DidClearAutofillSelection( | 453 bool PasswordAutofillAgent::DidClearAutofillSelection( |
439 const blink::WebNode& node) { | 454 const blink::WebNode& node) { |
440 blink::WebInputElement username_element; | 455 blink::WebInputElement username_element; |
441 PasswordInfo password_info; | 456 PasswordInfo* password_info; |
442 if (!FindLoginInfo(node, &username_element, &password_info)) | 457 if (!FindLoginInfo(node, &username_element, &password_info)) |
443 return false; | 458 return false; |
444 | 459 |
445 ClearPreview(&username_element, &password_info.password_field); | 460 ClearPreview(&username_element, &password_info->password_field); |
446 return true; | 461 return true; |
447 } | 462 } |
448 | 463 |
449 bool PasswordAutofillAgent::ShowSuggestions( | 464 bool PasswordAutofillAgent::ShowSuggestions( |
450 const blink::WebInputElement& element, | 465 const blink::WebInputElement& element, |
451 bool show_all) { | 466 bool show_all) { |
452 LoginToPasswordInfoMap::const_iterator iter = | 467 LoginToPasswordInfoMap::const_iterator iter = |
453 login_to_password_info_.find(element); | 468 login_to_password_info_.find(element); |
454 if (iter == login_to_password_info_.end()) | 469 if (iter == login_to_password_info_.end()) |
455 return false; | 470 return false; |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
804 // We might have already filled this form if there are two <form> elements | 819 // We might have already filled this form if there are two <form> elements |
805 // with identical markup. | 820 // with identical markup. |
806 if (login_to_password_info_.find(username_element) != | 821 if (login_to_password_info_.find(username_element) != |
807 login_to_password_info_.end()) | 822 login_to_password_info_.end()) |
808 continue; | 823 continue; |
809 | 824 |
810 PasswordInfo password_info; | 825 PasswordInfo password_info; |
811 password_info.fill_data = form_data; | 826 password_info.fill_data = form_data; |
812 password_info.password_field = password_element; | 827 password_info.password_field = password_element; |
813 login_to_password_info_[username_element] = password_info; | 828 login_to_password_info_[username_element] = password_info; |
| 829 password_to_username_[password_element] = username_element; |
814 | 830 |
815 FormData form; | 831 FormData form; |
816 FormFieldData field; | 832 FormFieldData field; |
817 FindFormAndFieldForFormControlElement( | 833 FindFormAndFieldForFormControlElement( |
818 username_element, &form, &field, REQUIRE_NONE); | 834 username_element, &form, &field, REQUIRE_NONE); |
819 Send(new AutofillHostMsg_AddPasswordFormMapping( | 835 Send(new AutofillHostMsg_AddPasswordFormMapping( |
820 routing_id(), field, form_data)); | 836 routing_id(), field, form_data)); |
821 } | 837 } |
822 } | 838 } |
823 | 839 |
824 void PasswordAutofillAgent::OnSetLoggingState(bool active) { | 840 void PasswordAutofillAgent::OnSetLoggingState(bool active) { |
825 logging_state_active_ = active; | 841 logging_state_active_ = active; |
826 } | 842 } |
827 | 843 |
828 //////////////////////////////////////////////////////////////////////////////// | 844 //////////////////////////////////////////////////////////////////////////////// |
829 // PasswordAutofillAgent, private: | 845 // PasswordAutofillAgent, private: |
830 | 846 |
| 847 PasswordAutofillAgent::PasswordInfo::PasswordInfo() |
| 848 : backspace_pressed_last(false), password_was_edited_last(false) { |
| 849 } |
| 850 |
831 void PasswordAutofillAgent::GetSuggestions( | 851 void PasswordAutofillAgent::GetSuggestions( |
832 const PasswordFormFillData& fill_data, | 852 const PasswordFormFillData& fill_data, |
833 const base::string16& input, | 853 const base::string16& input, |
834 std::vector<base::string16>* suggestions, | 854 std::vector<base::string16>* suggestions, |
835 std::vector<base::string16>* realms, | 855 std::vector<base::string16>* realms, |
836 bool show_all) { | 856 bool show_all) { |
837 if (show_all || | 857 if (show_all || |
838 StartsWith(fill_data.basic_data.fields[0].value, input, false)) { | 858 StartsWith(fill_data.basic_data.fields[0].value, input, false)) { |
839 suggestions->push_back(fill_data.basic_data.fields[0].value); | 859 suggestions->push_back(fill_data.basic_data.fields[0].value); |
840 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); | 860 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 &password, | 1068 &password, |
1049 fill_data, | 1069 fill_data, |
1050 false /* exact_username_match */, | 1070 false /* exact_username_match */, |
1051 true /* set_selection */); | 1071 true /* set_selection */); |
1052 #endif | 1072 #endif |
1053 } | 1073 } |
1054 | 1074 |
1055 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { | 1075 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { |
1056 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); | 1076 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); |
1057 iter != login_to_password_info_.end();) { | 1077 iter != login_to_password_info_.end();) { |
1058 if (iter->first.document().frame() == frame) | 1078 if (iter->first.document().frame() == frame) { |
| 1079 password_to_username_.erase(iter->second.password_field); |
1059 login_to_password_info_.erase(iter++); | 1080 login_to_password_info_.erase(iter++); |
1060 else | 1081 } else { |
1061 ++iter; | 1082 ++iter; |
| 1083 } |
1062 } | 1084 } |
1063 for (FrameToPasswordFormMap::iterator iter = | 1085 for (FrameToPasswordFormMap::iterator iter = |
1064 provisionally_saved_forms_.begin(); | 1086 provisionally_saved_forms_.begin(); |
1065 iter != provisionally_saved_forms_.end();) { | 1087 iter != provisionally_saved_forms_.end();) { |
1066 if (iter->first == frame) | 1088 if (iter->first == frame) |
1067 provisionally_saved_forms_.erase(iter++); | 1089 provisionally_saved_forms_.erase(iter++); |
1068 else | 1090 else |
1069 ++iter; | 1091 ++iter; |
1070 } | 1092 } |
1071 } | 1093 } |
1072 | 1094 |
1073 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, | 1095 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, |
1074 blink::WebInputElement* found_input, | 1096 blink::WebInputElement* found_input, |
1075 PasswordInfo* found_password) { | 1097 PasswordInfo** found_password) { |
1076 if (!node.isElementNode()) | 1098 if (!node.isElementNode()) |
1077 return false; | 1099 return false; |
1078 | 1100 |
1079 blink::WebElement element = node.toConst<blink::WebElement>(); | 1101 blink::WebElement element = node.toConst<blink::WebElement>(); |
1080 if (!element.hasHTMLTagName("input")) | 1102 if (!element.hasHTMLTagName("input")) |
1081 return false; | 1103 return false; |
1082 | 1104 |
1083 blink::WebInputElement input = element.to<blink::WebInputElement>(); | 1105 blink::WebInputElement input = element.to<blink::WebInputElement>(); |
1084 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); | 1106 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); |
1085 if (iter == login_to_password_info_.end()) | 1107 if (iter == login_to_password_info_.end()) |
1086 return false; | 1108 return false; |
1087 | 1109 |
1088 *found_input = input; | 1110 *found_input = input; |
1089 *found_password = iter->second; | 1111 *found_password = &iter->second; |
1090 return true; | 1112 return true; |
1091 } | 1113 } |
1092 | 1114 |
1093 void PasswordAutofillAgent::ClearPreview( | 1115 void PasswordAutofillAgent::ClearPreview( |
1094 blink::WebInputElement* username, | 1116 blink::WebInputElement* username, |
1095 blink::WebInputElement* password) { | 1117 blink::WebInputElement* password) { |
1096 if (!username->suggestedValue().isEmpty()) { | 1118 if (!username->suggestedValue().isEmpty()) { |
1097 username->setSuggestedValue(blink::WebString()); | 1119 username->setSuggestedValue(blink::WebString()); |
1098 username->setAutofilled(was_username_autofilled_); | 1120 username->setAutofilled(was_username_autofilled_); |
1099 username->setSelectionRange(username_selection_start_, | 1121 username->setSelectionRange(username_selection_start_, |
(...skipping 13 matching lines...) Expand all Loading... |
1113 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); | 1135 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); |
1114 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && | 1136 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && |
1115 password_form->password_value.empty() && | 1137 password_form->password_value.empty() && |
1116 password_form->new_password_value.empty())) { | 1138 password_form->new_password_value.empty())) { |
1117 return; | 1139 return; |
1118 } | 1140 } |
1119 provisionally_saved_forms_[frame].reset(password_form.release()); | 1141 provisionally_saved_forms_[frame].reset(password_form.release()); |
1120 } | 1142 } |
1121 | 1143 |
1122 } // namespace autofill | 1144 } // namespace autofill |
OLD | NEW |