Commit 356b5659 authored by Manas Verma's avatar Manas Verma Committed by Commit Bot

[Payments Autofill] Adding GetAuthenticationDetails to Payments Client

The GetDetailsForGetRealPan request will return the type of authentication required and potentially a dynamic nonce for the authenticator to sign.

Bug: 949269
Change-Id: I35b53f59415d8cc353ea501af6ad8b73eda47f1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1589695Reviewed-by: default avatarJared Saul <jsaul@google.com>
Commit-Queue: Manas Verma <manasverma@google.com>
Cr-Commit-Position: refs/heads/master@{#664891}
parent 7f9c7bba
......@@ -5,6 +5,8 @@
#include "components/autofill/core/browser/payments/payments_client.h"
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
......@@ -45,6 +47,9 @@ namespace payments {
namespace {
const char kGetUnmaskDetailsRequestPath[] =
"payments/apis/chromepaymentsservice/getdetailsforgetrealpan";
const char kUnmaskCardRequestPath[] =
"payments/apis-secure/creditcardservice/getrealpan?s7e_suffix=chromewallet";
const char kUnmaskCardRequestFormat[] =
......@@ -225,6 +230,93 @@ void SetActiveExperiments(const std::vector<const char*>& active_experiments,
std::move(active_chrome_experiments));
}
class GetUnmaskDetailsRequest : public PaymentsRequest {
public:
GetUnmaskDetailsRequest(GetUnmaskDetailsCallback callback,
const std::string& app_locale,
const bool full_sync_enabled)
: callback_(std::move(callback)),
app_locale_(app_locale),
full_sync_enabled_(full_sync_enabled) {}
~GetUnmaskDetailsRequest() override {}
std::string GetRequestUrlPath() override {
return kGetUnmaskDetailsRequestPath;
}
std::string GetRequestContentType() override { return "application/json"; }
std::string GetRequestContent() override {
base::Value request_dict(base::Value::Type::DICTIONARY);
base::Value context(base::Value::Type::DICTIONARY);
context.SetKey("language_code", base::Value(app_locale_));
context.SetKey("billable_service",
base::Value(kUnmaskCardBillableServiceNumber));
request_dict.SetKey("context", std::move(context));
if (ShouldUseActiveSignedInAccount()) {
base::Value chrome_user_context(base::Value::Type::DICTIONARY);
chrome_user_context.SetKey("full_sync_enabled",
base::Value(full_sync_enabled_));
request_dict.SetKey("chrome_user_context",
std::move(chrome_user_context));
}
std::string request_content;
base::JSONWriter::Write(request_dict, &request_content);
VLOG(3) << "getdetailsforgetrealpan request body: " << request_content;
return request_content;
}
void ParseResponse(const base::Value& response) override {
const auto* method = response.FindStringKey("authentication_method");
auth_method_ = method ? *method : std::string();
const auto* offer_opt_in =
response.FindKeyOfType("offer_opt_in", base::Value::Type::BOOLEAN);
offer_opt_in_ = offer_opt_in && offer_opt_in->GetBool();
const auto* dictionary_value = response.FindKeyOfType(
"request_options", base::Value::Type::DICTIONARY);
if (dictionary_value)
request_options_ =
std::make_unique<base::Value>(dictionary_value->Clone());
const auto* fido_eligible_card_ids = response.FindKeyOfType(
"fido_eligible_credit_card_id", base::Value::Type::LIST);
if (fido_eligible_card_ids) {
for (const base::Value& result : fido_eligible_card_ids->GetList()) {
fido_eligible_card_ids_.insert(result.GetString());
}
}
}
bool IsResponseComplete() override { return !auth_method_.empty(); }
void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
std::move(callback_).Run(result, auth_method_, offer_opt_in_,
std::move(request_options_),
fido_eligible_card_ids_);
}
private:
GetUnmaskDetailsCallback callback_;
std::string app_locale_;
const bool full_sync_enabled_;
// The type of authentication method suggested for card unmask.
std::string auth_method_;
// Set to true if the user should be offered opt-in for FIDO Authentication.
bool offer_opt_in_;
// Public Key Credential Request Options required for authentication.
// https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions
std::unique_ptr<base::Value> request_options_;
// Set of credit cards ids that are eligible for FIDO Authentication.
std::set<std::string> fido_eligible_card_ids_;
DISALLOW_COPY_AND_ASSIGN(GetUnmaskDetailsRequest);
};
class UnmaskCardRequest : public PaymentsRequest {
public:
UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details,
......@@ -773,6 +865,14 @@ void PaymentsClient::Prepare() {
StartTokenFetch(false);
}
void PaymentsClient::GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale) {
IssueRequest(std::make_unique<GetUnmaskDetailsRequest>(
std::move(callback), app_locale,
account_info_getter_->IsSyncFeatureEnabled()),
/*authenticate=*/true);
}
void PaymentsClient::UnmaskCard(
const PaymentsClient::UnmaskRequestDetails& request_details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
......
......@@ -5,6 +5,8 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
#include <set>
#include <string>
#include <utility>
#include "base/macros.h"
......@@ -46,6 +48,14 @@ typedef base::OnceCallback<void(
const std::string& display_text)>
MigrateCardsCallback;
// Callback type for GetUnmaskDetails callback.
typedef base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
std::string,
bool,
std::unique_ptr<base::Value>,
std::set<std::string>)>
GetUnmaskDetailsCallback;
// Billable service number is defined in Payments server to distinguish
// different requests.
const int kUnmaskCardBillableServiceNumber = 70154;
......@@ -151,6 +161,12 @@ class PaymentsClient {
// accepted an upload prompt.
void Prepare();
// The user has interacted with a credit card form and may attempt to unmask a
// card. This request returns what method of authentication is required, along
// with any information to facilitate the authentication.
virtual void GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale);
// The user has attempted to unmask a card with the given cvc.
void UnmaskCard(const UnmaskRequestDetails& request_details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <set>
#include <string>
#include <utility>
#include <vector>
......@@ -111,6 +113,18 @@ class PaymentsClientTest : public testing::Test {
base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
}
void OnDidGetUnmaskDetails(AutofillClient::PaymentsRpcResult result,
std::string auth_method,
bool offer_opt_in,
std::unique_ptr<base::Value> request_options,
std::set<std::string> fido_eligible_card_ids) {
result_ = result;
auth_method_ = auth_method;
offer_opt_in_ = offer_opt_in;
request_options_ = std::move(request_options);
fido_eligible_card_ids_ = fido_eligible_card_ids;
}
void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) {
result_ = result;
......@@ -145,6 +159,15 @@ class PaymentsClientTest : public testing::Test {
protected:
base::test::ScopedFeatureList scoped_feature_list_;
// Issue a GetUnmaskDetails request. This requires an OAuth token before
// starting the request.
void StartGettingUnmaskDetails() {
client_->GetUnmaskDetails(
base::BindOnce(&PaymentsClientTest::OnDidGetUnmaskDetails,
weak_ptr_factory_.GetWeakPtr()),
"language-LOCALE");
}
// Issue an UnmaskCard request. This requires an OAuth token before starting
// the request.
void StartUnmasking() {
......@@ -235,6 +258,11 @@ class PaymentsClientTest : public testing::Test {
}
AutofillClient::PaymentsRpcResult result_;
std::string auth_method_;
bool offer_opt_in_;
std::unique_ptr<base::Value> request_options_;
std::set<std::string> fido_eligible_card_ids_;
std::string server_id_;
std::string real_pan_;
std::unique_ptr<base::Value> legal_message_;
......@@ -289,6 +317,31 @@ class PaymentsClientTest : public testing::Test {
}
};
TEST_F(PaymentsClientTest, GetUnmaskDetailsSuccess) {
StartGettingUnmaskDetails();
IssueOAuthToken();
ReturnResponse(
net::HTTP_OK,
"{ \"offer_opt_in\": \"false\", \"authentication_method\": \"CVC\" }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
EXPECT_EQ(false, offer_opt_in_);
EXPECT_EQ("CVC", auth_method_);
}
TEST_F(PaymentsClientTest, GetUnmaskDetailsIncludesChromeUserContext) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillGetPaymentsIdentityFromSync}, // Enabled
{features::kAutofillEnableAccountWalletStorage}); // Disabled
StartGettingUnmaskDetails();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest, OAuthError) {
StartUnmasking();
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
......
......@@ -21,6 +21,12 @@ TestPaymentsClient::TestPaymentsClient(
TestPaymentsClient::~TestPaymentsClient() {}
void TestPaymentsClient::GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale) {
std::move(callback).Run(AutofillClient::SUCCESS, auth_method_, offer_opt_in_,
std::move(request_options_), fido_eligible_card_ids_);
}
void TestPaymentsClient::GetUploadDetails(
const std::vector<AutofillProfile>& addresses,
const int detected_values,
......@@ -61,6 +67,24 @@ void TestPaymentsClient::MigrateCards(
"this is display text");
}
void TestPaymentsClient::SetAuthenticationMethod(std::string auth_method) {
auth_method_ = auth_method;
}
void TestPaymentsClient::AllowFidoRegistration(bool offer_opt_in) {
offer_opt_in_ = offer_opt_in;
}
void TestPaymentsClient::SetFidoRequestOptions(
std::unique_ptr<base::Value> request_options) {
request_options_ = std::move(request_options);
}
void TestPaymentsClient::SetFidoEligibleCardIds(
std::set<std::string> fido_eligible_card_ids) {
fido_eligible_card_ids_ = fido_eligible_card_ids;
}
void TestPaymentsClient::SetServerIdForCardUpload(std::string server_id) {
server_id_ = server_id;
}
......
......@@ -5,6 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
#include <set>
#include <string>
#include <utility>
#include <vector>
......@@ -27,6 +28,9 @@ class TestPaymentsClient : public payments::PaymentsClient {
~TestPaymentsClient() override;
void GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale) override;
void GetUploadDetails(
const std::vector<AutofillProfile>& addresses,
const int detected_values,
......@@ -50,6 +54,14 @@ class TestPaymentsClient : public payments::PaymentsClient {
const std::vector<MigratableCreditCard>& migratable_credit_cards,
MigrateCardsCallback callback) override;
void SetAuthenticationMethod(std::string auth_method);
void AllowFidoRegistration(bool offer_opt_in = true);
void SetFidoRequestOptions(std::unique_ptr<base::Value> request_options);
void SetFidoEligibleCardIds(std::set<std::string> fido_eligible_card_ids);
void SetServerIdForCardUpload(std::string);
void SetSaveResultForCardsMigration(
......@@ -77,6 +89,10 @@ class TestPaymentsClient : public payments::PaymentsClient {
private:
std::string server_id_;
std::string auth_method_;
bool offer_opt_in_ = false;
std::unique_ptr<base::Value> request_options_ = nullptr;
std::set<std::string> fido_eligible_card_ids_;
std::vector<std::pair<int, int>> supported_card_bin_ranges_;
std::vector<AutofillProfile> upload_details_addresses_;
std::vector<AutofillProfile> upload_card_addresses_;
......
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