blob: 88be48054c001829f0201aa65cfd1d34fb835110 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/password_manager/password_generation_controller_impl.h"
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/autofill/manual_filling_controller.h"
#include "chrome/browser/password_manager/password_accessory_controller.h"
#include "chrome/browser/password_manager/password_generation_dialog_view_interface.h"
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/signatures_util.h"
#include "components/password_manager/core/browser/password_generation_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
namespace {
void RecordGenerationDialogDismissal(bool accepted) {
UMA_HISTOGRAM_BOOLEAN("KeyboardAccessory.GeneratedPasswordDialog", accepted);
}
} // namespace
PasswordGenerationControllerImpl::~PasswordGenerationControllerImpl() = default;
// static
bool PasswordGenerationController::AllowedForWebContents(
content::WebContents* web_contents) {
return PasswordAccessoryController::AllowedForWebContents(web_contents);
}
// static
PasswordGenerationController* PasswordGenerationController::GetOrCreate(
content::WebContents* web_contents) {
DCHECK(PasswordGenerationController::AllowedForWebContents(web_contents));
PasswordGenerationControllerImpl::CreateForWebContents(web_contents);
return PasswordGenerationControllerImpl::FromWebContents(web_contents);
}
// static
PasswordGenerationController* PasswordGenerationController::GetIfExisting(
content::WebContents* web_contents) {
return PasswordGenerationControllerImpl::FromWebContents(web_contents);
}
struct PasswordGenerationControllerImpl::GenerationElementData {
GenerationElementData(autofill::PasswordForm form,
autofill::FormSignature form_signature,
autofill::FieldSignature field_signature,
uint32_t max_password_length)
: form(std::move(form)),
form_signature(form_signature),
field_signature(field_signature),
max_password_length(max_password_length) {}
// Form for which password generation is triggered.
autofill::PasswordForm form;
// Signature of the form for which password generation is triggered.
autofill::FormSignature form_signature;
// Signature of the field for which password generation is triggered.
autofill::FieldSignature field_signature;
// Maximum length of the generated password.
uint32_t max_password_length;
};
void PasswordGenerationControllerImpl::OnAutomaticGenerationStatusChanged(
bool available,
const base::Optional<
autofill::password_generation::PasswordGenerationUIData>& ui_data,
const base::WeakPtr<password_manager::PasswordManagerDriver>& driver) {
target_frame_driver_ = driver;
if (available) {
DCHECK(ui_data.has_value());
generation_element_data_ = std::make_unique<GenerationElementData>(
ui_data.value().password_form,
autofill::CalculateFormSignature(
ui_data.value().password_form.form_data),
autofill::CalculateFieldSignatureByNameAndType(
ui_data.value().generation_element, "password"),
ui_data.value().max_length);
} else {
generation_element_data_.reset();
}
if (!manual_filling_controller_) {
manual_filling_controller_ =
ManualFillingController::GetOrCreate(web_contents_);
}
DCHECK(manual_filling_controller_);
manual_filling_controller_->OnAutomaticGenerationStatusChanged(available);
}
void PasswordGenerationControllerImpl::OnGenerationRequested() {
if (!target_frame_driver_)
return;
dialog_view_ = create_dialog_factory_.Run(this);
uint32_t spec_priority = 0;
base::string16 password =
target_frame_driver_->GetPasswordGenerationManager()->GeneratePassword(
web_contents_->GetLastCommittedURL().GetOrigin(),
generation_element_data_->form_signature,
generation_element_data_->field_signature,
generation_element_data_->max_password_length, &spec_priority);
if (target_frame_driver_ && target_frame_driver_->GetPasswordManager()) {
target_frame_driver_->GetPasswordManager()
->ReportSpecPriorityForGeneratedPassword(generation_element_data_->form,
spec_priority);
}
dialog_view_->Show(password);
}
void PasswordGenerationControllerImpl::GeneratedPasswordAccepted(
const base::string16& password) {
if (!target_frame_driver_)
return;
RecordGenerationDialogDismissal(true);
target_frame_driver_->GeneratedPasswordAccepted(password);
dialog_view_.reset();
}
void PasswordGenerationControllerImpl::GeneratedPasswordRejected() {
RecordGenerationDialogDismissal(false);
dialog_view_.reset();
}
gfx::NativeWindow PasswordGenerationControllerImpl::top_level_native_window()
const {
return web_contents_->GetTopLevelNativeWindow();
}
// static
void PasswordGenerationControllerImpl::CreateForWebContentsForTesting(
content::WebContents* web_contents,
base::WeakPtr<ManualFillingController> manual_filling_controller_,
CreateDialogFactory create_dialog_factory) {
DCHECK(web_contents) << "Need valid WebContents to attach controller to!";
DCHECK(!FromWebContents(web_contents)) << "Controller already attached!";
DCHECK(manual_filling_controller_);
web_contents->SetUserData(
UserDataKey(), base::WrapUnique(new PasswordGenerationControllerImpl(
web_contents, std::move(manual_filling_controller_),
create_dialog_factory)));
}
PasswordGenerationControllerImpl::PasswordGenerationControllerImpl(
content::WebContents* web_contents)
: web_contents_(web_contents),
create_dialog_factory_(
base::BindRepeating(&PasswordGenerationDialogViewInterface::Create)) {
}
PasswordGenerationControllerImpl::PasswordGenerationControllerImpl(
content::WebContents* web_contents,
base::WeakPtr<ManualFillingController> manual_filling_controller_,
CreateDialogFactory create_dialog_factory)
: web_contents_(web_contents),
manual_filling_controller_(std::move(manual_filling_controller_)),
create_dialog_factory_(create_dialog_factory) {}
WEB_CONTENTS_USER_DATA_KEY_IMPL(PasswordGenerationControllerImpl);