Chromium Code Reviews| 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 |