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

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

Issue 2318533002: [Password Generation] Use signatures for form matching (Closed)
Patch Set: Sent to review Created 4 years, 3 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 <memory> 7 #include <memory>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "components/autofill/content/common/autofill_messages.h" 11 #include "components/autofill/content/common/autofill_messages.h"
12 #include "components/autofill/content/renderer/form_autofill_util.h" 12 #include "components/autofill/content/renderer/form_autofill_util.h"
13 #include "components/autofill/content/renderer/form_classifier.h" 13 #include "components/autofill/content/renderer/form_classifier.h"
14 #include "components/autofill/content/renderer/password_autofill_agent.h" 14 #include "components/autofill/content/renderer/password_autofill_agent.h"
15 #include "components/autofill/content/renderer/password_form_conversion_utils.h" 15 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
16 #include "components/autofill/core/common/autofill_switches.h" 16 #include "components/autofill/core/common/autofill_switches.h"
17 #include "components/autofill/core/common/form_data.h" 17 #include "components/autofill/core/common/form_data.h"
18 #include "components/autofill/core/common/password_form.h" 18 #include "components/autofill/core/common/password_form.h"
19 #include "components/autofill/core/common/password_form_generation_data.h" 19 #include "components/autofill/core/common/password_form_generation_data.h"
20 #include "components/autofill/core/common/password_generation_util.h" 20 #include "components/autofill/core/common/password_generation_util.h"
21 #include "components/autofill/core/common/signatures_util.h"
21 #include "content/public/renderer/render_frame.h" 22 #include "content/public/renderer/render_frame.h"
22 #include "content/public/renderer/render_view.h" 23 #include "content/public/renderer/render_view.h"
23 #include "google_apis/gaia/gaia_urls.h" 24 #include "google_apis/gaia/gaia_urls.h"
24 #include "services/shell/public/cpp/interface_registry.h" 25 #include "services/shell/public/cpp/interface_registry.h"
25 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" 26 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
26 #include "third_party/WebKit/public/platform/WebVector.h" 27 #include "third_party/WebKit/public/platform/WebVector.h"
27 #include "third_party/WebKit/public/web/WebDocument.h" 28 #include "third_party/WebKit/public/web/WebDocument.h"
28 #include "third_party/WebKit/public/web/WebFormElement.h" 29 #include "third_party/WebKit/public/web/WebFormElement.h"
29 #include "third_party/WebKit/public/web/WebInputElement.h" 30 #include "third_party/WebKit/public/web/WebInputElement.h"
30 #include "third_party/WebKit/public/web/WebLocalFrame.h" 31 #include "third_party/WebKit/public/web/WebLocalFrame.h"
(...skipping 19 matching lines...) Expand all
50 passwords->push_back(*input_element); 51 passwords->push_back(*input_element);
51 } 52 }
52 } 53 }
53 return !passwords->empty(); 54 return !passwords->empty();
54 } 55 }
55 56
56 bool ContainsURL(const std::vector<GURL>& urls, const GURL& url) { 57 bool ContainsURL(const std::vector<GURL>& urls, const GURL& url) {
57 return std::find(urls.begin(), urls.end(), url) != urls.end(); 58 return std::find(urls.begin(), urls.end(), url) != urls.end();
58 } 59 }
59 60
60 // Finds a form in |forms| that has the same action and name as |form|. 61 // Calculates the signature of |form| and searches it in |forms|.
61 // If the action of a form in |forms| is empty, it uses |base_url| as action. It
62 // also strips parameters of the action.
63 const PasswordFormGenerationData* FindFormGenerationData( 62 const PasswordFormGenerationData* FindFormGenerationData(
64 const std::vector<PasswordFormGenerationData>& forms, 63 const std::vector<PasswordFormGenerationData>& forms,
65 const PasswordForm& form, 64 const PasswordForm& form) {
66 const GURL& base_url) { 65 FormSignature form_signature = CalculateFormSignature(form.form_data);
dvadym 2016/09/07 17:29:35 I was wondering, whether we want to cache this sig
67 for (const auto& form_it : forms) { 66 for (const auto& form_it : forms) {
68 GURL action = form_it.action; 67 if (form_it.form_signature == form_signature)
69 if (action.is_empty())
70 action = base_url;
71 action = form_util::StripAuthAndParams(action);
72 if (form_it.name == form.form_data.name && action == form.action)
73 return &form_it; 68 return &form_it;
74 } 69 }
75 return nullptr; 70 return nullptr;
76 } 71 }
77 72
78 // This function returns a vector of password fields into which Chrome should 73 // This function returns a vector of password fields into which Chrome should
79 // fill the generated password. It assumes that |field_data| describes the field 74 // fill the generated password. It assumes that |field_signature| describes the
80 // where Chrome shows the password generation prompt. It returns no more 75 // field where Chrome shows the password generation prompt. It returns no more
81 // than 2 elements. 76 // than 2 elements.
82 std::vector<blink::WebInputElement> FindPasswordElementsForGeneration( 77 std::vector<blink::WebInputElement> FindPasswordElementsForGeneration(
83 const std::vector<blink::WebInputElement>& all_password_elements, 78 const std::vector<blink::WebInputElement>& all_password_elements,
84 const base::string16& field_name) { 79 const FieldSignature field_signature) {
85 auto iter = 80 auto iter = std::find_if(
86 std::find_if(all_password_elements.begin(), all_password_elements.end(), 81 all_password_elements.begin(), all_password_elements.end(),
87 [&field_name](const blink::WebInputElement& input) { 82 [&field_signature](const blink::WebInputElement& input) {
88 // Make explicit conversion before comparing with string16. 83 FieldSignature signature = CalculateFieldSignatureByNameAndType(
89 base::string16 input_name = input.nameForAutofill(); 84 input.nameForAutofill(), input.formControlType().utf8());
90 return input_name == field_name; 85 return signature == field_signature;
91 }); 86 });
92 std::vector<blink::WebInputElement> passwords; 87 std::vector<blink::WebInputElement> passwords;
93 88
94 // We copy not more than 2 fields because occasionally there are forms where 89 // We copy not more than 2 fields because occasionally there are forms where
95 // the security question answers are put in password fields and we don't want 90 // the security question answers are put in password fields and we don't want
96 // to fill those. 91 // to fill those.
97 for (; iter != all_password_elements.end() && passwords.size() < 2; ++iter) { 92 for (; iter != all_password_elements.end() && passwords.size() < 2; ++iter)
98 passwords.push_back(*iter); 93 passwords.push_back(*iter);
99 }
100 return passwords; 94 return passwords;
101 } 95 }
102 96
103 void CopyElementValueToOtherInputElements( 97 void CopyElementValueToOtherInputElements(
104 const blink::WebInputElement* element, 98 const blink::WebInputElement* element,
105 std::vector<blink::WebInputElement>* elements) { 99 std::vector<blink::WebInputElement>* elements) {
106 for (blink::WebInputElement& it : *elements) { 100 for (blink::WebInputElement& it : *elements) {
107 if (*element != it) { 101 if (*element != it) {
108 it.setValue(element->value(), true /* sendEvents */); 102 it.setValue(element->value(), true /* sendEvents */);
109 } 103 }
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 const PasswordFormGenerationData* generation_data = nullptr; 377 const PasswordFormGenerationData* generation_data = nullptr;
384 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 378 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
385 switches::kLocalHeuristicsOnlyForPasswordGeneration)) { 379 switches::kLocalHeuristicsOnlyForPasswordGeneration)) {
386 VLOG(2) << "Bypassing additional checks."; 380 VLOG(2) << "Bypassing additional checks.";
387 } else if (!ContainsURL(not_blacklisted_password_form_origins_, 381 } else if (!ContainsURL(not_blacklisted_password_form_origins_,
388 possible_password_form->origin)) { 382 possible_password_form->origin)) {
389 VLOG(2) << "Have not received confirmation that password form isn't " 383 VLOG(2) << "Have not received confirmation that password form isn't "
390 << "blacklisted"; 384 << "blacklisted";
391 continue; 385 continue;
392 } else { 386 } else {
393 generation_data = FindFormGenerationData( 387 generation_data = FindFormGenerationData(generation_enabled_forms_,
394 generation_enabled_forms_, *possible_password_form, 388 *possible_password_form);
395 render_frame()->GetWebFrame()->document().baseURL());
396 if (!generation_data) { 389 if (!generation_data) {
397 if (AutocompleteAttributesSetForGeneration(*possible_password_form)) { 390 if (AutocompleteAttributesSetForGeneration(*possible_password_form)) {
398 VLOG(2) << "Ignoring lack of Autofill signal due to Autocomplete " 391 VLOG(2) << "Ignoring lack of Autofill signal due to Autocomplete "
399 << "attributes"; 392 << "attributes";
400 password_generation::LogPasswordGenerationEvent( 393 password_generation::LogPasswordGenerationEvent(
401 password_generation::AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION); 394 password_generation::AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION);
402 } else { 395 } else {
403 VLOG(2) 396 VLOG(2)
404 << "Have not received confirmation from Autofill that form is " 397 << "Have not received confirmation from Autofill that form is "
405 << "used for account creation"; 398 << "used for account creation";
406 continue; 399 continue;
407 } 400 }
408 } 401 }
409 } 402 }
410 403
411 VLOG(2) << "Password generation eligible form found"; 404 VLOG(2) << "Password generation eligible form found";
412 std::vector<blink::WebInputElement> password_elements = 405 std::vector<blink::WebInputElement> password_elements =
413 generation_data ? FindPasswordElementsForGeneration( 406 generation_data ? FindPasswordElementsForGeneration(
414 possible_form_data.password_elements, 407 possible_form_data.password_elements,
415 generation_data->generation_field.name) 408 generation_data->field_signature)
416 : possible_form_data.password_elements; 409 : possible_form_data.password_elements;
417 if (password_elements.empty()) { 410 if (password_elements.empty()) {
418 // It might be if JavaScript changes field names. 411 // It might be if JavaScript changes field names.
419 VLOG(2) << "Fields for generation are not found"; 412 VLOG(2) << "Fields for generation are not found";
420 return; 413 return;
421 } 414 }
422 generation_form_data_.reset(new AccountCreationFormData( 415 generation_form_data_.reset(new AccountCreationFormData(
423 possible_form_data.form, std::move(password_elements))); 416 possible_form_data.form, std::move(password_elements)));
424 generation_element_ = generation_form_data_->password_elements[0]; 417 generation_element_ = generation_form_data_->password_elements[0];
425 generation_element_.setAttribute("aria-autocomplete", "list"); 418 generation_element_.setAttribute("aria-autocomplete", "list");
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 form_util::GetUnownedFormFieldElements(doc.all(), nullptr); 560 form_util::GetUnownedFormFieldElements(doc.all(), nullptr);
568 } 561 }
569 562
570 if (!password_form) 563 if (!password_form)
571 return; 564 return;
572 565
573 generation_element_ = last_focused_password_element_; 566 generation_element_ = last_focused_password_element_;
574 std::vector<blink::WebInputElement> password_elements; 567 std::vector<blink::WebInputElement> password_elements;
575 GetAccountCreationPasswordFields(control_elements, &password_elements); 568 GetAccountCreationPasswordFields(control_elements, &password_elements);
576 password_elements = FindPasswordElementsForGeneration( 569 password_elements = FindPasswordElementsForGeneration(
577 password_elements, last_focused_password_element_.nameForAutofill()); 570 password_elements,
571 CalculateFieldSignatureByNameAndType(
572 last_focused_password_element_.nameForAutofill(),
573 last_focused_password_element_.formControlType().utf8()));
578 generation_form_data_.reset(new AccountCreationFormData( 574 generation_form_data_.reset(new AccountCreationFormData(
579 make_linked_ptr(password_form.release()), password_elements)); 575 make_linked_ptr(password_form.release()), password_elements));
580 is_manually_triggered_ = true; 576 is_manually_triggered_ = true;
581 ShowGenerationPopup(); 577 ShowGenerationPopup();
582 } 578 }
583 579
584 const mojom::PasswordManagerDriverPtr& 580 const mojom::PasswordManagerDriverPtr&
585 PasswordGenerationAgent::GetPasswordManagerDriver() { 581 PasswordGenerationAgent::GetPasswordManagerDriver() {
586 DCHECK(password_agent_); 582 DCHECK(password_agent_);
587 return password_agent_->GetPasswordManagerDriver(); 583 return password_agent_->GetPasswordManagerDriver();
588 } 584 }
589 585
590 } // namespace autofill 586 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698