Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(333)

Side by Side Diff: components/autofill/content/renderer/password_autofill_agent.cc

Issue 2035143002: Basic implementation of showing password fill dialog on page load (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Fix iOS compile Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « components/autofill/content/renderer/password_autofill_agent.h ('k') | components/autofill/core/common/autofill_switches.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698