Commit 698ab388 authored by sandromaggi's avatar sandromaggi Committed by Commit Bot

[Autofill Assistant] Add profile value for field filling

This allows the SetFormFieldValueAction to use a value from a
previously selected profile. If the profile is not available the action
will terminate with an error. If the value expression cannot be
resolved the action will terminate with an error.

Bug: b/169521597
Change-Id: Id2502d366d42a085103261bb35e30b0e701410fd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2435084
Commit-Queue: Sandro Maggi <sandromaggi@google.com>
Reviewed-by: default avatarClemens Arbesser <arbesser@google.com>
Cr-Commit-Position: refs/heads/master@{#811652}
parent e0f82769
......@@ -8,9 +8,11 @@
#include "base/bind.h"
#include "base/callback.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/field_formatter.h"
namespace autofill_assistant {
namespace {
......@@ -57,6 +59,7 @@ void SetFormFieldValueAction::InternalProcessAction(
}
// Check proto fields.
int keypress_index = 0;
for (const auto& keypress : proto_.set_form_value().value()) {
switch (keypress.keypress_case()) {
case SetFormFieldValueProto_KeyPress::kKeycode:
......@@ -68,7 +71,7 @@ void SetFormFieldValueAction::InternalProcessAction(
VLOG(1) << "SetFormFieldValueAction: field `keycode' is deprecated "
<< "and only supports US-ASCII values (encountered value > "
"127). Use field `key' instead.";
EndAction(ClientStatus(INVALID_ACTION));
FailAction(ClientStatus(INVALID_ACTION), keypress_index);
return;
}
field_inputs_.emplace_back(
......@@ -79,7 +82,7 @@ void SetFormFieldValueAction::InternalProcessAction(
if (keypress.keyboard_input().empty()) {
VLOG(1) << "SetFormFieldValueAction: field 'keyboard_input' must be "
"non-empty if set.";
EndAction(ClientStatus(INVALID_ACTION));
FailAction(ClientStatus(INVALID_ACTION), keypress_index);
return;
}
field_inputs_.emplace_back(
......@@ -93,7 +96,7 @@ void SetFormFieldValueAction::InternalProcessAction(
if (!delegate_->GetUserData()->selected_login_.has_value()) {
VLOG(1) << "SetFormFieldValueAction: requested login details not "
"available in client memory.";
EndAction(ClientStatus(PRECONDITION_FAILED));
FailAction(ClientStatus(PRECONDITION_FAILED), keypress_index);
return;
}
if (keypress.keypress_case() ==
......@@ -112,7 +115,7 @@ void SetFormFieldValueAction::InternalProcessAction(
case SetFormFieldValueProto_KeyPress::kClientMemoryKey:
if (keypress.client_memory_key().empty()) {
VLOG(1) << "SetFormFieldValueAction: empty |client_memory_key|";
EndAction(ClientStatus(INVALID_ACTION));
FailAction(ClientStatus(INVALID_ACTION), keypress_index);
return;
}
if (!delegate_->GetUserData()->has_additional_value(
......@@ -125,7 +128,7 @@ void SetFormFieldValueAction::InternalProcessAction(
VLOG(1) << "SetFormFieldValueAction: requested key '"
<< keypress.client_memory_key()
<< "' not available in client memory";
EndAction(ClientStatus(PRECONDITION_FAILED));
FailAction(ClientStatus(PRECONDITION_FAILED), keypress_index);
return;
}
field_inputs_.emplace_back(
......@@ -134,11 +137,43 @@ void SetFormFieldValueAction::InternalProcessAction(
->strings()
.values(0));
break;
case SetFormFieldValueProto_KeyPress::kAutofillValue: {
if (keypress.autofill_value().profile().identifier().empty() ||
keypress.autofill_value().value_expression().empty()) {
VLOG(1) << "SetFormFieldValueAction: |autofill_value| with empty "
"|profile.identifier| or |value_expression|";
FailAction(ClientStatus(INVALID_ACTION), keypress_index);
return;
}
const autofill::AutofillProfile* address =
delegate_->GetUserData()->selected_address(
keypress.autofill_value().profile().identifier());
if (address == nullptr) {
VLOG(1) << "SetFormFieldValueAction: requested unknown address '"
<< keypress.autofill_value().profile().identifier() << "'";
FailAction(ClientStatus(PRECONDITION_FAILED), keypress_index);
return;
}
auto value = field_formatter::FormatString(
keypress.autofill_value().value_expression(),
field_formatter::CreateAutofillMappings(*address,
/* locale= */ "en-US"));
if (!value.has_value()) {
FailAction(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE), keypress_index);
return;
}
field_inputs_.emplace_back(*value);
break;
}
default:
VLOG(1) << "Unrecognized field for SetFormFieldValueProto_KeyPress";
EndAction(ClientStatus(INVALID_ACTION));
FailAction(ClientStatus(INVALID_ACTION), keypress_index);
return;
}
++keypress_index;
}
delegate_->ShortWaitForElement(
......@@ -278,6 +313,14 @@ void SetFormFieldValueAction::OnGetStoredPassword(int field_index,
}
}
void SetFormFieldValueAction::FailAction(const ClientStatus& status,
int keypress_index) {
processed_action_proto_->mutable_status_details()
->mutable_form_field_error_info()
->set_invalid_keypress_index(keypress_index);
EndAction(status);
}
void SetFormFieldValueAction::EndAction(const ClientStatus& status) {
// Clear immediately, to prevent sensitive information from staying in memory.
field_inputs_.clear();
......
......@@ -70,6 +70,7 @@ class SetFormFieldValueAction : public Action {
void OnGetStoredPassword(int field_index, bool success, std::string password);
void FailAction(const ClientStatus& status, int keypress_index);
void EndAction(const ClientStatus& status);
Selector selector_;
......
......@@ -7,8 +7,14 @@
#include <string>
#include <utility>
#include "base/guid.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
......@@ -357,4 +363,80 @@ TEST_F(SetFormFieldValueActionTest, PasswordIsClearedFromMemory) {
EXPECT_TRUE(action.field_inputs_.empty());
}
TEST_F(SetFormFieldValueActionTest, EmptyProfileValueFails) {
set_form_field_proto_->add_value()->mutable_autofill_value();
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
TEST_F(SetFormFieldValueActionTest, RequestDataFromUnknownProfile) {
auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
value->mutable_profile()->set_identifier("none");
value->set_value_expression("value");
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
PRECONDITION_FAILED))));
action.ProcessAction(callback_.Get());
}
TEST_F(SetFormFieldValueActionTest, RequestUnknownDataFromProfile) {
autofill::AutofillProfile contact(base::GenerateGUID(),
autofill::test::kEmptyOrigin);
// Middle name is expected to be empty.
autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
"", "", "", "", "", "", "", "", "");
user_data_.selected_addresses_["contact"] =
std::make_unique<autofill::AutofillProfile>(contact);
auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
value->mutable_profile()->set_identifier("contact");
value->set_value_expression(
base::StrCat({"${",
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::NAME_MIDDLE)),
"}"}));
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
AUTOFILL_INFO_NOT_AVAILABLE))));
action.ProcessAction(callback_.Get());
}
TEST_F(SetFormFieldValueActionTest, SetFieldFromProfileValue) {
autofill::AutofillProfile contact(base::GenerateGUID(),
autofill::test::kEmptyOrigin);
autofill::test::SetProfileInfo(&contact, "John", "", "Doe", "", "", "", "",
"", "", "", "", "");
user_data_.selected_addresses_["contact"] =
std::make_unique<autofill::AutofillProfile>(contact);
auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
value->mutable_profile()->set_identifier("contact");
value->set_value_expression(
base::StrCat({"${",
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::NAME_FIRST)),
"}"}));
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_CALL(mock_action_delegate_,
OnSetFieldValue("John", _, _,
EqualsElement(test_util::MockFindElement(
mock_action_delegate_, fake_selector_)),
_))
.WillOnce(RunOnceCallback<4>(OkClientStatus()));
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
action.ProcessAction(callback_.Get());
}
} // namespace autofill_assistant
......@@ -459,6 +459,21 @@ enum ClickType {
CLICK = 3;
}
message AutofillValue {
message Profile { optional string identifier = 1; }
// The profile to be used. This has to be requested with a
// |CollectUserDataAction| first.
optional Profile profile = 1;
// A string containing any number of "${key}" placeholders, where the key is
// an integer corresponding to entries from field_types.h or
// |AutofillFormatProto::AutofillAssistantCustomField|.
// Note that the set of actually available fields are outside of our
// control and are retrieved automatically from the provided profile.
optional string value_expression = 2;
}
// An action could be performed.
message ActionProto {
// Wait these many milliseconds before executing the action, if set.
......@@ -607,6 +622,9 @@ message ProcessedActionStatusDetailsProto {
// More information included for autofill related errors.
optional AutofillErrorInfoProto autofill_error_info = 3;
// More information included for |SetFormFieldValueProto| related errors.
optional SetFormFieldErrorInfoProto form_field_error_info = 4;
}
message NavigationInfoProto {
......@@ -711,6 +729,13 @@ message AutofillErrorInfoProto {
repeated AutofillFieldError autofill_field_error = 5;
}
// Message to report |SetFormFieldValueProto| related errors for debugging
// purposes.
message SetFormFieldErrorInfoProto {
// The index of |keypress| that caused the action to be invalid.
optional int32 invalid_keypress_index = 1;
}
// The pseudo type values come from
// https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PseudoType.
enum PseudoType {
......@@ -993,9 +1018,9 @@ message UseAddressProto {
// Message used to indicate what form fields should be filled with what
// information coming from the address.
message RequiredField {
// A string containing either a single integer key or multiple "${key}"
// placeholders, where the key is an integer corresponding to entries from
// field_types.h or AutofillFormatProto::AutofillAssistantCustomField.
// A string containing any number of "${key}" placeholders, where the key
// is an integer corresponding to entries from field_types.h or
// |AutofillFormatProto::AutofillAssistantCustomField|.
// Example:
// * "3" -> First name.
// * "${3}" -> First name.
......@@ -1059,9 +1084,9 @@ message UseCreditCardProto {
// Message used to indicate what form fields should be filled with what
// information.
message RequiredField {
// A string containing either a single integer key or multiple "${key}"
// placeholders, where the key is an integer corresponding to entries from
// field_types.h or AutofillFormatProto::AutofillAssistantCustomField.
// A string containing any number of "${key}" placeholders, where the key
// is an integer corresponding to entries from field_types.h or
// |AutofillFormatProto::AutofillAssistantCustomField|.
// Example:
// * "51" -> Full name.
// * "${51}" -> Full Name.
......@@ -1918,6 +1943,9 @@ message SetFormFieldValueProto {
bool use_password = 5;
// Use the value stored at the specified memory location.
string client_memory_key = 6;
// A value from an Autofill source. Note that this must be proceeded by a
// |CollectUserDataAction|.
AutofillValue autofill_value = 8;
}
reserved 7;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment