| 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 <string> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/command_line.h" | |
| 15 #include "base/i18n/case_conversion.h" | 14 #include "base/i18n/case_conversion.h" |
| 16 #include "base/memory/linked_ptr.h" | 15 #include "base/memory/linked_ptr.h" |
| 17 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 18 #include "base/metrics/field_trial.h" | |
| 19 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 21 #include "build/build_config.h" | 19 #include "build/build_config.h" |
| 22 #include "components/autofill/content/common/autofill_messages.h" | 20 #include "components/autofill/content/common/autofill_messages.h" |
| 23 #include "components/autofill/content/renderer/form_autofill_util.h" | 21 #include "components/autofill/content/renderer/form_autofill_util.h" |
| 24 #include "components/autofill/content/renderer/password_form_conversion_utils.h" | 22 #include "components/autofill/content/renderer/password_form_conversion_utils.h" |
| 25 #include "components/autofill/content/renderer/renderer_save_password_progress_l
ogger.h" | 23 #include "components/autofill/content/renderer/renderer_save_password_progress_l
ogger.h" |
| 26 #include "components/autofill/core/common/autofill_constants.h" | 24 #include "components/autofill/core/common/autofill_constants.h" |
| 27 #include "components/autofill/core/common/autofill_switches.h" | |
| 28 #include "components/autofill/core/common/autofill_util.h" | 25 #include "components/autofill/core/common/autofill_util.h" |
| 29 #include "components/autofill/core/common/form_field_data.h" | 26 #include "components/autofill/core/common/form_field_data.h" |
| 30 #include "components/autofill/core/common/password_form.h" | 27 #include "components/autofill/core/common/password_form.h" |
| 31 #include "components/autofill/core/common/password_form_fill_data.h" | 28 #include "components/autofill/core/common/password_form_fill_data.h" |
| 32 #include "content/public/renderer/document_state.h" | 29 #include "content/public/renderer/document_state.h" |
| 33 #include "content/public/renderer/navigation_state.h" | 30 #include "content/public/renderer/navigation_state.h" |
| 34 #include "content/public/renderer/render_frame.h" | 31 #include "content/public/renderer/render_frame.h" |
| 35 #include "content/public/renderer/render_view.h" | 32 #include "content/public/renderer/render_view.h" |
| 36 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" | 33 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" |
| 37 #include "third_party/WebKit/public/platform/WebVector.h" | 34 #include "third_party/WebKit/public/platform/WebVector.h" |
| 38 #include "third_party/WebKit/public/web/WebAutofillClient.h" | 35 #include "third_party/WebKit/public/web/WebAutofillClient.h" |
| 39 #include "third_party/WebKit/public/web/WebDocument.h" | 36 #include "third_party/WebKit/public/web/WebDocument.h" |
| 40 #include "third_party/WebKit/public/web/WebElement.h" | 37 #include "third_party/WebKit/public/web/WebElement.h" |
| 41 #include "third_party/WebKit/public/web/WebFormElement.h" | 38 #include "third_party/WebKit/public/web/WebFormElement.h" |
| 42 #include "third_party/WebKit/public/web/WebInputEvent.h" | 39 #include "third_party/WebKit/public/web/WebInputEvent.h" |
| 43 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 40 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| 44 #include "third_party/WebKit/public/web/WebNode.h" | 41 #include "third_party/WebKit/public/web/WebNode.h" |
| 45 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" | 42 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" |
| 46 #include "third_party/WebKit/public/web/WebView.h" | 43 #include "third_party/WebKit/public/web/WebView.h" |
| 47 #include "ui/base/page_transition_types.h" | 44 #include "ui/base/page_transition_types.h" |
| 48 #include "ui/events/keycodes/keyboard_codes.h" | 45 #include "ui/events/keycodes/keyboard_codes.h" |
| 49 #include "url/gurl.h" | 46 #include "url/gurl.h" |
| 50 | 47 |
| 51 namespace autofill { | 48 namespace autofill { |
| 52 namespace { | 49 namespace { |
| 53 | 50 |
| 54 // The size above which we stop triggering autocomplete. | 51 // The size above which we stop triggering autocomplete. |
| 55 static const size_t kMaximumTextSizeForAutocomplete = 1000; | 52 static const size_t kMaximumTextSizeForAutocomplete = 1000; |
| 56 | 53 |
| 57 // Experiment information | |
| 58 const char kFillOnAccountSelectFieldTrialName[] = "FillOnAccountSelect"; | |
| 59 const char kFillOnAccountSelectFieldTrialEnabledWithHighlightGroup[] = | |
| 60 "EnableWithHighlight"; | |
| 61 const char kFillOnAccountSelectFieldTrialEnabledWithNoHighlightGroup[] = | |
| 62 "EnableWithNoHighlight"; | |
| 63 const char kDummyUsernameField[] = "anonymous_username"; | 54 const char kDummyUsernameField[] = "anonymous_username"; |
| 64 const char kDummyPasswordField[] = "anonymous_password"; | 55 const char kDummyPasswordField[] = "anonymous_password"; |
| 65 | 56 |
| 66 // Maps element names to the actual elements to simplify form filling. | 57 // Maps element names to the actual elements to simplify form filling. |
| 67 typedef std::map<base::string16, blink::WebInputElement> FormInputElementMap; | 58 typedef std::map<base::string16, blink::WebInputElement> FormInputElementMap; |
| 68 | 59 |
| 69 // Use the shorter name when referencing SavePasswordProgressLogger::StringID | 60 // Use the shorter name when referencing SavePasswordProgressLogger::StringID |
| 70 // values to spare line breaks. The code provides enough context for that | 61 // values to spare line breaks. The code provides enough context for that |
| 71 // already. | 62 // already. |
| 72 typedef SavePasswordProgressLogger Logger; | 63 typedef SavePasswordProgressLogger Logger; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 // iteration remain in the result set. | 211 // iteration remain in the result set. |
| 221 // Note: clear will remove a reference from each InputElement. | 212 // Note: clear will remove a reference from each InputElement. |
| 222 if (!found_input) { | 213 if (!found_input) { |
| 223 result->clear(); | 214 result->clear(); |
| 224 return false; | 215 return false; |
| 225 } | 216 } |
| 226 | 217 |
| 227 return true; | 218 return true; |
| 228 } | 219 } |
| 229 | 220 |
| 230 bool ShouldFillOnAccountSelect() { | |
| 231 std::string group_name = | |
| 232 base::FieldTrialList::FindFullName(kFillOnAccountSelectFieldTrialName); | |
| 233 | |
| 234 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 235 switches::kDisableFillOnAccountSelect)) { | |
| 236 return false; | |
| 237 } | |
| 238 | |
| 239 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 240 switches::kEnableFillOnAccountSelect) || | |
| 241 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 242 switches::kEnableFillOnAccountSelectNoHighlighting)) { | |
| 243 return true; | |
| 244 } | |
| 245 | |
| 246 return group_name == | |
| 247 kFillOnAccountSelectFieldTrialEnabledWithHighlightGroup || | |
| 248 group_name == | |
| 249 kFillOnAccountSelectFieldTrialEnabledWithNoHighlightGroup; | |
| 250 } | |
| 251 | |
| 252 bool ShouldHighlightFields() { | |
| 253 std::string group_name = | |
| 254 base::FieldTrialList::FindFullName(kFillOnAccountSelectFieldTrialName); | |
| 255 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 256 switches::kDisableFillOnAccountSelect) || | |
| 257 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 258 switches::kEnableFillOnAccountSelect)) { | |
| 259 return true; | |
| 260 } | |
| 261 | |
| 262 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 263 switches::kEnableFillOnAccountSelectNoHighlighting)) { | |
| 264 return false; | |
| 265 } | |
| 266 | |
| 267 return group_name != | |
| 268 kFillOnAccountSelectFieldTrialEnabledWithNoHighlightGroup; | |
| 269 } | |
| 270 | |
| 271 // Helper to search through |control_elements| for the specified input elements | 221 // Helper to search through |control_elements| for the specified input elements |
| 272 // in |data|, and add results to |result|. | 222 // in |data|, and add results to |result|. |
| 273 bool FindFormInputElements( | 223 bool FindFormInputElements( |
| 274 const std::vector<blink::WebFormControlElement>& control_elements, | 224 const std::vector<blink::WebFormControlElement>& control_elements, |
| 275 const PasswordFormFillData& data, | 225 const PasswordFormFillData& data, |
| 276 bool ambiguous_or_empty_names, | 226 bool ambiguous_or_empty_names, |
| 277 FormInputElementMap* result) { | 227 FormInputElementMap* result) { |
| 278 return FindFormInputElement(control_elements, data.password_field, | 228 return FindFormInputElement(control_elements, data.password_field, |
| 279 ambiguous_or_empty_names, result) && | 229 ambiguous_or_empty_names, result) && |
| 280 (!FillDataContainsFillableUsername(data) || | 230 (!FillDataContainsFillableUsername(data) || |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 base::StartsWith(base::i18n::ToLower(login.first), | 342 base::StartsWith(base::i18n::ToLower(login.first), |
| 393 current_username_lower, | 343 current_username_lower, |
| 394 base::CompareCase::SENSITIVE)) { | 344 base::CompareCase::SENSITIVE)) { |
| 395 return true; | 345 return true; |
| 396 } | 346 } |
| 397 } | 347 } |
| 398 | 348 |
| 399 return false; | 349 return false; |
| 400 } | 350 } |
| 401 | 351 |
| 402 // Returns true if there exists a credential suggestion whose username field is | |
| 403 // an exact match to the current username (not just a prefix). | |
| 404 bool HasExactMatchSuggestion(const PasswordFormFillData& fill_data, | |
| 405 const base::string16& current_username) { | |
| 406 if (fill_data.username_field.value == current_username) | |
| 407 return true; | |
| 408 | |
| 409 for (const auto& usernames : fill_data.other_possible_usernames) { | |
| 410 for (const auto& username_string : usernames.second) { | |
| 411 if (username_string == current_username) | |
| 412 return true; | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 for (const auto& login : fill_data.additional_logins) { | |
| 417 if (login.first == current_username) | |
| 418 return true; | |
| 419 } | |
| 420 | |
| 421 return false; | |
| 422 } | |
| 423 | |
| 424 // This function attempts to fill |username_element| and |password_element| | 352 // This function attempts to fill |username_element| and |password_element| |
| 425 // with values from |fill_data|. The |password_element| will only have the | 353 // with values from |fill_data|. The |password_element| will only have the |
| 426 // suggestedValue set, and will be registered for copying that to the real | 354 // suggestedValue set, and will be registered for copying that to the real |
| 427 // value through |registration_callback|. If a match is found, return true and | 355 // value through |registration_callback|. If a match is found, return true and |
| 428 // |nonscript_modified_values| will be modified with the autofilled credentials. | 356 // |nonscript_modified_values| will be modified with the autofilled credentials. |
| 429 bool FillUserNameAndPassword( | 357 bool FillUserNameAndPassword( |
| 430 blink::WebInputElement* username_element, | 358 blink::WebInputElement* username_element, |
| 431 blink::WebInputElement* password_element, | 359 blink::WebInputElement* password_element, |
| 432 const PasswordFormFillData& fill_data, | 360 const PasswordFormFillData& fill_data, |
| 433 bool exact_username_match, | 361 bool exact_username_match, |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 // If there is no autocompletable username field, and (a) is false, then the | 510 // If there is no autocompletable username field, and (a) is false, then the |
| 583 // username element cannot be autofilled, but the user should still be able to | 511 // username element cannot be autofilled, but the user should still be able to |
| 584 // select to fill the password element, so the password element must be marked | 512 // select to fill the password element, so the password element must be marked |
| 585 // as autofilled and the fill step should also be skipped if the user is not | 513 // as autofilled and the fill step should also be skipped if the user is not |
| 586 // in the "no highlighting" group. | 514 // in the "no highlighting" group. |
| 587 // | 515 // |
| 588 // In all other cases, do nothing. | 516 // In all other cases, do nothing. |
| 589 bool form_has_fillable_username = !username_field_name.empty() && | 517 bool form_has_fillable_username = !username_field_name.empty() && |
| 590 IsElementAutocompletable(username_element); | 518 IsElementAutocompletable(username_element); |
| 591 | 519 |
| 592 if (ShouldFillOnAccountSelect()) { | |
| 593 if (!ShouldHighlightFields()) { | |
| 594 return false; | |
| 595 } | |
| 596 | |
| 597 if (form_has_fillable_username) { | |
| 598 username_element.setAutofilled(true); | |
| 599 } else if (username_element.isNull() || | |
| 600 HasExactMatchSuggestion(fill_data, username_element.value())) { | |
| 601 password_element.setAutofilled(true); | |
| 602 } | |
| 603 return false; | |
| 604 } | |
| 605 | |
| 606 if (form_has_fillable_username && username_element.value().isEmpty()) { | 520 if (form_has_fillable_username && username_element.value().isEmpty()) { |
| 607 // TODO(tkent): Check maxlength and pattern. | 521 // TODO(tkent): Check maxlength and pattern. |
| 608 username_element.setValue(fill_data.username_field.value, true); | 522 username_element.setValue(fill_data.username_field.value, true); |
| 609 } | 523 } |
| 610 | 524 |
| 611 // Fill if we have an exact match for the username. Note that this sets | 525 // Fill if we have an exact match for the username. Note that this sets |
| 612 // username to autofilled. | 526 // username to autofilled. |
| 613 return FillUserNameAndPassword( | 527 return FillUserNameAndPassword( |
| 614 &username_element, &password_element, fill_data, | 528 &username_element, &password_element, fill_data, |
| 615 true /* exact_username_match */, false /* set_selection */, | 529 true /* exact_username_match */, false /* set_selection */, |
| (...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1321 } | 1235 } |
| 1322 | 1236 |
| 1323 // This is a new navigation, so require a new user gesture before filling in | 1237 // This is a new navigation, so require a new user gesture before filling in |
| 1324 // passwords. | 1238 // passwords. |
| 1325 gatekeeper_.Reset(); | 1239 gatekeeper_.Reset(); |
| 1326 } | 1240 } |
| 1327 | 1241 |
| 1328 void PasswordAutofillAgent::OnFillPasswordForm( | 1242 void PasswordAutofillAgent::OnFillPasswordForm( |
| 1329 int key, | 1243 int key, |
| 1330 const PasswordFormFillData& form_data) { | 1244 const PasswordFormFillData& form_data) { |
| 1245 std::vector<blink::WebInputElement> elements; |
| 1331 std::unique_ptr<RendererSavePasswordProgressLogger> logger; | 1246 std::unique_ptr<RendererSavePasswordProgressLogger> logger; |
| 1332 if (logging_state_active_) { | 1247 if (logging_state_active_) { |
| 1333 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); | 1248 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); |
| 1334 logger->LogMessage(Logger::STRING_ON_FILL_PASSWORD_FORM_METHOD); | 1249 logger->LogMessage(Logger::STRING_ON_FILL_PASSWORD_FORM_METHOD); |
| 1335 } | 1250 } |
| 1251 GetFillableElementFromFormData(key, form_data, logger.get(), &elements); |
| 1336 | 1252 |
| 1253 // If wait_for_username is true, we don't want to initially fill the form |
| 1254 // until the user types in a valid username. |
| 1255 if (form_data.wait_for_username) |
| 1256 return; |
| 1257 |
| 1258 for (auto element : elements) { |
| 1259 blink::WebInputElement username_element = |
| 1260 !element.isPasswordField() ? element : password_to_username_[element]; |
| 1261 blink::WebInputElement password_element = |
| 1262 element.isPasswordField() |
| 1263 ? element |
| 1264 : web_input_to_password_info_[element].password_field; |
| 1265 FillFormOnPasswordReceived( |
| 1266 form_data, username_element, password_element, |
| 1267 &nonscript_modified_values_, |
| 1268 base::Bind(&PasswordValueGatekeeper::RegisterElement, |
| 1269 base::Unretained(&gatekeeper_)), |
| 1270 logger.get()); |
| 1271 } |
| 1272 } |
| 1273 |
| 1274 void PasswordAutofillAgent::GetFillableElementFromFormData( |
| 1275 int key, |
| 1276 const PasswordFormFillData& form_data, |
| 1277 RendererSavePasswordProgressLogger* logger, |
| 1278 std::vector<blink::WebInputElement>* elements) { |
| 1279 DCHECK(elements); |
| 1337 bool ambiguous_or_empty_names = | 1280 bool ambiguous_or_empty_names = |
| 1338 DoesFormContainAmbiguousOrEmptyNames(form_data); | 1281 DoesFormContainAmbiguousOrEmptyNames(form_data); |
| 1339 FormElementsList forms; | 1282 FormElementsList forms; |
| 1340 FindFormElements(render_frame(), form_data, ambiguous_or_empty_names, &forms); | 1283 FindFormElements(render_frame(), form_data, ambiguous_or_empty_names, &forms); |
| 1341 if (logger) { | 1284 if (logger) { |
| 1342 logger->LogBoolean(Logger::STRING_AMBIGUOUS_OR_EMPTY_NAMES, | 1285 logger->LogBoolean(Logger::STRING_AMBIGUOUS_OR_EMPTY_NAMES, |
| 1343 ambiguous_or_empty_names); | 1286 ambiguous_or_empty_names); |
| 1344 logger->LogNumber(Logger::STRING_NUMBER_OF_POTENTIAL_FORMS_TO_FILL, | 1287 logger->LogNumber(Logger::STRING_NUMBER_OF_POTENTIAL_FORMS_TO_FILL, |
| 1345 forms.size()); | 1288 forms.size()); |
| 1346 logger->LogBoolean(Logger::STRING_FORM_DATA_WAIT, | 1289 logger->LogBoolean(Logger::STRING_FORM_DATA_WAIT, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1390 | 1333 |
| 1391 blink::WebInputElement main_element = | 1334 blink::WebInputElement main_element = |
| 1392 username_element.isNull() ? password_element : username_element; | 1335 username_element.isNull() ? password_element : username_element; |
| 1393 | 1336 |
| 1394 // We might have already filled this form if there are two <form> elements | 1337 // We might have already filled this form if there are two <form> elements |
| 1395 // with identical markup. | 1338 // with identical markup. |
| 1396 if (web_input_to_password_info_.find(main_element) != | 1339 if (web_input_to_password_info_.find(main_element) != |
| 1397 web_input_to_password_info_.end()) | 1340 web_input_to_password_info_.end()) |
| 1398 continue; | 1341 continue; |
| 1399 | 1342 |
| 1400 // If wait_for_username is true, we don't want to initially fill the form | |
| 1401 // until the user types in a valid username. | |
| 1402 if (!form_data.wait_for_username) { | |
| 1403 FillFormOnPasswordReceived( | |
| 1404 form_data, username_element, password_element, | |
| 1405 &nonscript_modified_values_, | |
| 1406 base::Bind(&PasswordValueGatekeeper::RegisterElement, | |
| 1407 base::Unretained(&gatekeeper_)), | |
| 1408 logger.get()); | |
| 1409 } | |
| 1410 | |
| 1411 PasswordInfo password_info; | 1343 PasswordInfo password_info; |
| 1412 password_info.fill_data = form_data; | 1344 password_info.fill_data = form_data; |
| 1413 password_info.key = key; | 1345 password_info.key = key; |
| 1414 password_info.password_field = password_element; | 1346 password_info.password_field = password_element; |
| 1415 web_input_to_password_info_[main_element] = password_info; | 1347 web_input_to_password_info_[main_element] = password_info; |
| 1416 if (!main_element.isPasswordField()) | 1348 if (!main_element.isPasswordField()) |
| 1417 password_to_username_[password_element] = username_element; | 1349 password_to_username_[password_element] = username_element; |
| 1350 if (elements) |
| 1351 elements->push_back(main_element); |
| 1418 } | 1352 } |
| 1419 } | 1353 } |
| 1420 | 1354 |
| 1421 void PasswordAutofillAgent::OnSetLoggingState(bool active) { | 1355 void PasswordAutofillAgent::OnSetLoggingState(bool active) { |
| 1422 logging_state_active_ = active; | 1356 logging_state_active_ = active; |
| 1423 } | 1357 } |
| 1424 | 1358 |
| 1425 void PasswordAutofillAgent::OnAutofillUsernameAndPasswordDataReceived( | 1359 void PasswordAutofillAgent::OnAutofillUsernameAndPasswordDataReceived( |
| 1426 const FormsPredictionsMap& predictions) { | 1360 const FormsPredictionsMap& predictions) { |
| 1427 form_predictions_.insert(predictions.begin(), predictions.end()); | 1361 form_predictions_.insert(predictions.begin(), predictions.end()); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1540 } | 1474 } |
| 1541 | 1475 |
| 1542 bool PasswordAutofillAgent::ProvisionallySavedPasswordIsValid() { | 1476 bool PasswordAutofillAgent::ProvisionallySavedPasswordIsValid() { |
| 1543 return provisionally_saved_form_ && | 1477 return provisionally_saved_form_ && |
| 1544 !provisionally_saved_form_->username_value.empty() && | 1478 !provisionally_saved_form_->username_value.empty() && |
| 1545 !(provisionally_saved_form_->password_value.empty() && | 1479 !(provisionally_saved_form_->password_value.empty() && |
| 1546 provisionally_saved_form_->new_password_value.empty()); | 1480 provisionally_saved_form_->new_password_value.empty()); |
| 1547 } | 1481 } |
| 1548 | 1482 |
| 1549 } // namespace autofill | 1483 } // namespace autofill |
| OLD | NEW |