blob: da861378f3dfd29499dee27f214fb2a1ae5c044c [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/callback.h"
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.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 "content/public/common/content_features.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/conditional_ui_delegate_android.h"
#endif
ChromeWebAuthnCredentialsDelegate::ChromeWebAuthnCredentialsDelegate(
content::WebContents* web_contents)
: web_contents_(web_contents) {}
ChromeWebAuthnCredentialsDelegate::~ChromeWebAuthnCredentialsDelegate() =
default;
bool ChromeWebAuthnCredentialsDelegate::IsWebAuthnAutofillEnabled() const {
return base::FeatureList::IsEnabled(features::kWebAuthConditionalUI);
}
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::SelectWebAuthnCredential(
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* credentials_delegate =
ConditionalUiDelegateAndroid::GetConditionalUiDelegate(web_contents_);
if (!credentials_delegate) {
return;
}
credentials_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<autofill::Suggestion>>&
ChromeWebAuthnCredentialsDelegate::GetWebAuthnSuggestions() const {
return suggestions_;
}
void ChromeWebAuthnCredentialsDelegate::RetrieveWebAuthnSuggestions(
base::OnceClosure callback) {
if (suggestions_.has_value()) {
// Entries were already populated from the WebAuthn request.
std::move(callback).Run();
return;
}
retrieve_suggestions_callback_ = std::move(callback);
}
void ChromeWebAuthnCredentialsDelegate::OnCredentialsReceived(
const std::vector<device::DiscoverableCredentialMetadata>& credentials) {
std::vector<autofill::Suggestion> suggestions;
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);
}
autofill::Suggestion suggestion(std::move(name));
std::u16string label = l10n_util::GetStringUTF16(
password_manager::GetPlatformAuthenticatorLabel());
if (!label.empty()) {
suggestion.labels = {{autofill::Suggestion::Text(label)}};
}
suggestion.icon = "globeIcon";
suggestion.frontend_id = autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL;
suggestion.payload =
autofill::Suggestion::BackendId(base::Base64Encode(credential.cred_id));
suggestions.push_back(std::move(suggestion));
}
suggestions_ = std::move(suggestions);
if (retrieve_suggestions_callback_) {
std::move(retrieve_suggestions_callback_).Run();
}
}