blob: 917a44f8d25460ca90446906afad21ea59722221 [file] [log] [blame]
// Copyright 2021 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/password_manager/chrome_webauthn_credentials_delegate.h"
#include "base/base64.h"
#include "base/functional/callback.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/password_manager/core/browser/passkey_credential.h"
#include "components/password_manager/core/browser/password_ui_utils.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "device/fido/discoverable_credential_metadata.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/l10n/l10n_util.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/webauthn/authenticator_request_scheduler.h"
#include "chrome/browser/webauthn/chrome_authenticator_request_delegate.h"
#endif // !BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/webauthn/android/webauthn_request_delegate_android.h"
#endif
using password_manager::PasskeyCredential;
ChromeWebAuthnCredentialsDelegate::ChromeWebAuthnCredentialsDelegate(
content::WebContents* web_contents)
: web_contents_(web_contents) {}
ChromeWebAuthnCredentialsDelegate::~ChromeWebAuthnCredentialsDelegate() =
default;
void ChromeWebAuthnCredentialsDelegate::LaunchWebAuthnFlow() {
#if !BUILDFLAG(IS_ANDROID)
ChromeAuthenticatorRequestDelegate* authenticator_delegate =
AuthenticatorRequestScheduler::GetRequestDelegate(web_contents_);
if (!authenticator_delegate) {
return;
}
authenticator_delegate->dialog_model()->TransitionToModalWebAuthnRequest();
#endif // !BUILDFLAG(IS_ANDROID)
}
void ChromeWebAuthnCredentialsDelegate::SelectPasskey(
const std::string& backend_id) {
// `backend_id` is the base64-encoded credential ID. See
// `OnCredentialsReceived()` for where these are encoded.
absl::optional<std::vector<uint8_t>> selected_credential_id =
base::Base64Decode(backend_id);
DCHECK(selected_credential_id);
#if BUILDFLAG(IS_ANDROID)
auto* request_delegate =
WebAuthnRequestDelegateAndroid::GetRequestDelegate(web_contents_);
if (!request_delegate) {
return;
}
request_delegate->OnWebAuthnAccountSelected(*selected_credential_id);
#else
ChromeAuthenticatorRequestDelegate* authenticator_delegate =
AuthenticatorRequestScheduler::GetRequestDelegate(web_contents_);
if (!authenticator_delegate) {
return;
}
authenticator_delegate->dialog_model()->OnAccountPreselected(
*selected_credential_id);
#endif // BUILDFLAG(IS_ANDROID)
}
const absl::optional<std::vector<PasskeyCredential>>&
ChromeWebAuthnCredentialsDelegate::GetPasskeys() const {
return passkeys_;
}
void ChromeWebAuthnCredentialsDelegate::RetrievePasskeys(
base::OnceClosure callback) {
if (passkeys_.has_value()) {
// Entries were already populated from the WebAuthn request.
std::move(callback).Run();
return;
}
retrieve_passkeys_callback_ = std::move(callback);
}
void ChromeWebAuthnCredentialsDelegate::OnCredentialsReceived(
const std::vector<device::DiscoverableCredentialMetadata>& credentials) {
std::vector<PasskeyCredential> passkeys;
for (const auto& credential : credentials) {
std::u16string name;
if (credential.user.name && !credential.user.name->empty()) {
name = base::UTF8ToUTF16(*credential.user.name);
} else {
name = l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_EMPTY_LOGIN);
}
passkeys.emplace_back(
PasskeyCredential::Username(name),
PasskeyCredential::BackendId(base::Base64Encode(credential.cred_id)));
}
passkeys_ = std::move(passkeys);
if (retrieve_passkeys_callback_) {
std::move(retrieve_passkeys_callback_).Run();
}
}
void ChromeWebAuthnCredentialsDelegate::NotifyWebAuthnRequestAborted() {
passkeys_ = absl::nullopt;
if (retrieve_passkeys_callback_) {
std::move(retrieve_passkeys_callback_).Run();
}
}