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_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" |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "third_party/WebKit/public/web/WebFormElement.h" | 30 #include "third_party/WebKit/public/web/WebFormElement.h" |
31 #include "third_party/WebKit/public/web/WebInputElement.h" | 31 #include "third_party/WebKit/public/web/WebInputElement.h" |
32 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 32 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
33 #include "third_party/WebKit/public/web/WebView.h" | 33 #include "third_party/WebKit/public/web/WebView.h" |
34 #include "ui/gfx/geometry/rect.h" | 34 #include "ui/gfx/geometry/rect.h" |
35 | 35 |
36 namespace autofill { | 36 namespace autofill { |
37 | 37 |
38 namespace { | 38 namespace { |
39 | 39 |
| 40 using Logger = autofill::SavePasswordProgressLogger; |
| 41 |
40 // Returns true if we think that this form is for account creation. |passwords| | 42 // Returns true if we think that this form is for account creation. |passwords| |
41 // is filled with the password field(s) in the form. | 43 // is filled with the password field(s) in the form. |
42 bool GetAccountCreationPasswordFields( | 44 bool GetAccountCreationPasswordFields( |
43 const std::vector<blink::WebFormControlElement>& control_elements, | 45 const std::vector<blink::WebFormControlElement>& control_elements, |
44 std::vector<blink::WebInputElement>* passwords) { | 46 std::vector<blink::WebInputElement>* passwords) { |
45 for (size_t i = 0; i < control_elements.size(); i++) { | 47 for (size_t i = 0; i < control_elements.size(); i++) { |
46 const blink::WebInputElement* input_element = | 48 const blink::WebInputElement* input_element = |
47 toWebInputElement(&control_elements[i]); | 49 toWebInputElement(&control_elements[i]); |
48 if (input_element && input_element->isTextField()) { | 50 if (input_element && input_element->isTextField()) { |
49 if (input_element->isPasswordField()) | 51 if (input_element->isPasswordField()) |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 : content::RenderFrameObserver(render_frame), | 137 : content::RenderFrameObserver(render_frame), |
136 password_is_generated_(false), | 138 password_is_generated_(false), |
137 is_manually_triggered_(false), | 139 is_manually_triggered_(false), |
138 password_edited_(false), | 140 password_edited_(false), |
139 generation_popup_shown_(false), | 141 generation_popup_shown_(false), |
140 editing_popup_shown_(false), | 142 editing_popup_shown_(false), |
141 enabled_(password_generation::IsPasswordGenerationEnabled()), | 143 enabled_(password_generation::IsPasswordGenerationEnabled()), |
142 form_classifier_enabled_(false), | 144 form_classifier_enabled_(false), |
143 password_agent_(password_agent), | 145 password_agent_(password_agent), |
144 binding_(this) { | 146 binding_(this) { |
145 VLOG(2) << "Password Generation is " << (enabled_ ? "Enabled" : "Disabled"); | 147 LogBoolean(Logger::STRING_GENERATION_RENDERER_ENABLED, enabled_); |
146 // PasswordGenerationAgent is guaranteed to outlive |render_frame|. | 148 // PasswordGenerationAgent is guaranteed to outlive |render_frame|. |
147 render_frame->GetInterfaceRegistry()->AddInterface(base::Bind( | 149 render_frame->GetInterfaceRegistry()->AddInterface(base::Bind( |
148 &PasswordGenerationAgent::BindRequest, base::Unretained(this))); | 150 &PasswordGenerationAgent::BindRequest, base::Unretained(this))); |
149 } | 151 } |
150 PasswordGenerationAgent::~PasswordGenerationAgent() {} | 152 PasswordGenerationAgent::~PasswordGenerationAgent() {} |
151 | 153 |
152 void PasswordGenerationAgent::BindRequest( | 154 void PasswordGenerationAgent::BindRequest( |
153 mojom::PasswordGenerationAgentRequest request) { | 155 mojom::PasswordGenerationAgentRequest request) { |
154 binding_.Bind(std::move(request)); | 156 binding_.Bind(std::move(request)); |
155 } | 157 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 render_frame()->GetWebFrame()->document().forms(forms); | 253 render_frame()->GetWebFrame()->document().forms(forms); |
252 for (size_t i = 0; i < forms.size(); ++i) { | 254 for (size_t i = 0; i < forms.size(); ++i) { |
253 if (forms[i].isNull()) | 255 if (forms[i].isNull()) |
254 continue; | 256 continue; |
255 | 257 |
256 // If we can't get a valid PasswordForm, we skip this form because the | 258 // If we can't get a valid PasswordForm, we skip this form because the |
257 // the password won't get saved even if we generate it. | 259 // the password won't get saved even if we generate it. |
258 std::unique_ptr<PasswordForm> password_form( | 260 std::unique_ptr<PasswordForm> password_form( |
259 CreatePasswordFormFromWebForm(forms[i], nullptr, nullptr)); | 261 CreatePasswordFormFromWebForm(forms[i], nullptr, nullptr)); |
260 if (!password_form.get()) { | 262 if (!password_form.get()) { |
261 VLOG(2) << "Skipping form as it would not be saved"; | 263 LogMessage(Logger::STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM); |
262 continue; | 264 continue; |
263 } | 265 } |
264 | 266 |
265 // Do not generate password for GAIA since it is used to retrieve the | 267 // Do not generate password for GAIA since it is used to retrieve the |
266 // generated paswords. | 268 // generated paswords. |
267 GURL realm(password_form->signon_realm); | 269 GURL realm(password_form->signon_realm); |
268 if (realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) | 270 if (realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) |
269 continue; | 271 continue; |
270 | 272 |
271 std::vector<blink::WebInputElement> passwords; | 273 std::vector<blink::WebInputElement> passwords; |
272 if (GetAccountCreationPasswordFields( | 274 if (GetAccountCreationPasswordFields( |
273 form_util::ExtractAutofillableElementsInForm(forms[i]), | 275 form_util::ExtractAutofillableElementsInForm(forms[i]), |
274 &passwords)) { | 276 &passwords)) { |
275 if (form_classifier_enabled_) | 277 if (form_classifier_enabled_) |
276 RunFormClassifierAndSaveVote(forms[i], *password_form); | 278 RunFormClassifierAndSaveVote(forms[i], *password_form); |
277 AccountCreationFormData ac_form_data( | 279 AccountCreationFormData ac_form_data( |
278 make_linked_ptr(password_form.release()), passwords); | 280 make_linked_ptr(password_form.release()), passwords); |
279 possible_account_creation_forms_.push_back(ac_form_data); | 281 possible_account_creation_forms_.push_back(ac_form_data); |
280 } | 282 } |
281 } | 283 } |
282 | 284 |
283 if (!possible_account_creation_forms_.empty()) { | 285 if (!possible_account_creation_forms_.empty()) { |
284 VLOG(2) << possible_account_creation_forms_.size() | 286 LogNumber( |
285 << " possible account creation forms deteceted"; | 287 Logger::STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS, |
| 288 possible_account_creation_forms_.size()); |
286 DetermineGenerationElement(); | 289 DetermineGenerationElement(); |
287 } | 290 } |
288 } | 291 } |
289 | 292 |
290 bool PasswordGenerationAgent::ShouldAnalyzeDocument() const { | 293 bool PasswordGenerationAgent::ShouldAnalyzeDocument() { |
291 // Make sure that this security origin is allowed to use password manager. | 294 // Make sure that this security origin is allowed to use password manager. |
292 // Generating a password that can't be saved is a bad idea. | 295 // Generating a password that can't be saved is a bad idea. |
293 if (!render_frame() || | 296 if (!render_frame() || |
294 !render_frame() | 297 !render_frame() |
295 ->GetWebFrame() | 298 ->GetWebFrame() |
296 ->document() | 299 ->document() |
297 .getSecurityOrigin() | 300 .getSecurityOrigin() |
298 .canAccessPasswordManager()) { | 301 .canAccessPasswordManager()) { |
299 VLOG(1) << "No PasswordManager access"; | 302 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS); |
300 return false; | 303 return false; |
301 } | 304 } |
302 | 305 |
303 return true; | 306 return true; |
304 } | 307 } |
305 | 308 |
306 void PasswordGenerationAgent::FormNotBlacklisted(const PasswordForm& form) { | 309 void PasswordGenerationAgent::FormNotBlacklisted(const PasswordForm& form) { |
307 not_blacklisted_password_form_origins_.push_back(form.origin); | 310 not_blacklisted_password_form_origins_.push_back(form.origin); |
308 DetermineGenerationElement(); | 311 DetermineGenerationElement(); |
309 } | 312 } |
310 | 313 |
311 void PasswordGenerationAgent::GeneratedPasswordAccepted( | 314 void PasswordGenerationAgent::GeneratedPasswordAccepted( |
312 const base::string16& password) { | 315 const base::string16& password) { |
313 password_is_generated_ = true; | 316 password_is_generated_ = true; |
314 password_generation::LogPasswordGenerationEvent( | 317 password_generation::LogPasswordGenerationEvent( |
315 password_generation::PASSWORD_ACCEPTED); | 318 password_generation::PASSWORD_ACCEPTED); |
| 319 LogMessage(Logger::STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED); |
316 for (auto& password_element : generation_form_data_->password_elements) { | 320 for (auto& password_element : generation_form_data_->password_elements) { |
317 password_element.setValue(blink::WebString::fromUTF16(password), | 321 password_element.setValue(blink::WebString::fromUTF16(password), |
318 true /* sendEvents */); | 322 true /* sendEvents */); |
319 // setValue() above may have resulted in JavaScript closing the frame. | 323 // setValue() above may have resulted in JavaScript closing the frame. |
320 if (!render_frame()) | 324 if (!render_frame()) |
321 return; | 325 return; |
322 password_element.setAutofilled(true); | 326 password_element.setAutofilled(true); |
323 // Needed to notify password_autofill_agent that the content of the field | 327 // Needed to notify password_autofill_agent that the content of the field |
324 // has changed. Without this we will overwrite the generated | 328 // has changed. Without this we will overwrite the generated |
325 // password with an Autofilled password when saving. | 329 // password with an Autofilled password when saving. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 | 365 |
362 void PasswordGenerationAgent::FoundFormsEligibleForGeneration( | 366 void PasswordGenerationAgent::FoundFormsEligibleForGeneration( |
363 const std::vector<PasswordFormGenerationData>& forms) { | 367 const std::vector<PasswordFormGenerationData>& forms) { |
364 generation_enabled_forms_.insert(generation_enabled_forms_.end(), | 368 generation_enabled_forms_.insert(generation_enabled_forms_.end(), |
365 forms.begin(), forms.end()); | 369 forms.begin(), forms.end()); |
366 DetermineGenerationElement(); | 370 DetermineGenerationElement(); |
367 } | 371 } |
368 | 372 |
369 void PasswordGenerationAgent::DetermineGenerationElement() { | 373 void PasswordGenerationAgent::DetermineGenerationElement() { |
370 if (generation_form_data_) { | 374 if (generation_form_data_) { |
371 VLOG(2) << "Account creation form already found"; | 375 LogMessage(Logger::STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND); |
372 return; | 376 return; |
373 } | 377 } |
374 | 378 |
375 // Make sure local heuristics have identified a possible account creation | 379 // Make sure local heuristics have identified a possible account creation |
376 // form. | 380 // form. |
377 if (possible_account_creation_forms_.empty()) { | 381 if (possible_account_creation_forms_.empty()) { |
378 VLOG(2) << "Local hueristics have not detected a possible account " | 382 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS); |
379 << "creation form"; | |
380 return; | 383 return; |
381 } | 384 } |
382 | 385 |
383 // Note that no messages will be sent if this feature is disabled | 386 // Note that no messages will be sent if this feature is disabled |
384 // (e.g. password saving is disabled). | 387 // (e.g. password saving is disabled). |
385 for (auto& possible_form_data : possible_account_creation_forms_) { | 388 for (auto& possible_form_data : possible_account_creation_forms_) { |
386 PasswordForm* possible_password_form = possible_form_data.form.get(); | 389 PasswordForm* possible_password_form = possible_form_data.form.get(); |
387 const PasswordFormGenerationData* generation_data = nullptr; | 390 const PasswordFormGenerationData* generation_data = nullptr; |
388 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 391 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
389 switches::kLocalHeuristicsOnlyForPasswordGeneration)) { | 392 switches::kLocalHeuristicsOnlyForPasswordGeneration)) { |
390 VLOG(2) << "Bypassing additional checks."; | 393 VLOG(2) << "Bypassing additional checks."; |
391 } else if (!ContainsURL(not_blacklisted_password_form_origins_, | 394 } else if (!ContainsURL(not_blacklisted_password_form_origins_, |
392 possible_password_form->origin)) { | 395 possible_password_form->origin)) { |
393 VLOG(2) << "Have not received confirmation that password form isn't " | 396 LogMessage(Logger::STRING_GENERATION_RENDERER_NOT_BLACKLISTED); |
394 << "blacklisted"; | |
395 continue; | 397 continue; |
396 } else { | 398 } else { |
397 generation_data = FindFormGenerationData(generation_enabled_forms_, | 399 generation_data = FindFormGenerationData(generation_enabled_forms_, |
398 *possible_password_form); | 400 *possible_password_form); |
399 if (!generation_data) { | 401 if (!generation_data) { |
400 if (AutocompleteAttributesSetForGeneration(*possible_password_form)) { | 402 if (AutocompleteAttributesSetForGeneration(*possible_password_form)) { |
401 VLOG(2) << "Ignoring lack of Autofill signal due to Autocomplete " | 403 LogMessage(Logger::STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE); |
402 << "attributes"; | |
403 password_generation::LogPasswordGenerationEvent( | 404 password_generation::LogPasswordGenerationEvent( |
404 password_generation::AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION); | 405 password_generation::AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION); |
405 } else { | 406 } else { |
406 VLOG(2) | 407 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL); |
407 << "Have not received confirmation from Autofill that form is " | |
408 << "used for account creation"; | |
409 continue; | 408 continue; |
410 } | 409 } |
411 } | 410 } |
412 } | 411 } |
413 | 412 LogMessage(Logger::STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND); |
414 VLOG(2) << "Password generation eligible form found"; | |
415 std::vector<blink::WebInputElement> password_elements = | 413 std::vector<blink::WebInputElement> password_elements = |
416 generation_data | 414 generation_data |
417 ? FindPasswordElementsForGeneration( | 415 ? FindPasswordElementsForGeneration( |
418 possible_form_data.password_elements, *generation_data) | 416 possible_form_data.password_elements, *generation_data) |
419 : possible_form_data.password_elements; | 417 : possible_form_data.password_elements; |
420 if (password_elements.empty()) { | 418 if (password_elements.empty()) { |
421 // It might be if JavaScript changes field names. | 419 // It might be if JavaScript changes field names. |
422 VLOG(2) << "Fields for generation are not found"; | 420 LogMessage(Logger::STRING_GENERATION_RENDERER_NO_FIELD_FOUND); |
423 return; | 421 return; |
424 } | 422 } |
425 generation_form_data_.reset(new AccountCreationFormData( | 423 generation_form_data_.reset(new AccountCreationFormData( |
426 possible_form_data.form, std::move(password_elements))); | 424 possible_form_data.form, std::move(password_elements))); |
427 generation_element_ = generation_form_data_->password_elements[0]; | 425 generation_element_ = generation_form_data_->password_elements[0]; |
428 generation_element_.setAttribute("aria-autocomplete", "list"); | 426 generation_element_.setAttribute("aria-autocomplete", "list"); |
429 password_generation::LogPasswordGenerationEvent( | 427 password_generation::LogPasswordGenerationEvent( |
430 password_generation::GENERATION_AVAILABLE); | 428 password_generation::GENERATION_AVAILABLE); |
431 possible_account_creation_forms_.clear(); | 429 possible_account_creation_forms_.clear(); |
432 GetPasswordManagerClient()->GenerationAvailableForForm( | 430 GetPasswordManagerClient()->GenerationAvailableForForm( |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
515 // will just keep the previous popup if one is already showing. | 513 // will just keep the previous popup if one is already showing. |
516 ShowGenerationPopup(); | 514 ShowGenerationPopup(); |
517 } | 515 } |
518 | 516 |
519 return true; | 517 return true; |
520 } | 518 } |
521 | 519 |
522 void PasswordGenerationAgent::ShowGenerationPopup() { | 520 void PasswordGenerationAgent::ShowGenerationPopup() { |
523 if (!render_frame()) | 521 if (!render_frame()) |
524 return; | 522 return; |
| 523 LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP); |
525 GetPasswordManagerClient()->ShowPasswordGenerationPopup( | 524 GetPasswordManagerClient()->ShowPasswordGenerationPopup( |
526 render_frame()->GetRenderView()->ElementBoundsInWindow( | 525 render_frame()->GetRenderView()->ElementBoundsInWindow( |
527 generation_element_), | 526 generation_element_), |
528 generation_element_.maxLength(), | 527 generation_element_.maxLength(), |
529 generation_element_.nameForAutofill().utf16(), is_manually_triggered_, | 528 generation_element_.nameForAutofill().utf16(), is_manually_triggered_, |
530 *generation_form_data_->form); | 529 *generation_form_data_->form); |
531 generation_popup_shown_ = true; | 530 generation_popup_shown_ = true; |
532 } | 531 } |
533 | 532 |
534 void PasswordGenerationAgent::ShowEditingPopup() { | 533 void PasswordGenerationAgent::ShowEditingPopup() { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 const mojom::PasswordManagerClientAssociatedPtr& | 593 const mojom::PasswordManagerClientAssociatedPtr& |
595 PasswordGenerationAgent::GetPasswordManagerClient() { | 594 PasswordGenerationAgent::GetPasswordManagerClient() { |
596 if (!password_manager_client_) { | 595 if (!password_manager_client_) { |
597 render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( | 596 render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( |
598 &password_manager_client_); | 597 &password_manager_client_); |
599 } | 598 } |
600 | 599 |
601 return password_manager_client_; | 600 return password_manager_client_; |
602 } | 601 } |
603 | 602 |
| 603 void PasswordGenerationAgent::LogMessage(Logger::StringID message_id) { |
| 604 if (!password_agent_->logging_state_active()) |
| 605 return; |
| 606 RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get()); |
| 607 logger.LogMessage(message_id); |
| 608 } |
| 609 |
| 610 void PasswordGenerationAgent::LogBoolean(Logger::StringID message_id, |
| 611 bool truth_value) { |
| 612 if (!password_agent_->logging_state_active()) |
| 613 return; |
| 614 RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get()); |
| 615 logger.LogBoolean(message_id, truth_value); |
| 616 } |
| 617 |
| 618 void PasswordGenerationAgent::LogNumber(Logger::StringID message_id, |
| 619 int number) { |
| 620 if (!password_agent_->logging_state_active()) |
| 621 return; |
| 622 RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get()); |
| 623 logger.LogNumber(message_id, number); |
| 624 } |
| 625 |
604 } // namespace autofill | 626 } // namespace autofill |
OLD | NEW |