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

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

Issue 2917933002: [PasswordGeneration] Improve change/confirm password field detection. (Closed)
Patch Set: Address more comments. Created 3 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_generation_agent.h" 5 #include "components/autofill/content/renderer/password_generation_agent.h"
6 6
7 #include <algorithm>
7 #include <memory> 8 #include <memory>
9 #include <utility>
8 10
9 #include "base/command_line.h" 11 #include "base/command_line.h"
10 #include "base/logging.h" 12 #include "base/logging.h"
11 #include "base/threading/thread_task_runner_handle.h" 13 #include "base/threading/thread_task_runner_handle.h"
12 #include "components/autofill/content/renderer/form_autofill_util.h" 14 #include "components/autofill/content/renderer/form_autofill_util.h"
13 #include "components/autofill/content/renderer/form_classifier.h" 15 #include "components/autofill/content/renderer/form_classifier.h"
14 #include "components/autofill/content/renderer/password_autofill_agent.h" 16 #include "components/autofill/content/renderer/password_autofill_agent.h"
15 #include "components/autofill/content/renderer/password_form_conversion_utils.h" 17 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
16 #include "components/autofill/core/common/autofill_switches.h" 18 #include "components/autofill/core/common/autofill_switches.h"
17 #include "components/autofill/core/common/form_data.h" 19 #include "components/autofill/core/common/form_data.h"
(...skipping 14 matching lines...) Expand all
32 #include "third_party/WebKit/public/web/WebLocalFrame.h" 34 #include "third_party/WebKit/public/web/WebLocalFrame.h"
33 #include "third_party/WebKit/public/web/WebView.h" 35 #include "third_party/WebKit/public/web/WebView.h"
34 #include "ui/gfx/geometry/rect.h" 36 #include "ui/gfx/geometry/rect.h"
35 37
36 namespace autofill { 38 namespace autofill {
37 39
38 namespace { 40 namespace {
39 41
40 using Logger = autofill::SavePasswordProgressLogger; 42 using Logger = autofill::SavePasswordProgressLogger;
41 43
42 // Returns true if we think that this form is for account creation. |passwords| 44 // Returns true if we think that this form is for account creation. Password
43 // is filled with the password field(s) in the form. 45 // field(s) of the form are pushed back to |passwords|.
44 bool GetAccountCreationPasswordFields( 46 bool GetAccountCreationPasswordFields(
45 const std::vector<blink::WebFormControlElement>& control_elements, 47 const std::vector<blink::WebFormControlElement>& control_elements,
46 std::vector<blink::WebInputElement>* passwords) { 48 std::vector<blink::WebInputElement>* passwords) {
47 for (size_t i = 0; i < control_elements.size(); i++) { 49 for (const auto& control_element : control_elements) {
48 const blink::WebInputElement* input_element = 50 const blink::WebInputElement* input_element =
49 ToWebInputElement(&control_elements[i]); 51 ToWebInputElement(&control_element);
50 if (input_element && input_element->IsTextField()) { 52 if (input_element && input_element->IsTextField() &&
51 if (input_element->IsPasswordField()) 53 input_element->IsPasswordField()) {
52 passwords->push_back(*input_element); 54 passwords->push_back(*input_element);
53 } 55 }
54 } 56 }
55 return !passwords->empty(); 57 return !passwords->empty();
56 } 58 }
57 59
58 bool ContainsURL(const std::vector<GURL>& urls, const GURL& url) { 60 bool ContainsURL(const std::vector<GURL>& urls, const GURL& url) {
59 return std::find(urls.begin(), urls.end(), url) != urls.end(); 61 return std::find(urls.begin(), urls.end(), url) != urls.end();
60 } 62 }
61 63
62 // Calculates the signature of |form| and searches it in |forms|. 64 // Calculates the signature of |form| and searches it in |forms|.
63 const PasswordFormGenerationData* FindFormGenerationData( 65 const PasswordFormGenerationData* FindFormGenerationData(
64 const std::vector<PasswordFormGenerationData>& forms, 66 const std::vector<PasswordFormGenerationData>& forms,
65 const PasswordForm& form) { 67 const PasswordForm& form) {
66 FormSignature form_signature = CalculateFormSignature(form.form_data); 68 FormSignature form_signature = CalculateFormSignature(form.form_data);
67 for (const auto& form_it : forms) { 69 for (const auto& form_it : forms) {
68 if (form_it.form_signature == form_signature) 70 if (form_it.form_signature == form_signature)
69 return &form_it; 71 return &form_it;
70 } 72 }
71 return nullptr; 73 return nullptr;
72 } 74 }
73 75
74 // This function returns a vector of password fields into which Chrome should 76 // Returns a vector of up to 2 password fields with autocomplete attribute set
75 // fill the generated password. It assumes that |field_signature| describes the 77 // to "new-password". These will be filled with the generated password.
76 // field where Chrome shows the password generation prompt. It returns no more 78 std::vector<blink::WebInputElement> FindNewPasswordElementsMarkedBySite(
77 // than 2 elements. 79 const std::vector<blink::WebInputElement>& all_password_elements) {
80 std::vector<blink::WebInputElement> passwords;
81
82 auto is_new_password_field = [](const blink::WebInputElement& element) {
83 return HasAutocompleteAttributeValue(element, "new-password");
84 };
85
86 auto field_iter =
87 std::find_if(all_password_elements.begin(), all_password_elements.end(),
88 is_new_password_field);
89 if (field_iter != all_password_elements.end()) {
90 passwords.push_back(*field_iter++);
91 field_iter = std::find_if(field_iter, all_password_elements.end(),
92 is_new_password_field);
93 if (field_iter != all_password_elements.end())
94 passwords.push_back(*field_iter);
95 }
96
97 return passwords;
98 }
99
100 // Returns a vector of up to 2 password fields into which Chrome should fill the
101 // generated password. It assumes that |field_signature| describes the field
102 // where Chrome shows the password generation prompt.
78 std::vector<blink::WebInputElement> FindPasswordElementsForGeneration( 103 std::vector<blink::WebInputElement> FindPasswordElementsForGeneration(
79 const std::vector<blink::WebInputElement>& all_password_elements, 104 const std::vector<blink::WebInputElement>& all_password_elements,
80 const PasswordFormGenerationData& generation_data) { 105 const PasswordFormGenerationData& generation_data) {
81 auto generation_field_iter = all_password_elements.end(); 106 auto generation_field_iter = all_password_elements.end();
82 auto confirmation_field_iter = all_password_elements.end(); 107 auto confirmation_field_iter = all_password_elements.end();
83 for (auto iter = all_password_elements.begin(); 108 for (auto iter = all_password_elements.begin();
84 iter != all_password_elements.end(); ++iter) { 109 iter != all_password_elements.end(); ++iter) {
85 const blink::WebInputElement& input = *iter; 110 const blink::WebInputElement& input = *iter;
86 FieldSignature signature = CalculateFieldSignatureByNameAndType( 111 FieldSignature signature = CalculateFieldSignatureByNameAndType(
87 input.NameForAutofill().Utf16(), input.FormControlType().Utf8()); 112 input.NameForAutofill().Utf16(), input.FormControlType().Utf8());
88 if (signature == generation_data.field_signature) 113 if (signature == generation_data.field_signature) {
89 generation_field_iter = iter; 114 generation_field_iter = iter;
90 else if (generation_data.confirmation_field_signature && 115 } else if (generation_data.confirmation_field_signature &&
91 signature == *generation_data.confirmation_field_signature) 116 signature == *generation_data.confirmation_field_signature) {
92 confirmation_field_iter = iter; 117 confirmation_field_iter = iter;
118 }
93 } 119 }
94 120
95 std::vector<blink::WebInputElement> passwords; 121 std::vector<blink::WebInputElement> passwords;
96 if (generation_field_iter != all_password_elements.end()) { 122 if (generation_field_iter != all_password_elements.end()) {
97 passwords.push_back(*generation_field_iter); 123 passwords.push_back(*generation_field_iter);
98 124
99 if (confirmation_field_iter == all_password_elements.end()) 125 if (confirmation_field_iter == all_password_elements.end())
100 confirmation_field_iter = generation_field_iter + 1; 126 confirmation_field_iter = generation_field_iter + 1;
101 if (confirmation_field_iter != all_password_elements.end()) 127 if (confirmation_field_iter != all_password_elements.end())
102 passwords.push_back(*confirmation_field_iter); 128 passwords.push_back(*confirmation_field_iter);
103 } 129 }
104 return passwords; 130 return passwords;
105 } 131 }
106 132
107 void CopyElementValueToOtherInputElements( 133 void CopyElementValueToOtherInputElements(
108 const blink::WebInputElement* element, 134 const blink::WebInputElement* element,
109 std::vector<blink::WebInputElement>* elements) { 135 std::vector<blink::WebInputElement>* elements) {
110 for (blink::WebInputElement& it : *elements) { 136 for (blink::WebInputElement& it : *elements) {
111 if (*element != it) { 137 if (*element != it) {
112 it.SetAutofillValue(element->Value()); 138 it.SetAutofillValue(element->Value());
113 } 139 }
114 } 140 }
115 } 141 }
116 142
117 bool AutocompleteAttributesSetForGeneration(const PasswordForm& form) {
118 return form.username_marked_by_site && form.new_password_marked_by_site;
119 }
120
121 } // namespace 143 } // namespace
122 144
123 PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData( 145 PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData(
124 linked_ptr<PasswordForm> password_form, 146 linked_ptr<PasswordForm> password_form,
125 std::vector<blink::WebInputElement> passwords) 147 std::vector<blink::WebInputElement> passwords)
126 : form(password_form), 148 : form(password_form), password_elements(std::move(passwords)) {}
127 password_elements(passwords) {}
128 149
129 PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData( 150 PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData(
130 const AccountCreationFormData& other) = default; 151 const AccountCreationFormData& other) = default;
131 152
132 PasswordGenerationAgent::AccountCreationFormData::~AccountCreationFormData() {} 153 PasswordGenerationAgent::AccountCreationFormData::~AccountCreationFormData() {}
133 154
134 PasswordGenerationAgent::PasswordGenerationAgent( 155 PasswordGenerationAgent::PasswordGenerationAgent(
135 content::RenderFrame* render_frame, 156 content::RenderFrame* render_frame,
136 PasswordAutofillAgent* password_agent) 157 PasswordAutofillAgent* password_agent)
137 : content::RenderFrameObserver(render_frame), 158 : content::RenderFrameObserver(render_frame),
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 GURL realm(password_form->signon_realm); 291 GURL realm(password_form->signon_realm);
271 if (realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) 292 if (realm == GaiaUrls::GetInstance()->gaia_login_form_realm())
272 continue; 293 continue;
273 294
274 std::vector<blink::WebInputElement> passwords; 295 std::vector<blink::WebInputElement> passwords;
275 if (GetAccountCreationPasswordFields( 296 if (GetAccountCreationPasswordFields(
276 form_util::ExtractAutofillableElementsInForm(forms[i]), 297 form_util::ExtractAutofillableElementsInForm(forms[i]),
277 &passwords)) { 298 &passwords)) {
278 if (form_classifier_enabled_) 299 if (form_classifier_enabled_)
279 RunFormClassifierAndSaveVote(forms[i], *password_form); 300 RunFormClassifierAndSaveVote(forms[i], *password_form);
280 AccountCreationFormData ac_form_data( 301 possible_account_creation_forms_.emplace_back(
281 make_linked_ptr(password_form.release()), passwords); 302 make_linked_ptr(password_form.release()), std::move(passwords));
282 possible_account_creation_forms_.push_back(ac_form_data);
283 } 303 }
284 } 304 }
285 305
286 if (!possible_account_creation_forms_.empty()) { 306 if (!possible_account_creation_forms_.empty()) {
287 LogNumber( 307 LogNumber(
288 Logger::STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS, 308 Logger::STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS,
289 possible_account_creation_forms_.size()); 309 possible_account_creation_forms_.size());
290 DetermineGenerationElement(); 310 DetermineGenerationElement();
291 } 311 }
292 } 312 }
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 if (possible_account_creation_forms_.empty()) { 402 if (possible_account_creation_forms_.empty()) {
383 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS); 403 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS);
384 return; 404 return;
385 } 405 }
386 406
387 // Note that no messages will be sent if this feature is disabled 407 // Note that no messages will be sent if this feature is disabled
388 // (e.g. password saving is disabled). 408 // (e.g. password saving is disabled).
389 for (auto& possible_form_data : possible_account_creation_forms_) { 409 for (auto& possible_form_data : possible_account_creation_forms_) {
390 PasswordForm* possible_password_form = possible_form_data.form.get(); 410 PasswordForm* possible_password_form = possible_form_data.form.get();
391 const PasswordFormGenerationData* generation_data = nullptr; 411 const PasswordFormGenerationData* generation_data = nullptr;
412
413 std::vector<blink::WebInputElement> password_elements;
392 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 414 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
393 switches::kLocalHeuristicsOnlyForPasswordGeneration)) { 415 switches::kLocalHeuristicsOnlyForPasswordGeneration)) {
416 password_elements = possible_form_data.password_elements;
394 VLOG(2) << "Bypassing additional checks."; 417 VLOG(2) << "Bypassing additional checks.";
395 } else if (!ContainsURL(not_blacklisted_password_form_origins_, 418 } else if (!ContainsURL(not_blacklisted_password_form_origins_,
396 possible_password_form->origin)) { 419 possible_password_form->origin)) {
397 LogMessage(Logger::STRING_GENERATION_RENDERER_NOT_BLACKLISTED); 420 LogMessage(Logger::STRING_GENERATION_RENDERER_NOT_BLACKLISTED);
398 continue; 421 continue;
399 } else { 422 } else {
400 generation_data = FindFormGenerationData(generation_enabled_forms_, 423 generation_data = FindFormGenerationData(generation_enabled_forms_,
401 *possible_password_form); 424 *possible_password_form);
402 if (!generation_data) { 425 if (generation_data) {
403 if (AutocompleteAttributesSetForGeneration(*possible_password_form)) { 426 password_elements = FindPasswordElementsForGeneration(
404 LogMessage(Logger::STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE); 427 possible_form_data.password_elements, *generation_data);
405 password_generation::LogPasswordGenerationEvent( 428 } else {
406 password_generation::AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION); 429 if (!possible_password_form->new_password_marked_by_site) {
407 } else {
408 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL); 430 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL);
409 continue; 431 continue;
410 } 432 }
433
434 LogMessage(Logger::STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE);
435 password_generation::LogPasswordGenerationEvent(
436 password_generation::AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION);
437
438 password_elements = FindNewPasswordElementsMarkedBySite(
439 possible_form_data.password_elements);
411 } 440 }
412 } 441 }
442
413 LogMessage(Logger::STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND); 443 LogMessage(Logger::STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND);
414 std::vector<blink::WebInputElement> password_elements =
415 generation_data
416 ? FindPasswordElementsForGeneration(
417 possible_form_data.password_elements, *generation_data)
418 : possible_form_data.password_elements;
419 if (password_elements.empty()) { 444 if (password_elements.empty()) {
420 // It might be if JavaScript changes field names. 445 // It might be if JavaScript changes field names.
421 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_FIELD_FOUND); 446 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_FIELD_FOUND);
422 return; 447 return;
423 } 448 }
449
424 generation_form_data_.reset(new AccountCreationFormData( 450 generation_form_data_.reset(new AccountCreationFormData(
425 possible_form_data.form, std::move(password_elements))); 451 possible_form_data.form, std::move(password_elements)));
426 generation_element_ = generation_form_data_->password_elements[0]; 452 generation_element_ = generation_form_data_->password_elements[0];
427 generation_element_.SetAttribute("aria-autocomplete", "list"); 453 generation_element_.SetAttribute("aria-autocomplete", "list");
428 password_generation::LogPasswordGenerationEvent( 454 password_generation::LogPasswordGenerationEvent(
429 password_generation::GENERATION_AVAILABLE); 455 password_generation::GENERATION_AVAILABLE);
430 possible_account_creation_forms_.clear(); 456 possible_account_creation_forms_.clear();
431 GetPasswordManagerClient()->GenerationAvailableForForm( 457 GetPasswordManagerClient()->GenerationAvailableForForm(
432 *generation_form_data_->form); 458 *generation_form_data_->form);
433 return; 459 return;
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 651
626 void PasswordGenerationAgent::LogNumber(Logger::StringID message_id, 652 void PasswordGenerationAgent::LogNumber(Logger::StringID message_id,
627 int number) { 653 int number) {
628 if (!password_agent_->logging_state_active()) 654 if (!password_agent_->logging_state_active())
629 return; 655 return;
630 RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get()); 656 RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get());
631 logger.LogNumber(message_id, number); 657 logger.LogNumber(message_id, number);
632 } 658 }
633 659
634 } // namespace autofill 660 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698