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 <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <string> | |
10 #include <utility> | 11 #include <utility> |
11 | 12 |
12 #include "base/bind.h" | 13 #include "base/bind.h" |
13 #include "base/command_line.h" | 14 #include "base/command_line.h" |
14 #include "base/i18n/case_conversion.h" | 15 #include "base/i18n/case_conversion.h" |
15 #include "base/memory/linked_ptr.h" | 16 #include "base/memory/linked_ptr.h" |
16 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
17 #include "base/metrics/field_trial.h" | 18 #include "base/metrics/field_trial.h" |
18 #include "base/metrics/histogram_macros.h" | 19 #include "base/metrics/histogram_macros.h" |
19 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
426 // value through |registration_callback|. If a match is found, return true and | 427 // value through |registration_callback|. If a match is found, return true and |
427 // |nonscript_modified_values| will be modified with the autofilled credentials. | 428 // |nonscript_modified_values| will be modified with the autofilled credentials. |
428 bool FillUserNameAndPassword( | 429 bool FillUserNameAndPassword( |
429 blink::WebInputElement* username_element, | 430 blink::WebInputElement* username_element, |
430 blink::WebInputElement* password_element, | 431 blink::WebInputElement* password_element, |
431 const PasswordFormFillData& fill_data, | 432 const PasswordFormFillData& fill_data, |
432 bool exact_username_match, | 433 bool exact_username_match, |
433 bool set_selection, | 434 bool set_selection, |
434 std::map<const blink::WebInputElement, blink::WebString>* | 435 std::map<const blink::WebInputElement, blink::WebString>* |
435 nonscript_modified_values, | 436 nonscript_modified_values, |
436 base::Callback<void(blink::WebInputElement*)> registration_callback) { | 437 base::Callback<void(blink::WebInputElement*)> registration_callback, |
438 RendererSavePasswordProgressLogger* logger) { | |
439 if (logger) | |
440 logger->LogMessage(Logger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD); | |
441 | |
437 // Don't fill username if password can't be set. | 442 // Don't fill username if password can't be set. |
438 if (!IsElementAutocompletable(*password_element)) | 443 if (!IsElementAutocompletable(*password_element)) |
439 return false; | 444 return false; |
440 | 445 |
441 base::string16 current_username; | 446 base::string16 current_username; |
442 if (!username_element->isNull()) { | 447 if (!username_element->isNull()) { |
443 current_username = username_element->value(); | 448 current_username = username_element->value(); |
444 } | 449 } |
445 | 450 |
446 // username and password will contain the match found if any. | 451 // username and password will contain the match found if any. |
447 base::string16 username; | 452 base::string16 username; |
448 base::string16 password; | 453 base::string16 password; |
449 | 454 |
450 // Look for any suitable matches to current field text. | 455 // Look for any suitable matches to current field text. |
451 if (DoUsernamesMatch(fill_data.username_field.value, current_username, | 456 if (DoUsernamesMatch(fill_data.username_field.value, current_username, |
452 exact_username_match)) { | 457 exact_username_match)) { |
453 username = fill_data.username_field.value; | 458 username = fill_data.username_field.value; |
454 password = fill_data.password_field.value; | 459 password = fill_data.password_field.value; |
460 if (logger) | |
461 logger->LogMessage(Logger::STRING_USERNAMES_MATCH); | |
455 } else { | 462 } else { |
456 // Scan additional logins for a match. | 463 // Scan additional logins for a match. |
457 for (const auto& it : fill_data.additional_logins) { | 464 for (const auto& it : fill_data.additional_logins) { |
458 if (DoUsernamesMatch(it.first, current_username, exact_username_match)) { | 465 if (DoUsernamesMatch(it.first, current_username, exact_username_match)) { |
459 username = it.first; | 466 username = it.first; |
460 password = it.second.password; | 467 password = it.second.password; |
461 break; | 468 break; |
462 } | 469 } |
463 } | 470 } |
471 if (logger) { | |
472 logger->LogBoolean(Logger::STRING_MATCH_IN_ADDITIONAL, | |
473 !(username.empty() && password.empty())); | |
474 } | |
464 | 475 |
465 // Check possible usernames. | 476 // Check possible usernames. |
466 if (username.empty() && password.empty()) { | 477 if (username.empty() && password.empty()) { |
467 for (const auto& it : fill_data.other_possible_usernames) { | 478 for (const auto& it : fill_data.other_possible_usernames) { |
468 for (size_t i = 0; i < it.second.size(); ++i) { | 479 for (size_t i = 0; i < it.second.size(); ++i) { |
469 if (DoUsernamesMatch( | 480 if (DoUsernamesMatch( |
470 it.second[i], current_username, exact_username_match)) { | 481 it.second[i], current_username, exact_username_match)) { |
471 username = it.second[i]; | 482 username = it.second[i]; |
472 password = it.first.password; | 483 password = it.first.password; |
473 break; | 484 break; |
474 } | 485 } |
475 } | 486 } |
476 if (!username.empty() && !password.empty()) | 487 if (!username.empty() && !password.empty()) |
477 break; | 488 break; |
478 } | 489 } |
479 } | 490 } |
480 } | 491 } |
481 if (password.empty()) | 492 if (password.empty()) |
482 return false; | 493 return false; |
483 | 494 |
484 // TODO(tkent): Check maxlength and pattern for both username and password | 495 // TODO(tkent): Check maxlength and pattern for both username and password |
485 // fields. | 496 // fields. |
486 | 497 |
487 // Input matches the username, fill in required values. | 498 // Input matches the username, fill in required values. |
488 if (!username_element->isNull() && | 499 if (!username_element->isNull() && |
489 IsElementAutocompletable(*username_element)) { | 500 IsElementAutocompletable(*username_element)) { |
490 // TODO(vabr): Why not setSuggestedValue? http://crbug.com/507714 | 501 // TODO(crbug.com/507714): Why not setSuggestedValue? |
491 username_element->setValue(username, true); | 502 username_element->setValue(username, true); |
492 (*nonscript_modified_values)[*username_element] = username; | 503 (*nonscript_modified_values)[*username_element] = username; |
493 username_element->setAutofilled(true); | 504 username_element->setAutofilled(true); |
505 if (logger) | |
506 logger->LogMessage(Logger::STRING_USERNAME_FILLED); | |
dvadym
2016/04/26 14:47:34
It seems that it would be helpful to log also name
vabr (Chromium)
2016/04/26 16:55:41
While I agree, this would need some more changes t
| |
494 if (set_selection) { | 507 if (set_selection) { |
495 form_util::PreviewSuggestion(username, current_username, | 508 form_util::PreviewSuggestion(username, current_username, |
496 username_element); | 509 username_element); |
497 } | 510 } |
498 } else if (current_username != username) { | 511 } else if (current_username != username) { |
499 // If the username can't be filled and it doesn't match a saved password | 512 // If the username can't be filled and it doesn't match a saved password |
500 // as is, don't autofill a password. | 513 // as is, don't autofill a password. |
501 return false; | 514 return false; |
502 } | 515 } |
503 | 516 |
504 // Wait to fill in the password until a user gesture occurs. This is to make | 517 // Wait to fill in the password until a user gesture occurs. This is to make |
505 // sure that we do not fill in the DOM with a password until we believe the | 518 // sure that we do not fill in the DOM with a password until we believe the |
506 // user is intentionally interacting with the page. | 519 // user is intentionally interacting with the page. |
507 password_element->setSuggestedValue(password); | 520 password_element->setSuggestedValue(password); |
508 (*nonscript_modified_values)[*password_element] = password; | 521 (*nonscript_modified_values)[*password_element] = password; |
509 registration_callback.Run(password_element); | 522 registration_callback.Run(password_element); |
510 | 523 |
511 password_element->setAutofilled(true); | 524 password_element->setAutofilled(true); |
525 if (logger) | |
526 logger->LogMessage(Logger::STRING_PASSWORD_FILLED); | |
dvadym
2016/04/26 14:47:34
It seems that it would be helpful to log also name
vabr (Chromium)
2016/04/26 16:55:41
Ditto.
| |
512 return true; | 527 return true; |
513 } | 528 } |
514 | 529 |
515 // Attempts to fill |username_element| and |password_element| with the | 530 // Attempts to fill |username_element| and |password_element| with the |
516 // |fill_data|. Will use the data corresponding to the preferred username, | 531 // |fill_data|. Will use the data corresponding to the preferred username, |
517 // unless the |username_element| already has a value set. In that case, | 532 // unless the |username_element| already has a value set. In that case, |
518 // attempts to fill the password matching the already filled username, if | 533 // attempts to fill the password matching the already filled username, if |
519 // such a password exists. The |password_element| will have the | 534 // such a password exists. The |password_element| will have the |
520 // |suggestedValue| set, and |suggestedValue| will be registered for copying to | 535 // |suggestedValue| set, and |suggestedValue| will be registered for copying to |
521 // the real value through |registration_callback|. Returns true if the password | 536 // the real value through |registration_callback|. Returns true if the password |
522 // is filled. | 537 // is filled. |
523 bool FillFormOnPasswordReceived( | 538 bool FillFormOnPasswordReceived( |
524 const PasswordFormFillData& fill_data, | 539 const PasswordFormFillData& fill_data, |
525 blink::WebInputElement username_element, | 540 blink::WebInputElement username_element, |
526 blink::WebInputElement password_element, | 541 blink::WebInputElement password_element, |
527 std::map<const blink::WebInputElement, blink::WebString>* | 542 std::map<const blink::WebInputElement, blink::WebString>* |
528 nonscript_modified_values, | 543 nonscript_modified_values, |
529 base::Callback<void(blink::WebInputElement*)> registration_callback) { | 544 base::Callback<void(blink::WebInputElement*)> registration_callback, |
545 RendererSavePasswordProgressLogger* logger) { | |
530 // Do not fill if the password field is in a chain of iframes not having | 546 // Do not fill if the password field is in a chain of iframes not having |
531 // identical origin. | 547 // identical origin. |
532 blink::WebFrame* cur_frame = password_element.document().frame(); | 548 blink::WebFrame* cur_frame = password_element.document().frame(); |
533 blink::WebString bottom_frame_origin = | 549 blink::WebString bottom_frame_origin = |
534 cur_frame->getSecurityOrigin().toString(); | 550 cur_frame->getSecurityOrigin().toString(); |
535 | 551 |
536 DCHECK(cur_frame); | 552 DCHECK(cur_frame); |
537 | 553 |
538 while (cur_frame->parent()) { | 554 while (cur_frame->parent()) { |
539 cur_frame = cur_frame->parent(); | 555 cur_frame = cur_frame->parent(); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
587 return false; | 603 return false; |
588 } | 604 } |
589 | 605 |
590 if (form_has_fillable_username && username_element.value().isEmpty()) { | 606 if (form_has_fillable_username && username_element.value().isEmpty()) { |
591 // TODO(tkent): Check maxlength and pattern. | 607 // TODO(tkent): Check maxlength and pattern. |
592 username_element.setValue(fill_data.username_field.value, true); | 608 username_element.setValue(fill_data.username_field.value, true); |
593 } | 609 } |
594 | 610 |
595 // Fill if we have an exact match for the username. Note that this sets | 611 // Fill if we have an exact match for the username. Note that this sets |
596 // username to autofilled. | 612 // username to autofilled. |
597 return FillUserNameAndPassword(&username_element, | 613 return FillUserNameAndPassword( |
598 &password_element, | 614 &username_element, &password_element, fill_data, |
599 fill_data, | 615 true /* exact_username_match */, false /* set_selection */, |
600 true /* exact_username_match */, | 616 nonscript_modified_values, registration_callback, logger); |
601 false /* set_selection */, | |
602 nonscript_modified_values, | |
603 registration_callback); | |
604 } | 617 } |
605 | 618 |
606 // Takes a |map| with pointers as keys and linked_ptr as values, and returns | 619 // Takes a |map| with pointers as keys and linked_ptr as values, and returns |
607 // true if |key| is not NULL and |map| contains a non-NULL entry for |key|. | 620 // true if |key| is not NULL and |map| contains a non-NULL entry for |key|. |
608 // Makes sure not to create an entry as a side effect of using the operator []. | 621 // Makes sure not to create an entry as a side effect of using the operator []. |
609 template <class Key, class Value> | 622 template <class Key, class Value> |
610 bool ContainsNonNullEntryForNonNullKey( | 623 bool ContainsNonNullEntryForNonNullKey( |
611 const std::map<Key*, linked_ptr<Value>>& map, | 624 const std::map<Key*, linked_ptr<Value>>& map, |
612 Key* key) { | 625 Key* key) { |
613 if (!key) | 626 if (!key) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
687 return false; | 700 return false; |
688 | 701 |
689 blink::WebInputElement password = password_info.password_field; | 702 blink::WebInputElement password = password_info.password_field; |
690 if (!IsElementEditable(password)) | 703 if (!IsElementEditable(password)) |
691 return false; | 704 return false; |
692 | 705 |
693 blink::WebInputElement username = element; // We need a non-const. | 706 blink::WebInputElement username = element; // We need a non-const. |
694 | 707 |
695 // Do not set selection when ending an editing session, otherwise it can | 708 // Do not set selection when ending an editing session, otherwise it can |
696 // mess with focus. | 709 // mess with focus. |
697 FillUserNameAndPassword( | 710 FillUserNameAndPassword(&username, &password, fill_data, true, false, |
698 &username, &password, fill_data, true, false, | 711 &nonscript_modified_values_, |
699 &nonscript_modified_values_, | 712 base::Bind(&PasswordValueGatekeeper::RegisterElement, |
700 base::Bind(&PasswordValueGatekeeper::RegisterElement, | 713 base::Unretained(&gatekeeper_)), |
701 base::Unretained(&gatekeeper_))); | 714 nullptr); |
702 return true; | 715 return true; |
703 } | 716 } |
704 | 717 |
705 bool PasswordAutofillAgent::TextDidChangeInTextField( | 718 bool PasswordAutofillAgent::TextDidChangeInTextField( |
706 const blink::WebInputElement& element) { | 719 const blink::WebInputElement& element) { |
707 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 | 720 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 |
708 blink::WebInputElement mutable_element = element; // We need a non-const. | 721 blink::WebInputElement mutable_element = element; // We need a non-const. |
709 mutable_element.setAutofilled(false); | 722 mutable_element.setAutofilled(false); |
710 | 723 |
711 WebInputToPasswordInfoMap::iterator iter = | 724 WebInputToPasswordInfoMap::iterator iter = |
(...skipping 592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1304 } | 1317 } |
1305 | 1318 |
1306 // This is a new navigation, so require a new user gesture before filling in | 1319 // This is a new navigation, so require a new user gesture before filling in |
1307 // passwords. | 1320 // passwords. |
1308 gatekeeper_.Reset(); | 1321 gatekeeper_.Reset(); |
1309 } | 1322 } |
1310 | 1323 |
1311 void PasswordAutofillAgent::OnFillPasswordForm( | 1324 void PasswordAutofillAgent::OnFillPasswordForm( |
1312 int key, | 1325 int key, |
1313 const PasswordFormFillData& form_data) { | 1326 const PasswordFormFillData& form_data) { |
1327 std::unique_ptr<RendererSavePasswordProgressLogger> logger; | |
1328 if (logging_state_active_) { | |
1329 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); | |
1330 logger->LogMessage(Logger::STRING_ON_FILL_PASSWORD_FORM_METHOD); | |
1331 } | |
1332 | |
1314 bool ambiguous_or_empty_names = | 1333 bool ambiguous_or_empty_names = |
1315 DoesFormContainAmbiguousOrEmptyNames(form_data); | 1334 DoesFormContainAmbiguousOrEmptyNames(form_data); |
1316 FormElementsList forms; | 1335 FormElementsList forms; |
1317 FindFormElements(render_frame(), form_data, ambiguous_or_empty_names, &forms); | 1336 FindFormElements(render_frame(), form_data, ambiguous_or_empty_names, &forms); |
1337 if (logger) { | |
1338 logger->LogBoolean(Logger::STRING_AMBIGUOUS_OR_EMPTY_NAMES, | |
1339 ambiguous_or_empty_names); | |
1340 logger->LogNumber(Logger::STRING_NUMBER_OF_POTENTIAL_FORMS_TO_FILL, | |
1341 forms.size()); | |
1342 logger->LogBoolean(Logger::STRING_FORM_DATA_WAIT, | |
1343 form_data.wait_for_username); | |
1344 } | |
1318 for (const auto& form : forms) { | 1345 for (const auto& form : forms) { |
1319 base::string16 username_field_name; | 1346 base::string16 username_field_name; |
1320 base::string16 password_field_name = | 1347 base::string16 password_field_name = |
1321 FieldName(form_data.password_field, ambiguous_or_empty_names); | 1348 FieldName(form_data.password_field, ambiguous_or_empty_names); |
1322 bool form_contains_fillable_username_field = | 1349 bool form_contains_fillable_username_field = |
1323 FillDataContainsFillableUsername(form_data); | 1350 FillDataContainsFillableUsername(form_data); |
1324 if (form_contains_fillable_username_field) { | 1351 if (form_contains_fillable_username_field) { |
1325 username_field_name = | 1352 username_field_name = |
1326 FieldName(form_data.username_field, ambiguous_or_empty_names); | 1353 FieldName(form_data.username_field, ambiguous_or_empty_names); |
1327 } | 1354 } |
1355 if (logger) { | |
1356 logger->LogBoolean(Logger::STRING_CONTAINS_FILLABLE_USERNAME_FIELD, | |
1357 form_contains_fillable_username_field); | |
1358 logger->LogBoolean(Logger::STRING_USERNAME_FIELD_NAME_EMPTY, | |
1359 username_field_name.empty()); | |
1360 logger->LogBoolean(Logger::STRING_PASSWORD_FIELD_NAME_EMPTY, | |
1361 password_field_name.empty()); | |
1362 } | |
1328 | 1363 |
1329 // Attach autocomplete listener to enable selecting alternate logins. | 1364 // Attach autocomplete listener to enable selecting alternate logins. |
1330 blink::WebInputElement username_element; | 1365 blink::WebInputElement username_element; |
1331 blink::WebInputElement password_element; | 1366 blink::WebInputElement password_element; |
1332 | 1367 |
1333 // Check whether the password form has a username input field. | 1368 // Check whether the password form has a username input field. |
1334 if (!username_field_name.empty()) { | 1369 if (!username_field_name.empty()) { |
1335 const auto it = form.find(username_field_name); | 1370 const auto it = form.find(username_field_name); |
1336 DCHECK(it != form.end()); | 1371 DCHECK(it != form.end()); |
1337 username_element = it->second; | 1372 username_element = it->second; |
(...skipping 17 matching lines...) Expand all Loading... | |
1355 // We might have already filled this form if there are two <form> elements | 1390 // We might have already filled this form if there are two <form> elements |
1356 // with identical markup. | 1391 // with identical markup. |
1357 if (web_input_to_password_info_.find(main_element) != | 1392 if (web_input_to_password_info_.find(main_element) != |
1358 web_input_to_password_info_.end()) | 1393 web_input_to_password_info_.end()) |
1359 continue; | 1394 continue; |
1360 | 1395 |
1361 // If wait_for_username is true, we don't want to initially fill the form | 1396 // If wait_for_username is true, we don't want to initially fill the form |
1362 // until the user types in a valid username. | 1397 // until the user types in a valid username. |
1363 if (!form_data.wait_for_username) { | 1398 if (!form_data.wait_for_username) { |
1364 FillFormOnPasswordReceived( | 1399 FillFormOnPasswordReceived( |
1365 form_data, | 1400 form_data, username_element, password_element, |
1366 username_element, | |
1367 password_element, | |
1368 &nonscript_modified_values_, | 1401 &nonscript_modified_values_, |
1369 base::Bind(&PasswordValueGatekeeper::RegisterElement, | 1402 base::Bind(&PasswordValueGatekeeper::RegisterElement, |
1370 base::Unretained(&gatekeeper_))); | 1403 base::Unretained(&gatekeeper_)), |
1404 logger.get()); | |
1371 } | 1405 } |
1372 | 1406 |
1373 PasswordInfo password_info; | 1407 PasswordInfo password_info; |
1374 password_info.fill_data = form_data; | 1408 password_info.fill_data = form_data; |
1375 password_info.key = key; | 1409 password_info.key = key; |
1376 password_info.password_field = password_element; | 1410 password_info.password_field = password_element; |
1377 web_input_to_password_info_[main_element] = password_info; | 1411 web_input_to_password_info_[main_element] = password_info; |
1378 if (!main_element.isPasswordField()) | 1412 if (!main_element.isPasswordField()) |
1379 password_to_username_[password_element] = username_element; | 1413 password_to_username_[password_element] = username_element; |
1380 } | 1414 } |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1501 } | 1535 } |
1502 | 1536 |
1503 bool PasswordAutofillAgent::ProvisionallySavedPasswordIsValid() { | 1537 bool PasswordAutofillAgent::ProvisionallySavedPasswordIsValid() { |
1504 return provisionally_saved_form_ && | 1538 return provisionally_saved_form_ && |
1505 !provisionally_saved_form_->username_value.empty() && | 1539 !provisionally_saved_form_->username_value.empty() && |
1506 !(provisionally_saved_form_->password_value.empty() && | 1540 !(provisionally_saved_form_->password_value.empty() && |
1507 provisionally_saved_form_->new_password_value.empty()); | 1541 provisionally_saved_form_->new_password_value.empty()); |
1508 } | 1542 } |
1509 | 1543 |
1510 } // namespace autofill | 1544 } // namespace autofill |
OLD | NEW |