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 |