blob: 3df02ea632db5ace2920c71eeaf06ec12e596e93 [file] [log] [blame]
// Copyright 2023 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/devtools/protocol/autofill_handler.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/manual_testing_import.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/unique_ids.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/render_frame_host.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
using autofill::AutofillTriggerSource;
using autofill::CreditCard;
using autofill::FieldGlobalId;
using autofill::FormData;
using autofill::FormFieldData;
using protocol::Maybe;
using protocol::Response;
namespace {
absl::optional<std::pair<FormData, FormFieldData>> FindFieldWithFormData(
autofill::ContentAutofillDriver* driver,
autofill::FieldGlobalId id) {
for (const auto& [key, form] :
driver->autofill_manager()->form_structures()) {
for (const auto& field : form->fields()) {
if (field->global_id() == id) {
return std::make_pair(form->ToFormData(), FormFieldData(*field));
}
}
}
return absl::nullopt;
}
} // namespace
AutofillHandler::AutofillHandler(protocol::UberDispatcher* dispatcher,
const std::string& target_id)
: target_id_(target_id) {
protocol::Autofill::Dispatcher::wire(dispatcher, this);
}
AutofillHandler::~AutofillHandler() = default;
void AutofillHandler::Trigger(
int field_id,
Maybe<String> frame_id,
std::unique_ptr<protocol::Autofill::CreditCard> card,
std::unique_ptr<TriggerCallback> callback) {
auto host = content::DevToolsAgentHost::GetForId(target_id_);
if (!host) {
std::move(callback)->sendFailure(Response::ServerError("Target not found"));
return;
}
host->GetUniqueFormControlId(
field_id,
base::BindOnce(&AutofillHandler::FinishTrigger,
weak_ptr_factory_.GetWeakPtr(), std::move(frame_id),
std::move(card), std::move(callback)));
}
void AutofillHandler::FinishTrigger(
Maybe<String> frame_id,
std::unique_ptr<protocol::Autofill::CreditCard> card,
std::unique_ptr<TriggerCallback> callback,
uint64_t field_id) {
auto host = content::DevToolsAgentHost::GetForId(target_id_);
if (!host) {
std::move(callback)->sendFailure(Response::ServerError("Target not found"));
return;
}
content::RenderFrameHost* outermost_primary_rfh =
host->GetWebContents()->GetOutermostWebContents()->GetPrimaryMainFrame();
content::RenderFrameHost* frame_rfh = nullptr;
if (frame_id.has_value()) {
outermost_primary_rfh->ForEachRenderFrameHost(
[&frame_id, &frame_rfh](content::RenderFrameHost* rfh) {
if (rfh->GetDevToolsFrameToken().ToString() == frame_id.value()) {
frame_rfh = rfh;
}
});
if (!frame_rfh) {
std::move(callback)->sendFailure(
Response::ServerError("Frame not found"));
return;
}
} else {
frame_rfh = outermost_primary_rfh;
}
autofill::LocalFrameToken frame_token(frame_rfh->GetFrameToken().value());
autofill::FieldGlobalId global_field_id = {
frame_token, autofill::FieldRendererId(field_id)};
autofill::ContentAutofillDriver* autofill_driver = nullptr;
absl::optional<std::pair<FormData, FormFieldData>> field_data;
while (frame_rfh) {
autofill_driver =
autofill::ContentAutofillDriver::GetForRenderFrameHost(frame_rfh);
if (!autofill_driver) {
continue;
}
field_data = FindFieldWithFormData(autofill_driver, global_field_id);
if (field_data.has_value()) {
break;
}
frame_rfh = frame_rfh->GetParent();
}
if (!field_data.has_value()) {
std::move(callback)->sendFailure(
Response::InvalidRequest("Field not found"));
return;
}
if (!autofill_driver) {
std::move(callback)->sendFailure(
Response::ServerError("RenderFrameHost is being destroyed"));
return;
}
CreditCard tmp_autofill_card;
tmp_autofill_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER,
base::UTF8ToUTF16(card->GetNumber()));
tmp_autofill_card.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL,
base::UTF8ToUTF16(card->GetName()));
tmp_autofill_card.SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH,
base::UTF8ToUTF16(card->GetExpiryMonth()));
tmp_autofill_card.SetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR,
base::UTF8ToUTF16(card->GetExpiryYear()));
tmp_autofill_card.SetRawInfo(autofill::CREDIT_CARD_VERIFICATION_CODE,
base::UTF8ToUTF16(card->GetCvc()));
autofill_driver->autofill_manager()->FillCreditCardForm(
field_data->first, field_data->second, tmp_autofill_card,
base::UTF8ToUTF16(card->GetCvc()),
{.trigger_source = AutofillTriggerSource::kPopup});
std::move(callback)->sendSuccess();
}
void AutofillHandler::SetAddresses(
std::unique_ptr<protocol::Array<protocol::Autofill::Address>> addresses,
std::unique_ptr<SetAddressesCallback> callback) {
if (!content::DevToolsAgentHost::GetForId(target_id_)) {
std::move(callback)->sendFailure(Response::ServerError("Target not found"));
return;
}
std::vector<autofill::AutofillProfile> test_address_for_countries;
base::Value::List profiles;
for (const auto& address : *addresses) {
base::Value::Dict address_fields;
for (const auto& field : *address->GetFields()) {
address_fields.Set(field->GetName(), field->GetValue());
}
profiles.Append(std::move(address_fields));
}
absl::optional<std::vector<autofill::AutofillProfile>> autofill_profiles =
autofill::AutofillProfilesFromJSON(&profiles);
if (autofill_profiles) {
for (const autofill::AutofillProfile& profile : *autofill_profiles) {
test_address_for_countries.push_back(profile);
}
}
autofill::ContentAutofillDriver* autofill_driver = GetAutofillDriver();
if (!autofill_driver) {
std::move(callback)->sendFailure(
Response::ServerError("RenderFrameHost is being destroyed"));
return;
}
static_cast<autofill::BrowserAutofillManager*>(
autofill_driver->autofill_manager())
->set_test_addresses(test_address_for_countries);
std::move(callback)->sendSuccess();
}
autofill::ContentAutofillDriver* AutofillHandler::GetAutofillDriver() {
auto host = content::DevToolsAgentHost::GetForId(target_id_);
DCHECK(host);
content::RenderFrameHost* outermost_primary_rfh =
host->GetWebContents()->GetOutermostWebContents()->GetPrimaryMainFrame();
return autofill::ContentAutofillDriver::GetForRenderFrameHost(
outermost_primary_rfh);
}
Response AutofillHandler::Enable() {
enabled_ = true;
return Response::FallThrough();
}
Response AutofillHandler::Disable() {
enabled_ = false;
return Response::FallThrough();
}