blob: fc7a61dd255078debd1866dc791a94265e51e4a6 [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/ui/webauthn/context_menu_helper.h"
#include <cstdint>
#include "chrome/browser/password_manager/chrome_webauthn_credentials_delegate_factory.h"
#include "chrome/browser/ui/webauthn/user_actions.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/autocomplete_parsing_util.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/password_manager/core/browser/webauthn_credentials_delegate.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
namespace webauthn {
namespace {
password_manager::WebAuthnCredentialsDelegate* GetWebAuthnCredentialsDelegate(
content::RenderFrameHost* render_frame_host) {
return ChromeWebAuthnCredentialsDelegateFactory::GetFactory(
content::WebContents::FromRenderFrameHost(render_frame_host))
->GetDelegateForFrame(render_frame_host);
}
} // namespace
bool IsPasskeyFromAnotherDeviceContextMenuEnabled(
content::RenderFrameHost* render_frame_host,
uint64_t form_renderer_id,
uint64_t field_renderer_id) {
auto* af_driver =
autofill::ContentAutofillDriver::GetForRenderFrameHost(render_frame_host);
if (!af_driver) {
return false;
}
const autofill::LocalFrameToken frame_token = af_driver->GetFrameToken();
autofill::FormStructure* form =
af_driver->GetAutofillManager().FindCachedFormById(
{frame_token, autofill::FormRendererId(form_renderer_id)});
if (!form) {
return false;
}
// If the field does not have autocomplete="webauthn", the entry is disabled:
auto* field = form->GetFieldById(
{frame_token, autofill::FieldRendererId(field_renderer_id)});
if (!field || !field->parsed_autocomplete()
.value_or(autofill::AutocompleteParsingResult())
.webauthn) {
return false;
}
// Enable the entry if a conditional request is made and the security key or
// hybrid flow is available:
auto* webauthn_delegate = GetWebAuthnCredentialsDelegate(render_frame_host);
return webauthn_delegate && webauthn_delegate->GetPasskeys().has_value() &&
webauthn_delegate->IsSecurityKeyOrHybridFlowAvailable();
}
void OnPasskeyFromAnotherDeviceContextMenuItemSelected(
content::RenderFrameHost* render_frame_host) {
user_actions::RecordContextMenuEntryClick();
auto* delegate = GetWebAuthnCredentialsDelegate(render_frame_host);
if (!delegate) {
return;
}
delegate->LaunchSecurityKeyOrHybridFlow();
}
} // namespace webauthn