| 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 |