| // 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 "build/build_config.h" |
| #include "components/password_manager/core/browser/passkey_credential.h" |
| #include "components/password_manager/core/browser/password_ui_utils.h" |
| #include "content/public/browser/web_contents.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 `PasskeyCredential` |
| // 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; |
| } |
| // TODO(https:/crbug.com/1439659): This clears the passkey list because |
| // Android does not allow a second attempt at account selection, but this |
| // should be changed later when we better recover from user cancellation |
| // of the GMSCore UI. |
| passkeys_ = absl::nullopt; |
| 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( |
| std::vector<PasskeyCredential> credentials) { |
| passkeys_ = std::move(credentials); |
| 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(); |
| } |
| } |