blob: 4ea09956bf764e53eabde1e6b32c816cbaf81acd [file] [log] [blame]
// Copyright 2025 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/passkey_unlock_manager.h"
#include "base/memory/weak_ptr.h"
#include "base/notimplemented.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/webauthn/enclave_manager_factory.h"
#include "chrome/browser/webauthn/passkey_model_factory.h"
#include "chrome/grit/generated_resources.h"
#include "google_apis/gaia/gaia_urls.h"
#include "ui/base/l10n/l10n_util.h"
namespace webauthn {
PasskeyUnlockManager::PasskeyUnlockManager(Profile* profile) {
EnclaveManager* enclave_manager = static_cast<EnclaveManager*>(
EnclaveManagerFactory::GetForProfile(profile));
enclave_manager_observation_.Observe(enclave_manager);
passkey_model_observation_.Observe(
PasskeyModelFactory::GetForProfile(profile));
if (enclave_manager->is_loaded()) {
enclave_ready_ = enclave_manager->is_ready();
} else {
AsynchronouslyLoadEnclaveManager();
}
UpdateHasPasskeys();
NotifyObservers();
}
PasskeyUnlockManager::~PasskeyUnlockManager() = default;
void PasskeyUnlockManager::AddObserver(Observer* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observer_list_.AddObserver(observer);
}
void PasskeyUnlockManager::RemoveObserver(Observer* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observer_list_.RemoveObserver(observer);
}
bool PasskeyUnlockManager::ShouldDisplayErrorUi() {
// TODO(crbug.com/450238902): Implement this method: check if passkeys are
// locked and if they are unlockable.
return false;
}
void PasskeyUnlockManager::OpenTabWithPasskeyUnlockChallenge(Browser* browser) {
NavigateParams params(GetSingletonTabNavigateParams(
browser, GaiaUrls::GetInstance()->signin_chrome_passkey_unlock_url()));
Navigate(&params);
}
std::u16string PasskeyUnlockManager::GetPasskeyErrorProfilePillTitle(
ExperimentArm experiment_arm) {
switch (experiment_arm) {
case ExperimentArm::kUnlock:
return l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_PASSKEYS_ERROR_UNLOCK);
case ExperimentArm::kGet:
return l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_PASSKEYS_ERROR_GET);
case ExperimentArm::kVerify:
return l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_PASSKEYS_ERROR_VERIFY);
}
}
std::u16string PasskeyUnlockManager::GetPasskeyErrorProfileMenuDetails(
ExperimentArm experiment_arm) {
switch (experiment_arm) {
case ExperimentArm::kUnlock:
return l10n_util::GetStringUTF16(
IDS_PROFILE_MENU_PASSKEYS_ERROR_DESCRIPTION_UNLOCK);
case ExperimentArm::kGet:
return l10n_util::GetStringUTF16(
IDS_PROFILE_MENU_PASSKEYS_ERROR_DESCRIPTION_GET);
case ExperimentArm::kVerify:
return l10n_util::GetStringUTF16(
IDS_PROFILE_MENU_PASSKEYS_ERROR_DESCRIPTION_VERIFY);
}
}
std::u16string PasskeyUnlockManager::GetPasskeyErrorProfileMenuButtonLabel(
ExperimentArm experiment_arm) {
switch (experiment_arm) {
case ExperimentArm::kUnlock:
return l10n_util::GetStringUTF16(
IDS_PROFILE_MENU_PASSKEYS_ERROR_BUTTON_UNLOCK);
case ExperimentArm::kGet:
return l10n_util::GetStringUTF16(
IDS_PROFILE_MENU_PASSKEYS_ERROR_BUTTON_GET);
case ExperimentArm::kVerify:
return l10n_util::GetStringUTF16(
IDS_PROFILE_MENU_PASSKEYS_ERROR_BUTTON_VERIFY);
}
}
PasskeyModel* PasskeyUnlockManager::passkey_model() {
return passkey_model_observation_.GetSource();
}
EnclaveManager* PasskeyUnlockManager::enclave_manager() {
return enclave_manager_observation_.GetSource();
}
void PasskeyUnlockManager::UpdateHasPasskeys() {
has_passkeys_ = !passkey_model()->GetAllPasskeys().empty();
}
void PasskeyUnlockManager::NotifyObservers() {
for (Observer& observer : observer_list_) {
observer.OnPasskeyUnlockManagerStateChanged();
}
}
void PasskeyUnlockManager::AsynchronouslyCheckGpmPinAvailability() {
// TODO(crbug.com/449948649): Implement and call in the constructor.
NOTIMPLEMENTED();
}
void PasskeyUnlockManager::AsynchronouslyCheckSystemUVAvailability() {
// TODO(crbug.com/450271375): Implement and call in the constructor.
NOTIMPLEMENTED();
}
void PasskeyUnlockManager::AsynchronouslyLoadEnclaveManager() {
auto callback = base::BindOnce(&PasskeyUnlockManager::OnStateUpdated,
weak_ptr_factory_.GetWeakPtr());
scoped_refptr<base::SequencedTaskRunner> task_runner =
base::SequencedTaskRunner::GetCurrentDefault();
auto delayed_task =
base::BindOnce(&EnclaveManager::Load, enclave_manager()->GetWeakPtr(),
std::move(callback));
task_runner->PostDelayedTask(FROM_HERE, std::move(delayed_task),
base::Minutes(4));
}
void PasskeyUnlockManager::OnKeysStored() {}
void PasskeyUnlockManager::OnStateUpdated() {
enclave_ready_ = enclave_manager()->is_ready();
NotifyObservers();
}
void PasskeyUnlockManager::OnPasskeysChanged(
const std::vector<webauthn::PasskeyModelChange>& changes) {
UpdateHasPasskeys();
NotifyObservers();
}
void PasskeyUnlockManager::OnPasskeyModelShuttingDown() {}
void PasskeyUnlockManager::OnPasskeyModelIsReady(bool is_ready) {
UpdateHasPasskeys();
NotifyObservers();
}
} // namespace webauthn