blob: 24fdfd7500d1ad48b95b2272636c658148e3eeb6 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/webauthn/change_pin_controller_impl.h"
#include <memory>
#include <string>
#include <utility>
#include "base/check.h"
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
#include "chrome/browser/webauthn/chrome_authenticator_request_delegate.h"
#include "chrome/browser/webauthn/enclave_manager.h"
#include "chrome/browser/webauthn/enclave_manager_factory.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"
using Step = AuthenticatorRequestDialogModel::Step;
ChangePinControllerImpl::ChangePinControllerImpl(
content::RenderFrameHost* render_frame_host)
: content::DocumentUserData<ChangePinControllerImpl>(render_frame_host) {
Profile* profile =
Profile::FromBrowserContext(render_frame_host->GetBrowserContext());
enclave_manager_ =
EnclaveManagerFactory::GetAsEnclaveManagerForProfile(profile);
model_ =
base::MakeRefCounted<AuthenticatorRequestDialogModel>(render_frame_host);
model_observation_.Observe(model_.get());
}
ChangePinControllerImpl::~ChangePinControllerImpl() {
if (!notify_pin_change_callback_.is_null()) {
std::move(notify_pin_change_callback_).Run(false);
}
}
void ChangePinControllerImpl::IsChangePinFlowAvailable(
PinAvailableCallback callback) {
if (enclave_manager_->is_loaded()) {
NotifyPinAvailability(std::move(callback));
return;
}
enclave_manager_->Load(
base::BindOnce(&ChangePinControllerImpl::NotifyPinAvailability,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void ChangePinControllerImpl::StartChangePin(SuccessCallback callback) {
if (notify_pin_change_callback_) {
std::move(callback).Run(false);
return;
}
notify_pin_change_callback_ = std::move(callback);
model_->SetStep(Step::kGPMReauthForPinReset);
RecordHistogram(ChangePinEvent::kFlowStartedFromSettings);
}
void ChangePinControllerImpl::CancelAuthenticatorRequest() {
// User clicked "Cancel" in the GPM dialog.
Reset(/*success=*/false);
RecordHistogram(ChangePinEvent::kNewPinCancelled);
}
void ChangePinControllerImpl::OnReauthComplete(std::string rapt) {
CHECK_EQ(model_->step(), Step::kGPMReauthForPinReset);
rapt_ = std::move(rapt);
model_->SetStep(Step::kGPMChangePin);
RecordHistogram(ChangePinEvent::kReauthCompleted);
}
void ChangePinControllerImpl::OnRecoverSecurityDomainClosed() {
// User closed the reauth window.
Reset(/*success=*/false);
RecordHistogram(ChangePinEvent::kReauthCancelled);
}
void ChangePinControllerImpl::OnGPMPinEntered(const std::u16string& pin) {
CHECK(rapt_.has_value() && (model_->step() == Step::kGPMChangePin ||
model_->step() == Step::kGPMChangeArbitraryPin));
model_->DisableUiOrShowLoadingDialog();
enclave_manager_->ChangePIN(
base::UTF16ToUTF8(pin), std::move(*rapt_),
base::BindOnce(&ChangePinControllerImpl::OnGpmPinChanged,
weak_ptr_factory_.GetWeakPtr()));
rapt_.reset();
RecordHistogram(ChangePinEvent::kNewPinEntered);
}
void ChangePinControllerImpl::OnGPMPinOptionChanged(bool is_arbitrary) {
CHECK(model_->step() == Step::kGPMChangePin ||
model_->step() == Step::kGPMChangeArbitraryPin);
model_->SetStep(is_arbitrary ? Step::kGPMChangeArbitraryPin
: Step::kGPMChangePin);
}
// static
void ChangePinControllerImpl::RecordHistogram(ChangePinEvent event) {
base::UmaHistogramEnumeration("WebAuthentication.Enclave.ChangePinEvents",
event);
}
void ChangePinControllerImpl::Reset(bool success) {
if (!notify_pin_change_callback_.is_null()) {
std::move(notify_pin_change_callback_).Run(success);
}
rapt_.reset();
model_->SetStep(Step::kNotStarted);
}
void ChangePinControllerImpl::OnGpmPinChanged(bool success) {
if (!success) {
model_->SetStep(Step::kGPMError);
RecordHistogram(ChangePinEvent::kFailed);
return;
}
Reset(/*success=*/true);
RecordHistogram(ChangePinEvent::kCompletedSuccessfully);
}
void ChangePinControllerImpl::NotifyPinAvailability(
PinAvailableCallback callback) {
std::move(callback).Run(enclave_manager_->is_registered() &&
enclave_manager_->is_ready() &&
enclave_manager_->has_wrapped_pin());
}
DOCUMENT_USER_DATA_KEY_IMPL(ChangePinControllerImpl);