summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdonnelly <jdonnelly@chromium.org>2015-11-10 13:45:38 -0800
committerCommit bot <commit-bot@chromium.org>2015-11-10 21:46:45 +0000
commit171e51e7a69886d993b1257d89a969524b30efff (patch)
tree7f369711656bb816e3ec20daadae5032a0ce5199
parentcf4914733abd70c90a3396c394ff4fad7ac55bb2 (diff)
downloadchromium_src-171e51e7a69886d993b1257d89a969524b30efff.zip
chromium_src-171e51e7a69886d993b1257d89a969524b30efff.tar.gz
chromium_src-171e51e7a69886d993b1257d89a969524b30efff.tar.bz2
Add credit card upstreaming.
In support, also: - Rename RealPanWalletClient to PaymentsClient and add the new upstreaming RPCs. Redesign the logic here to support multiple types of requests. - Move risk data generation from CardUnmaskPromptControllerImpl to AutofillManager. Here it can be used for both unmasking and uploading. BUG=535784 Review URL: https://codereview.chromium.org/1412073004 Cr-Commit-Position: refs/heads/master@{#358913}
-rw-r--r--android_webview/native/aw_autofill_client.cc17
-rw-r--r--android_webview/native/aw_autofill_client.h9
-rw-r--r--chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc10
-rw-r--r--chrome/browser/ui/autofill/chrome_autofill_client.cc25
-rw-r--r--chrome/browser/ui/autofill/chrome_autofill_client.h11
-rw-r--r--components/autofill.gypi5
-rw-r--r--components/autofill/content/browser/BUILD.gn2
-rw-r--r--components/autofill/content/browser/wallet/payments_client_unittest.cc (renamed from components/autofill/content/browser/wallet/real_pan_wallet_client_unittest.cc)156
-rw-r--r--components/autofill/core/browser/BUILD.gn5
-rw-r--r--components/autofill/core/browser/autofill_client.h22
-rw-r--r--components/autofill/core/browser/autofill_experiments.cc28
-rw-r--r--components/autofill/core/browser/autofill_experiments.h8
-rw-r--r--components/autofill/core/browser/autofill_manager.cc163
-rw-r--r--components/autofill/core/browser/autofill_manager.h59
-rw-r--r--components/autofill/core/browser/autofill_manager_unittest.cc169
-rw-r--r--components/autofill/core/browser/autofill_metrics.cc19
-rw-r--r--components/autofill/core/browser/autofill_metrics.h22
-rw-r--r--components/autofill/core/browser/autofill_metrics_unittest.cc2
-rw-r--r--components/autofill/core/browser/card_unmask_delegate.cc10
-rw-r--r--components/autofill/core/browser/card_unmask_delegate.h7
-rw-r--r--components/autofill/core/browser/payments/payments_client.cc484
-rw-r--r--components/autofill/core/browser/payments/payments_client.h171
-rw-r--r--components/autofill/core/browser/payments/payments_request.h46
-rw-r--r--components/autofill/core/browser/test_autofill_client.cc15
-rw-r--r--components/autofill/core/browser/test_autofill_client.h9
-rw-r--r--components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc28
-rw-r--r--components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h17
-rw-r--r--components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc19
-rw-r--r--components/autofill/core/browser/wallet/real_pan_wallet_client.cc286
-rw-r--r--components/autofill/core/browser/wallet/real_pan_wallet_client.h115
-rw-r--r--components/autofill/core/common/autofill_switches.cc7
-rw-r--r--components/autofill/core/common/autofill_switches.h2
-rw-r--r--components/components_tests.gyp2
-rw-r--r--ios/chrome/browser/ui/autofill/autofill_client_ios.h9
-rw-r--r--ios/chrome/browser/ui/autofill/autofill_client_ios.mm30
35 files changed, 1338 insertions, 651 deletions
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc
index 2ac1b40..2b2c2667 100644
--- a/android_webview/native/aw_autofill_client.cc
+++ b/android_webview/native/aw_autofill_client.cc
@@ -217,12 +217,23 @@ void AwAutofillClient::ShowUnmaskPrompt(
NOTIMPLEMENTED();
}
-void AwAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) {
+void AwAutofillClient::OnUnmaskVerificationResult(PaymentsRpcResult result) {
NOTIMPLEMENTED();
}
-void AwAutofillClient::ConfirmSaveCreditCard(
- const base::Closure& save_card_callback) {
+void AwAutofillClient::ConfirmSaveCreditCardLocally(
+ const base::Closure& callback) {
+ NOTIMPLEMENTED();
+}
+
+void AwAutofillClient::ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) {
+ NOTIMPLEMENTED();
+}
+
+void AwAutofillClient::LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) {
NOTIMPLEMENTED();
}
diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h
index a884949..c869ddb 100644
--- a/android_webview/native/aw_autofill_client.h
+++ b/android_webview/native/aw_autofill_client.h
@@ -66,8 +66,13 @@ class AwAutofillClient : public autofill::AutofillClient,
void ShowUnmaskPrompt(
const autofill::CreditCard& card,
base::WeakPtr<autofill::CardUnmaskDelegate> delegate) override;
- void OnUnmaskVerificationResult(GetRealPanResult result) override;
- void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
+ void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
+ void ConfirmSaveCreditCardLocally(const base::Closure& callback) override;
+ void ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) override;
+ void LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(const CreditCardScanCallback& callback) override;
void ShowRequestAutocompleteDialog(const autofill::FormData& form,
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc b/chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc
index e9e4ce2..cd4c294 100644
--- a/chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc
+++ b/chrome/browser/ui/autofill/card_unmask_prompt_view_browsertest.cc
@@ -6,7 +6,6 @@
#include "base/guid.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/autofill/risk_util.h"
#include "chrome/browser/ui/autofill/card_unmask_prompt_view_tester.h"
#include "chrome/browser/ui/autofill/create_card_unmask_prompt_view.h"
#include "chrome/browser/ui/browser.h"
@@ -55,8 +54,9 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
TestCardUnmaskPromptController(
content::WebContents* contents,
scoped_refptr<content::MessageLoopRunner> runner)
- : CardUnmaskPromptControllerImpl(base::Bind(&LoadRiskData, 0, contents),
- user_prefs::UserPrefs::Get(contents->GetBrowserContext()), false),
+ : CardUnmaskPromptControllerImpl(
+ user_prefs::UserPrefs::Get(contents->GetBrowserContext()),
+ false),
runner_(runner),
weak_factory_(this) {}
@@ -65,10 +65,6 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
return base::TimeDelta::FromMilliseconds(10);
}
- void LoadRiskFingerprint() override {
- OnDidLoadRiskFingerprint("risk_data");
- }
-
base::WeakPtr<TestCardUnmaskPromptController> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 3288d5a..26a8c50 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -54,7 +54,6 @@ namespace autofill {
ChromeAutofillClient::ChromeAutofillClient(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
unmask_controller_(
- base::Bind(&LoadRiskData, 0, web_contents),
user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()),
Profile::FromBrowserContext(web_contents->GetBrowserContext())
->IsOffTheRecord()),
@@ -148,27 +147,39 @@ void ChromeAutofillClient::ShowUnmaskPrompt(
card, delegate);
}
-void ChromeAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) {
+void ChromeAutofillClient::OnUnmaskVerificationResult(
+ PaymentsRpcResult result) {
unmask_controller_.OnVerificationResult(result);
}
-void ChromeAutofillClient::ConfirmSaveCreditCard(
- const base::Closure& save_card_callback) {
+void ChromeAutofillClient::ConfirmSaveCreditCardLocally(
+ const base::Closure& callback) {
// TODO(bondd): Implement save card bubble for OS_MACOSX.
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
// Do lazy initialization of SaveCardBubbleControllerImpl.
autofill::SaveCardBubbleControllerImpl::CreateForWebContents(web_contents());
autofill::SaveCardBubbleControllerImpl* controller =
autofill::SaveCardBubbleControllerImpl::FromWebContents(web_contents());
- controller->SetCallback(save_card_callback);
+ controller->SetCallback(callback);
controller->ShowBubble();
#else
AutofillCCInfoBarDelegate::Create(
- InfoBarService::FromWebContents(web_contents()), this,
- save_card_callback);
+ InfoBarService::FromWebContents(web_contents()), this, callback);
#endif
}
+void ChromeAutofillClient::ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) {
+ // TODO(bondd): Implement upload UI.
+ ConfirmSaveCreditCardLocally(callback);
+}
+
+void ChromeAutofillClient::LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) {
+ ::autofill::LoadRiskData(0, web_contents(), callback);
+}
+
bool ChromeAutofillClient::HasCreditCardScanFeature() {
return CreditCardScannerController::HasCreditCardScanFeature();
}
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 306259a..271678e 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -53,8 +53,13 @@ class ChromeAutofillClient
void ShowAutofillSettings() override;
void ShowUnmaskPrompt(const CreditCard& card,
base::WeakPtr<CardUnmaskDelegate> delegate) override;
- void OnUnmaskVerificationResult(GetRealPanResult result) override;
- void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
+ void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
+ void ConfirmSaveCreditCardLocally(const base::Closure& callback) override;
+ void ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) override;
+ void LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(const CreditCardScanCallback& callback) override;
void ShowRequestAutocompleteDialog(
@@ -112,7 +117,7 @@ class ChromeAutofillClient
// The last render frame that called requestAutocomplete.
content::RenderFrameHost* last_rfh_to_rac_;
- // The identity provider, used for Wallet integration.
+ // The identity provider, used for Payments integration.
scoped_ptr<IdentityProvider> identity_provider_;
DISALLOW_COPY_AND_ASSIGN(ChromeAutofillClient);
diff --git a/components/autofill.gypi b/components/autofill.gypi
index f30eb9d..19ff103 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -175,6 +175,9 @@
'autofill/core/browser/options_util.h',
'autofill/core/browser/password_generator.cc',
'autofill/core/browser/password_generator.h',
+ 'autofill/core/browser/payments/payments_client.cc',
+ 'autofill/core/browser/payments/payments_client.h',
+ 'autofill/core/browser/payments/payments_request.h',
'autofill/core/browser/personal_data_manager.cc',
'autofill/core/browser/personal_data_manager.h',
'autofill/core/browser/personal_data_manager_observer.h',
@@ -197,8 +200,6 @@
'autofill/core/browser/ui/card_unmask_prompt_view.h',
'autofill/core/browser/validation.cc',
'autofill/core/browser/validation.h',
- 'autofill/core/browser/wallet/real_pan_wallet_client.cc',
- 'autofill/core/browser/wallet/real_pan_wallet_client.h',
'autofill/core/browser/webdata/autocomplete_syncable_service.cc',
'autofill/core/browser/webdata/autocomplete_syncable_service.h',
'autofill/core/browser/webdata/autofill_change.cc',
diff --git a/components/autofill/content/browser/BUILD.gn b/components/autofill/content/browser/BUILD.gn
index 02871f7..36f9760 100644
--- a/components/autofill/content/browser/BUILD.gn
+++ b/components/autofill/content/browser/BUILD.gn
@@ -70,7 +70,7 @@ source_set("unit_tests") {
"content_autofill_driver_unittest.cc",
"request_autocomplete_manager_unittest.cc",
"wallet/full_wallet_unittest.cc",
- "wallet/real_pan_wallet_client_unittest.cc",
+ "wallet/payments_client_unittest.cc",
"wallet/wallet_address_unittest.cc",
"wallet/wallet_service_url_unittest.cc",
]
diff --git a/components/autofill/content/browser/wallet/real_pan_wallet_client_unittest.cc b/components/autofill/content/browser/wallet/payments_client_unittest.cc
index 4bbc78c..f761e99 100644
--- a/components/autofill/content/browser/wallet/real_pan_wallet_client_unittest.cc
+++ b/components/autofill/content/browser/wallet/payments_client_unittest.cc
@@ -4,8 +4,9 @@
#include "base/command_line.h"
#include "base/thread_task_runner_handle.h"
+#include "base/values.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/wallet/real_pan_wallet_client.h"
+#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "google_apis/gaia/fake_identity_provider.h"
@@ -15,54 +16,87 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
-namespace wallet {
+namespace payments {
-class RealPanWalletClientTest : public testing::Test,
- public RealPanWalletClient::Delegate {
+class PaymentsClientTest : public testing::Test, public PaymentsClientDelegate {
public:
- RealPanWalletClientTest() : result_(AutofillClient::SUCCESS) {}
- ~RealPanWalletClientTest() override {}
+ PaymentsClientTest() : result_(AutofillClient::NONE) {}
+ ~PaymentsClientTest() override {}
void SetUp() override {
- // Silence the warning for mismatching sync and wallet servers.
+ // Silence the warning for mismatching sync and Payments servers.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kWalletServiceUseSandbox, "0");
+ result_ = AutofillClient::NONE;
+ real_pan_.clear();
+ legal_message_.reset();
+
request_context_ = new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get());
token_service_.reset(new FakeOAuth2TokenService());
identity_provider_.reset(new FakeIdentityProvider(token_service_.get()));
- client_.reset(new RealPanWalletClient(request_context_.get(), this));
+ client_.reset(new PaymentsClient(request_context_.get(), this));
}
void TearDown() override { client_.reset(); }
- // RealPanWalletClient::Delegate
+ // PaymentsClientDelegate
IdentityProvider* GetIdentityProvider() override {
return identity_provider_.get();
}
- void OnDidGetRealPan(AutofillClient::GetRealPanResult result,
+ void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) override {
result_ = result;
real_pan_ = real_pan;
}
+ void OnDidGetUploadDetails(
+ AutofillClient::PaymentsRpcResult result,
+ const base::string16& context_token,
+ scoped_ptr<base::DictionaryValue> legal_message) override {
+ result_ = result;
+ legal_message_ = legal_message.Pass();
+ }
+
+ void OnDidUploadCard(AutofillClient::PaymentsRpcResult result) override {
+ result_ = result;
+ }
+
protected:
void StartUnmasking() {
token_service_->AddAccount("example@gmail.com");
identity_provider_->LogIn("example@gmail.com");
- CreditCard card = test::GetMaskedServerCard();
- CardUnmaskDelegate::UnmaskResponse response;
- response.cvc = base::ASCIIToUTF16("123");
- client_->UnmaskCard(card, response);
+ PaymentsClient::UnmaskRequestDetails request_details;
+ request_details.card = test::GetMaskedServerCard();
+ request_details.user_response.cvc = base::ASCIIToUTF16("123");
+ request_details.risk_data = "some risk data";
+ client_->UnmaskCard(request_details);
+ }
+
+ void StartGettingUploadDetails() {
+ token_service_->AddAccount("example@gmail.com");
+ identity_provider_->LogIn("example@gmail.com");
+ client_->GetUploadDetails("language-LOCALE");
+ }
+
+ void StartUploading() {
+ token_service_->AddAccount("example@gmail.com");
+ identity_provider_->LogIn("example@gmail.com");
+ PaymentsClient::UploadRequestDetails request_details;
+ request_details.card = test::GetCreditCard();
+ request_details.cvc = base::ASCIIToUTF16("123");
+ request_details.context_token = base::ASCIIToUTF16("context token");
+ request_details.risk_data = "some risk data";
+ request_details.app_locale = "language-LOCALE";
+ client_->UploadCard(request_details);
}
void IssueOAuthToken() {
token_service_->IssueAllTokensForAccount(
- "example@gmail.com",
- "totally_real_token",
+ "example@gmail.com", "totally_real_token",
base::Time::Now() + base::TimeDelta::FromDays(10));
// Verify the auth header.
@@ -71,8 +105,8 @@ class RealPanWalletClientTest : public testing::Test,
fetcher->GetExtraRequestHeaders(&request_headers);
std::string auth_header_value;
EXPECT_TRUE(request_headers.GetHeader(
- net::HttpRequestHeaders::kAuthorization,
- &auth_header_value)) << request_headers.ToString();
+ net::HttpRequestHeaders::kAuthorization, &auth_header_value))
+ << request_headers.ToString();
EXPECT_EQ("Bearer totally_real_token", auth_header_value);
}
@@ -85,21 +119,22 @@ class RealPanWalletClientTest : public testing::Test,
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
- AutofillClient::GetRealPanResult result_;
+ AutofillClient::PaymentsRpcResult result_;
std::string real_pan_;
+ scoped_ptr<base::DictionaryValue> legal_message_;
content::TestBrowserThreadBundle thread_bundle_;
net::TestURLFetcherFactory factory_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
scoped_ptr<FakeOAuth2TokenService> token_service_;
scoped_ptr<FakeIdentityProvider> identity_provider_;
- scoped_ptr<RealPanWalletClient> client_;
+ scoped_ptr<PaymentsClient> client_;
private:
- DISALLOW_COPY_AND_ASSIGN(RealPanWalletClientTest);
+ DISALLOW_COPY_AND_ASSIGN(PaymentsClientTest);
};
-TEST_F(RealPanWalletClientTest, OAuthError) {
+TEST_F(PaymentsClientTest, OAuthError) {
StartUnmasking();
token_service_->IssueErrorForAllPendingRequestsForAccount(
"example@gmail.com",
@@ -108,7 +143,7 @@ TEST_F(RealPanWalletClientTest, OAuthError) {
EXPECT_TRUE(real_pan_.empty());
}
-TEST_F(RealPanWalletClientTest, Success) {
+TEST_F(PaymentsClientTest, UnmaskSuccess) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
@@ -116,7 +151,57 @@ TEST_F(RealPanWalletClientTest, Success) {
EXPECT_EQ("1234", real_pan_);
}
-TEST_F(RealPanWalletClientTest, RetryFailure) {
+TEST_F(PaymentsClientTest, GetDetailsSuccess) {
+ StartGettingUploadDetails();
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"context_token\": \"some_token\", \"legal_message\": {} }");
+ EXPECT_EQ(AutofillClient::SUCCESS, result_);
+ EXPECT_NE(nullptr, legal_message_.get());
+}
+
+TEST_F(PaymentsClientTest, UploadSuccess) {
+ StartUploading();
+ IssueOAuthToken();
+ ReturnResponse(net::HTTP_OK, "{}");
+ EXPECT_EQ(AutofillClient::SUCCESS, result_);
+}
+
+TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) {
+ StartGettingUploadDetails();
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"context_token\": \"some_token\", \"legal_message\": {} }");
+ EXPECT_EQ(AutofillClient::SUCCESS, result_);
+
+ result_ = AutofillClient::NONE;
+
+ StartUploading();
+ IssueOAuthToken();
+ ReturnResponse(net::HTTP_OK, "{}");
+ EXPECT_EQ(AutofillClient::SUCCESS, result_);
+}
+
+TEST_F(PaymentsClientTest, UnmaskMissingPan) {
+ StartUnmasking();
+ ReturnResponse(net::HTTP_OK, "{}");
+ EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
+}
+
+TEST_F(PaymentsClientTest, GetDetailsMissingContextToken) {
+ StartGettingUploadDetails();
+ ReturnResponse(net::HTTP_OK, "{ \"legal_message\": {} }");
+ EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
+}
+
+TEST_F(PaymentsClientTest, GetDetailsMissingLegalMessage) {
+ StartGettingUploadDetails();
+ ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"some_token\" }");
+ EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
+ EXPECT_EQ(nullptr, legal_message_.get());
+}
+
+TEST_F(PaymentsClientTest, RetryFailure) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"error\": { \"code\": \"INTERNAL\" } }");
@@ -124,31 +209,30 @@ TEST_F(RealPanWalletClientTest, RetryFailure) {
EXPECT_EQ("", real_pan_);
}
-TEST_F(RealPanWalletClientTest, PermanentFailure) {
+TEST_F(PaymentsClientTest, PermanentFailure) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
- "{ \"error\": { \"code\": \"ANYTHING_ELSE\" } }");
+ "{ \"error\": { \"code\": \"ANYTHING_ELSE\" } }");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_EQ("", real_pan_);
}
-TEST_F(RealPanWalletClientTest, MalformedResponse) {
+TEST_F(PaymentsClientTest, MalformedResponse) {
StartUnmasking();
IssueOAuthToken();
- ReturnResponse(net::HTTP_OK,
- "{ \"error_code\": \"WRONG_JSON_FORMAT\" }");
+ ReturnResponse(net::HTTP_OK, "{ \"error_code\": \"WRONG_JSON_FORMAT\" }");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_EQ("", real_pan_);
}
-TEST_F(RealPanWalletClientTest, ReauthNeeded) {
+TEST_F(PaymentsClientTest, ReauthNeeded) {
{
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_UNAUTHORIZED, "");
// No response yet.
- EXPECT_EQ(AutofillClient::SUCCESS, result_);
+ EXPECT_EQ(AutofillClient::NONE, result_);
EXPECT_EQ("", real_pan_);
// Second HTTP_UNAUTHORIZED causes permanent failure.
@@ -158,7 +242,7 @@ TEST_F(RealPanWalletClientTest, ReauthNeeded) {
EXPECT_EQ("", real_pan_);
}
- result_ = AutofillClient::SUCCESS;
+ result_ = AutofillClient::NONE;
real_pan_.clear();
{
@@ -166,7 +250,7 @@ TEST_F(RealPanWalletClientTest, ReauthNeeded) {
IssueOAuthToken();
ReturnResponse(net::HTTP_UNAUTHORIZED, "");
// No response yet.
- EXPECT_EQ(AutofillClient::SUCCESS, result_);
+ EXPECT_EQ(AutofillClient::NONE, result_);
EXPECT_EQ("", real_pan_);
// HTTP_OK after first HTTP_UNAUTHORIZED results in success.
@@ -177,7 +261,7 @@ TEST_F(RealPanWalletClientTest, ReauthNeeded) {
}
}
-TEST_F(RealPanWalletClientTest, NetworkError) {
+TEST_F(PaymentsClientTest, NetworkError) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_REQUEST_TIMEOUT, std::string());
@@ -185,7 +269,7 @@ TEST_F(RealPanWalletClientTest, NetworkError) {
EXPECT_EQ("", real_pan_);
}
-TEST_F(RealPanWalletClientTest, OtherError) {
+TEST_F(PaymentsClientTest, OtherError) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_FORBIDDEN, std::string());
@@ -194,4 +278,4 @@ TEST_F(RealPanWalletClientTest, OtherError) {
}
} // namespace autofill
-} // namespace wallet
+} // namespace payments
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 1ecaf93..28ad3c5 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -90,6 +90,9 @@ source_set("browser") {
"options_util.h",
"password_generator.cc",
"password_generator.h",
+ "payments/payments_client.cc",
+ "payments/payments_client.h",
+ "payments/payments_request.h",
"personal_data_manager.cc",
"personal_data_manager.h",
"personal_data_manager_observer.h",
@@ -112,8 +115,6 @@ source_set("browser") {
"ui/card_unmask_prompt_view.h",
"validation.cc",
"validation.h",
- "wallet/real_pan_wallet_client.cc",
- "wallet/real_pan_wallet_client.h",
"webdata/autocomplete_syncable_service.cc",
"webdata/autocomplete_syncable_service.h",
"webdata/autofill_change.cc",
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index b89acc9..a1faf80 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -11,6 +11,7 @@
#include "base/i18n/rtl.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
+#include "base/values.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
@@ -60,7 +61,7 @@ class AutofillClient {
AutocompleteResultErrorInvalid,
};
- enum GetRealPanResult {
+ enum PaymentsRpcResult {
// Empty result. Used for initializing variables and should generally
// not be returned nor passed as arguments unless explicitly allowed by
// the API.
@@ -75,7 +76,7 @@ class AutofillClient {
// Request failed; don't try again.
PERMANENT_FAILURE,
- // Unable to connect to Wallet servers. Prompt user to check internet
+ // Unable to connect to Payments servers. Prompt user to check internet
// connection.
NETWORK_ERROR,
};
@@ -115,12 +116,21 @@ class AutofillClient {
// information to proceed.
virtual void ShowUnmaskPrompt(const CreditCard& card,
base::WeakPtr<CardUnmaskDelegate> delegate) = 0;
- virtual void OnUnmaskVerificationResult(GetRealPanResult result) = 0;
+ virtual void OnUnmaskVerificationResult(PaymentsRpcResult result) = 0;
- // Run |save_card_callback| if the credit card should be imported as personal
+ // Runs |callback| if the credit card should be imported as personal
// data. |metric_logger| can be used to log user actions.
- virtual void ConfirmSaveCreditCard(
- const base::Closure& save_card_callback) = 0;
+ virtual void ConfirmSaveCreditCardLocally(const base::Closure& callback) = 0;
+
+ // Runs |callback| if the credit card should be uploaded to Payments. Displays
+ // the contents of |legal_message| to the user.
+ virtual void ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) = 0;
+
+ // Gathers risk data and provides it to |callback|.
+ virtual void LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) = 0;
// Returns true if both the platform and the device support scanning credit
// cards. Should be called before ScanCreditCard().
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index c43f5b4..23a6e25 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -7,8 +7,10 @@
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/prefs/pref_service.h"
+#include "base/strings/string_util.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/autofill_switches.h"
+#include "google_apis/gaia/gaia_auth_util.h"
namespace autofill {
@@ -47,4 +49,30 @@ bool OfferStoreUnmaskedCards() {
#endif
}
+bool IsCreditCardUploadEnabled(const PrefService* pref_service,
+ const std::string& user_email) {
+ // Query the field trial before checking command line flags to ensure UMA
+ // reports the correct group.
+ std::string group_name =
+ base::FieldTrialList::FindFullName("OfferUploadCreditCards");
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableOfferUploadCreditCards))
+ return true;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableOfferUploadCreditCards))
+ return false;
+
+ if (group_name.empty() || group_name == "Disabled")
+ return false;
+
+ if (!pref_service->GetBoolean(prefs::kAutofillWalletSyncExperimentEnabled) ||
+ !pref_service->GetBoolean(prefs::kAutofillWalletImportEnabled))
+ return false;
+
+ std::string domain = gaia::ExtractDomainName(user_email);
+ return domain == "googlemail.com" || domain == "gmail.com" ||
+ domain == "google.com";
+}
+
} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index cd2764e..3a152cc 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_EXPERIMENTS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_EXPERIMENTS_H_
+#include <string>
+
class PrefService;
namespace autofill {
@@ -24,6 +26,12 @@ bool IsInAutofillSuggestionsDisabledExperiment();
// response of the option.
bool OfferStoreUnmaskedCards();
+// Returns true if uploading credit cards to Wallet servers is enabled. This
+// requires the appropriate flags and user settings to be true and the user to
+// be a member of a supported domain.
+bool IsCreditCardUploadEnabled(const PrefService* pref_service,
+ const std::string& user_email);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_EXPERIMENTS_H_
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index edc99de..8e05d1f 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -52,6 +52,7 @@
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/pref_registry/pref_registry_syncable.h"
+#include "google_apis/gaia/identity_provider.h"
#include "grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect.h"
@@ -135,7 +136,8 @@ AutofillManager::AutofillManager(
AutofillDownloadManagerState enable_download_manager)
: driver_(driver),
client_(client),
- real_pan_client_(driver->GetURLRequestContext(), this),
+ payments_client_(
+ new payments::PaymentsClient(driver->GetURLRequestContext(), this)),
app_locale_(app_locale),
personal_data_(client->GetPersonalDataManager()),
autocomplete_history_manager_(
@@ -150,6 +152,7 @@ AutofillManager::AutofillManager(
user_did_type_(false),
user_did_autofill_(false),
user_did_edit_autofilled_field_(false),
+ user_did_accept_upload_prompt_(false),
external_delegate_(NULL),
test_delegate_(NULL),
weak_ptr_factory_(this) {
@@ -511,13 +514,15 @@ void AutofillManager::FillOrPreviewCreditCardForm(
if (action == AutofillDriver::FORM_DATA_ACTION_FILL) {
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD &&
WillFillCreditCardNumber(form, field)) {
- unmasking_card_ = credit_card;
+ unmask_request_.card = credit_card;
unmasking_query_id_ = query_id;
unmasking_form_ = form;
unmasking_field_ = field;
- real_pan_client_.Prepare();
- client()->ShowUnmaskPrompt(unmasking_card_,
- weak_ptr_factory_.GetWeakPtr());
+ payments_client_->Prepare();
+ client_->ShowUnmaskPrompt(unmask_request_.card,
+ weak_ptr_factory_.GetWeakPtr());
+ client_->LoadRiskData(base::Bind(&AutofillManager::OnDidGetUnmaskRiskData,
+ weak_ptr_factory_.GetWeakPtr()));
credit_card_form_event_logger_->OnDidSelectMaskedServerCardSuggestion();
return;
}
@@ -714,7 +719,7 @@ void AutofillManager::RemoveAutocompleteEntry(const base::string16& name,
}
bool AutofillManager::IsShowingUnmaskPrompt() {
- return unmasking_card_.Compare(CreditCard()) != 0;
+ return unmask_request_.card.Compare(CreditCard()) != 0;
}
const std::vector<FormStructure*>& AutofillManager::GetFormStructures() {
@@ -750,48 +755,103 @@ void AutofillManager::OnLoadedServerPredictions(
}
void AutofillManager::OnUnmaskResponse(const UnmaskResponse& response) {
- unmask_response_ = response;
- real_pan_request_timestamp_ = base::Time::Now();
- real_pan_client_.UnmaskCard(unmasking_card_, response);
+ unmask_request_.user_response = response;
+ if (!unmask_request_.risk_data.empty()) {
+ real_pan_request_timestamp_ = base::Time::Now();
+ payments_client_->UnmaskCard(unmask_request_);
+ }
}
void AutofillManager::OnUnmaskPromptClosed() {
- real_pan_client_.CancelRequest();
+ payments_client_->CancelRequest();
driver_->RendererShouldClearPreviewedForm();
- unmasking_card_ = CreditCard();
- unmask_response_ = UnmaskResponse();
+ unmask_request_ = payments::PaymentsClient::UnmaskRequestDetails();
}
IdentityProvider* AutofillManager::GetIdentityProvider() {
- return client()->GetIdentityProvider();
+ return client_->GetIdentityProvider();
}
-void AutofillManager::OnDidGetRealPan(AutofillClient::GetRealPanResult result,
+void AutofillManager::OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) {
AutofillMetrics::LogRealPanDuration(
base::Time::Now() - real_pan_request_timestamp_, result);
if (!real_pan.empty()) {
DCHECK_EQ(AutofillClient::SUCCESS, result);
- credit_card_form_event_logger_->OnDidFillSuggestion(unmasking_card_);
- recently_unmasked_cards_.push_back(unmasking_card_);
- unmasking_card_.set_record_type(CreditCard::FULL_SERVER_CARD);
- unmasking_card_.SetNumber(base::UTF8ToUTF16(real_pan));
- if (!unmask_response_.exp_month.empty()) {
- unmasking_card_.SetRawInfo(CREDIT_CARD_EXP_MONTH,
- unmask_response_.exp_month);
+ credit_card_form_event_logger_->OnDidFillSuggestion(unmask_request_.card);
+ recently_unmasked_cards_.push_back(unmask_request_.card);
+ unmask_request_.card.set_record_type(CreditCard::FULL_SERVER_CARD);
+ unmask_request_.card.SetNumber(base::UTF8ToUTF16(real_pan));
+ if (!unmask_request_.user_response.exp_month.empty()) {
+ unmask_request_.card.SetRawInfo(CREDIT_CARD_EXP_MONTH,
+ unmask_request_.user_response.exp_month);
}
- if (!unmask_response_.exp_year.empty()) {
- unmasking_card_.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- unmask_response_.exp_year);
+ if (!unmask_request_.user_response.exp_year.empty()) {
+ unmask_request_.card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ unmask_request_.user_response.exp_year);
}
- if (unmask_response_.should_store_pan)
- personal_data_->UpdateServerCreditCard(unmasking_card_);
+ if (unmask_request_.user_response.should_store_pan)
+ personal_data_->UpdateServerCreditCard(unmask_request_.card);
FillCreditCardForm(unmasking_query_id_, unmasking_form_, unmasking_field_,
- unmasking_card_);
+ unmask_request_.card);
+ }
+
+ client_->OnUnmaskVerificationResult(result);
+}
+
+void AutofillManager::OnDidGetUploadDetails(
+ AutofillClient::PaymentsRpcResult result,
+ const base::string16& context_token,
+ scoped_ptr<base::DictionaryValue> legal_message) {
+ // TODO(jdonnelly): Log duration.
+ if (result == AutofillClient::SUCCESS) {
+ // Do *not* call payments_client_->Prepare() here. We shouldn't send
+ // credentials until the user has explicitly accepted a prompt to upload.
+ upload_request_.context_token = context_token;
+ user_did_accept_upload_prompt_ = false;
+ client_->ConfirmSaveCreditCardToCloud(
+ base::Bind(&AutofillManager::OnUserDidAcceptUpload,
+ weak_ptr_factory_.GetWeakPtr()),
+ legal_message.Pass());
+ client_->LoadRiskData(base::Bind(&AutofillManager::OnDidGetUploadRiskData,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ // Since the upload details request failed, fallback to a local save.
+ client_->ConfirmSaveCreditCardLocally(base::Bind(
+ base::IgnoreResult(&PersonalDataManager::SaveImportedCreditCard),
+ base::Unretained(personal_data_), upload_request_.card));
+ }
+}
+
+void AutofillManager::OnDidUploadCard(
+ AutofillClient::PaymentsRpcResult result) {
+ // We don't do anything user-visible if the upload attempt fails.
+ // TODO(jdonnelly): Log duration.
+}
+
+void AutofillManager::OnDidGetUnmaskRiskData(const std::string& risk_data) {
+ unmask_request_.risk_data = risk_data;
+ if (!unmask_request_.user_response.cvc.empty()) {
+ real_pan_request_timestamp_ = base::Time::Now();
+ payments_client_->UnmaskCard(unmask_request_);
+ }
+}
+
+void AutofillManager::OnUserDidAcceptUpload() {
+ user_did_accept_upload_prompt_ = true;
+ if (!upload_request_.risk_data.empty()) {
+ upload_request_.app_locale = app_locale_;
+ payments_client_->UploadCard(upload_request_);
}
+}
- client()->OnUnmaskVerificationResult(result);
+void AutofillManager::OnDidGetUploadRiskData(const std::string& risk_data) {
+ upload_request_.risk_data = risk_data;
+ if (user_did_accept_upload_prompt_) {
+ upload_request_.app_locale = app_locale_;
+ payments_client_->UploadCard(upload_request_);
+ }
}
void AutofillManager::OnDidEndTextFieldEditing() {
@@ -802,6 +862,11 @@ bool AutofillManager::IsAutofillEnabled() const {
return ::autofill::IsAutofillEnabled(client_->GetPrefs());
}
+bool AutofillManager::IsCreditCardUploadEnabled() {
+ return ::autofill::IsCreditCardUploadEnabled(
+ client_->GetPrefs(), GetIdentityProvider()->GetActiveUsername());
+}
+
bool AutofillManager::ShouldUploadForm(const FormStructure& form) {
if (!IsAutofillEnabled())
return false;
@@ -860,11 +925,28 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
imported_credit_card->TypeAndLastFourDigits())
return;
}
- client_->ConfirmSaveCreditCard(
- base::Bind(
- base::IgnoreResult(&PersonalDataManager::SaveImportedCreditCard),
- base::Unretained(personal_data_),
- *imported_credit_card));
+
+ // Check for a CVC in order to determine whether we can prompt the user to
+ // upload their card.
+ for (const auto& field : submitted_form) {
+ if (field->Type().GetStorableType() == CREDIT_CARD_VERIFICATION_CODE) {
+ upload_request_.cvc = field->value;
+ break;
+ }
+ }
+
+ if (!upload_request_.cvc.empty() && IsCreditCardUploadEnabled()) {
+ // Initiate the upload flow if a CVC was entered into the form and the
+ // feature is enabled.
+ upload_request_ = payments::PaymentsClient::UploadRequestDetails();
+ upload_request_.card = *imported_credit_card;
+ payments_client_->GetUploadDetails(app_locale_);
+ } else {
+ // Otherwise, prompt the user for local save.
+ client_->ConfirmSaveCreditCardLocally(base::Bind(
+ base::IgnoreResult(&PersonalDataManager::SaveImportedCreditCard),
+ base::Unretained(personal_data_), *imported_credit_card));
+ }
}
}
@@ -908,6 +990,8 @@ void AutofillManager::UploadFormData(const FormStructure& submitted_form) {
}
void AutofillManager::Reset() {
+ // Note that upload_request_ is not reset here because the prompt to
+ // save a card is shown after page navigation.
form_structures_.clear();
address_form_event_logger_.reset(
new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */));
@@ -919,7 +1003,7 @@ void AutofillManager::Reset() {
user_did_type_ = false;
user_did_autofill_ = false;
user_did_edit_autofilled_field_ = false;
- unmasking_card_ = CreditCard();
+ unmask_request_ = payments::PaymentsClient::UnmaskRequestDetails();
unmasking_query_id_ = -1;
unmasking_form_ = FormData();
unmasking_field_ = FormFieldData();
@@ -933,7 +1017,8 @@ AutofillManager::AutofillManager(AutofillDriver* driver,
PersonalDataManager* personal_data)
: driver_(driver),
client_(client),
- real_pan_client_(driver->GetURLRequestContext(), this),
+ payments_client_(
+ new payments::PaymentsClient(driver->GetURLRequestContext(), this)),
app_locale_("en-US"),
personal_data_(personal_data),
autocomplete_history_manager_(
@@ -1116,10 +1201,10 @@ void AutofillManager::FillOrPreviewDataModelForm(
if (is_credit_card &&
cached_field->Type().GetStorableType() ==
CREDIT_CARD_VERIFICATION_CODE) {
- // If this is |unmasking_card_|, |unmask_response_.cvc| should be
- // non-empty and vice versa.
- value = unmask_response_.cvc;
- DCHECK_EQ(&unmasking_card_ == &data_model, !value.empty());
+ // If this is |unmask_request_.card|, |unmask_request_.user_response.cvc|
+ // should be non-empty and vice versa.
+ value = unmask_request_.user_response.cvc;
+ DCHECK_EQ(&unmask_request_.card == &data_model, !value.empty());
}
// Must match ForEachMatchingFormField() in form_autofill_util.cc.
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index c7b3029..90c30e4 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -26,8 +26,8 @@
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/card_unmask_delegate.h"
#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/wallet/real_pan_wallet_client.h"
#include "components/autofill/core/common/form_data.h"
// This define protects some debugging code (see DumpAutofillData). This
@@ -71,7 +71,7 @@ struct FormFieldData;
// forms. One per frame; owned by the AutofillDriver.
class AutofillManager : public AutofillDownloadManager::Observer,
public CardUnmaskDelegate,
- public wallet::RealPanWalletClient::Delegate {
+ public payments::PaymentsClientDelegate {
public:
enum AutofillDownloadManagerState {
ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
@@ -127,7 +127,7 @@ class AutofillManager : public AutofillDownloadManager::Observer,
void RemoveAutocompleteEntry(const base::string16& name,
const base::string16& value);
- // Returns true when the Wallet card unmask prompt is being displayed.
+ // Returns true when the Payments card unmask prompt is being displayed.
bool IsShowingUnmaskPrompt();
// Returns the present form structures seen by Autofill manager.
@@ -150,6 +150,8 @@ class AutofillManager : public AutofillDownloadManager::Observer,
void OnFormsSeen(const std::vector<FormData>& forms,
const base::TimeTicks& timestamp);
+ void set_app_locale(std::string app_locale) { app_locale_ = app_locale; }
+
// IMPORTANT: On iOS, this method is called when the form is submitted,
// immediately before OnFormSubmitted() is called. Do not assume that
// OnWillSubmitForm() will run before the form submits.
@@ -184,6 +186,10 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Returns the value of the AutofillEnabled pref.
virtual bool IsAutofillEnabled() const;
+ // Returns true if all the conditions for enabling the upload of credit card
+ // are satisfied.
+ virtual bool IsCreditCardUploadEnabled();
+
// Shared code to determine if |form| should be uploaded to the Autofill
// server. It verifies that uploading is allowed and |form| meets conditions
// to be uploadable.
@@ -222,6 +228,7 @@ class AutofillManager : public AutofillDownloadManager::Observer,
ScopedVector<FormStructure>* form_structures() { return &form_structures_; }
+ protected:
// Exposed for testing.
AutofillExternalDelegate* external_delegate() {
return external_delegate_;
@@ -232,6 +239,11 @@ class AutofillManager : public AutofillDownloadManager::Observer,
download_manager_.reset(manager);
}
+ // Exposed for testing.
+ void set_payments_client(payments::PaymentsClient* payments_client) {
+ payments_client_.reset(payments_client);
+ }
+
private:
// AutofillDownloadManager::Observer:
void OnLoadedServerPredictions(const std::string& response_xml) override;
@@ -240,10 +252,27 @@ class AutofillManager : public AutofillDownloadManager::Observer,
void OnUnmaskResponse(const UnmaskResponse& response) override;
void OnUnmaskPromptClosed() override;
- // wallet::RealPanWalletClient::Delegate:
+ // payments::PaymentsClientDelegate:
IdentityProvider* GetIdentityProvider() override;
- void OnDidGetRealPan(AutofillClient::GetRealPanResult result,
+ void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) override;
+ void OnDidGetUploadDetails(
+ AutofillClient::PaymentsRpcResult result,
+ const base::string16& context_token,
+ scoped_ptr<base::DictionaryValue> legal_message) override;
+ void OnDidUploadCard(AutofillClient::PaymentsRpcResult result) override;
+
+ // Saves risk data in |unmasking_risk_data_| and calls UnmaskCard if the user
+ // has accepted the prompt.
+ void OnDidGetUnmaskRiskData(const std::string& risk_data);
+
+ // Sets |user_did_accept_upload_prompt_| and calls UploadCard if the risk data
+ // is available.
+ void OnUserDidAcceptUpload();
+
+ // Saves risk data in |uploading_risk_data_| and calls UploadCard if the user
+ // has accepted the prompt.
+ void OnDidGetUploadRiskData(const std::string& risk_data);
// Returns false if Autofill is disabled or if no Autofill data is available.
bool RefreshDataModels();
@@ -361,8 +390,8 @@ class AutofillManager : public AutofillDownloadManager::Observer,
AutofillClient* const client_;
- // Handles real PAN requests.
- wallet::RealPanWalletClient real_pan_client_;
+ // Handles Payments service requests.
+ scoped_ptr<payments::PaymentsClient> payments_client_;
std::string app_locale_;
@@ -407,17 +436,19 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Our copy of the form data.
ScopedVector<FormStructure> form_structures_;
- // A copy of the credit card that's currently being unmasked, and data about
- // the form.
- CreditCard unmasking_card_;
- // A copy of the latest card unmasking response.
- UnmaskResponse unmask_response_;
+ // Collected information about a pending unmask request, and data about the
+ // form.
+ payments::PaymentsClient::UnmaskRequestDetails unmask_request_;
int unmasking_query_id_;
FormData unmasking_form_;
FormFieldData unmasking_field_;
- // Time when we requested the last real pan
+ // Time when we requested the last real pan.
base::Time real_pan_request_timestamp_;
+ // Collected information about a pending upload request.
+ payments::PaymentsClient::UploadRequestDetails upload_request_;
+ bool user_did_accept_upload_prompt_;
+
// Masked copies of recently unmasked cards, to help avoid double-asking to
// save the card (in the prompt and in the infobar after submit).
std::vector<CreditCard> recently_unmasked_cards_;
@@ -494,7 +525,7 @@ class AutofillManager : public AutofillDownloadManager::Observer,
AutocompleteOffRespectedForAutocomplete);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
DontSaveCvcInAutocompleteHistory);
- FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DontOfferToSaveWalletCard);
+ FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DontOfferToSavePaymentsCard);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, FillInUpdatedExpirationDate);
DISALLOW_COPY_AND_ASSIGN(AutofillManager);
};
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index f5cbdfa..7383a8e 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -63,13 +63,40 @@ class MockAutofillClient : public TestAutofillClient {
~MockAutofillClient() override {}
- MOCK_METHOD1(ConfirmSaveCreditCard,
- void(const base::Closure& save_card_callback));
+ MOCK_METHOD1(ConfirmSaveCreditCardLocally,
+ void(const base::Closure& callback));
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
};
+class TestPaymentsClient : public payments::PaymentsClient {
+ public:
+ TestPaymentsClient(net::URLRequestContextGetter* context_getter,
+ payments::PaymentsClientDelegate* delegate)
+ : PaymentsClient(context_getter, delegate), delegate_(delegate) {}
+
+ ~TestPaymentsClient() override {}
+
+ void GetUploadDetails(const std::string& app_locale) override {
+ delegate_->OnDidGetUploadDetails(
+ app_locale == "en-US" ? AutofillClient::SUCCESS
+ : AutofillClient::PERMANENT_FAILURE,
+ base::ASCIIToUTF16("this is a context token"),
+ scoped_ptr<base::DictionaryValue>(nullptr));
+ }
+
+ void UploadCard(const payments::PaymentsClient::UploadRequestDetails&
+ request_details) override {
+ delegate_->OnDidUploadCard(AutofillClient::SUCCESS);
+ }
+
+ private:
+ payments::PaymentsClientDelegate* const delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient);
+};
+
class TestPersonalDataManager : public PersonalDataManager {
public:
TestPersonalDataManager()
@@ -297,7 +324,7 @@ void ExpectFilledForm(int page_id,
bool use_month_type) {
// The number of fields in the address and credit card forms created above.
const size_t kAddressFormSize = 11;
- const size_t kCreditCardFormSize = use_month_type ? 3 : 4;
+ const size_t kCreditCardFormSize = use_month_type ? 4 : 5;
EXPECT_EQ(expected_page_id, page_id);
EXPECT_EQ(ASCIIToUTF16("MyForm"), filled_form.name);
@@ -433,7 +460,12 @@ class TestAutofillManager : public AutofillManager {
: AutofillManager(driver, client, personal_data),
personal_data_(personal_data),
autofill_enabled_(true),
- expect_all_unknown_possible_types_(false) {}
+ credit_card_upload_enabled_(true),
+ credit_card_was_uploaded_(false),
+ expect_all_unknown_possible_types_(false) {
+ set_payments_client(
+ new TestPaymentsClient(driver->GetURLRequestContext(), this));
+ }
~TestAutofillManager() override {}
bool IsAutofillEnabled() const override { return autofill_enabled_; }
@@ -442,6 +474,16 @@ class TestAutofillManager : public AutofillManager {
autofill_enabled_ = autofill_enabled;
}
+ bool IsCreditCardUploadEnabled() override {
+ return credit_card_upload_enabled_;
+ }
+
+ void set_credit_card_upload_enabled(bool credit_card_upload_enabled) {
+ credit_card_upload_enabled_ = credit_card_upload_enabled;
+ }
+
+ bool credit_card_was_uploaded() { return credit_card_was_uploaded_; }
+
void set_expected_submitted_field_types(
const std::vector<ServerFieldTypeSet>& expected_types) {
expected_submitted_field_types_ = expected_types;
@@ -529,10 +571,16 @@ class TestAutofillManager : public AutofillManager {
}
private:
+ void OnDidUploadCard(AutofillClient::PaymentsRpcResult result) override {
+ credit_card_was_uploaded_ = true;
+ };
+
// Weak reference.
TestPersonalDataManager* personal_data_;
bool autofill_enabled_;
+ bool credit_card_upload_enabled_;
+ bool credit_card_was_uploaded_;
bool expect_all_unknown_possible_types_;
scoped_ptr<base::RunLoop> run_loop_;
@@ -774,6 +822,8 @@ class AutofillManagerTest : public testing::Test {
test::CreateTestFormField("", "ccyear", "", "text", &field);
form->fields.push_back(field);
}
+ test::CreateTestFormField("CVC", "cvc", "", "text", &field);
+ form->fields.push_back(field);
}
// Tests if credit card data gets saved
@@ -788,13 +838,13 @@ class AutofillManagerTest : public testing::Test {
form.fields[1].value = ASCIIToUTF16("4111111111111111");
form.fields[2].value = ASCIIToUTF16("11");
form.fields[3].value = ASCIIToUTF16("2017");
- EXPECT_CALL(autofill_client_, ConfirmSaveCreditCard(_)).Times(1);
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
FormSubmitted(form);
}
void PrepareForRealPanResponse(FormData* form, CreditCard* card) {
- // This line silences the warning from RealPanWalletClient about matching
- // sync and wallet server types.
+ // This line silences the warning from PaymentsClient about matching sync
+ // and Payments server types.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
"sync-url", "https://google.com");
@@ -805,7 +855,7 @@ class AutofillManagerTest : public testing::Test {
"2017");
card->SetTypeForMaskedCard(kVisaCard);
- EXPECT_CALL(autofill_client_, ConfirmSaveCreditCard(_)).Times(0);
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(0);
EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _))
.Times(AtLeast(1));
autofill_manager_->FillOrPreviewCreditCardForm(
@@ -834,6 +884,7 @@ class AutofillManagerTest : public testing::Test {
scoped_ptr<TestAutofillManager> autofill_manager_;
scoped_ptr<TestAutofillExternalDelegate> external_delegate_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+ TestPaymentsClient* payments_client_;
TestAutofillDownloadManager* download_manager_;
TestPersonalDataManager personal_data_;
};
@@ -2089,9 +2140,9 @@ TEST_F(AutofillManagerTest, FillAutofilledForm) {
const int kPageID3 = 3;
response_page_id = 0;
- FillAutofillFormDataAndSaveResults(kPageID3, form, *form.fields.rbegin(),
- MakeFrontendID(guid2, std::string()),
- &response_page_id, &response_data);
+ FillAutofillFormDataAndSaveResults(
+ kPageID3, form, form.fields[form.fields.size() - 2],
+ MakeFrontendID(guid2, std::string()), &response_page_id, &response_data);
{
SCOPED_TRACE("Credit card 2");
ExpectFilledForm(response_page_id, response_data, kPageID3, "", "", "", "",
@@ -2684,7 +2735,7 @@ TEST_F(AutofillManagerTest, CreditCardSavedWhenAutocompleteOff) {
form.fields[1].value = ASCIIToUTF16("4111111111111111");
form.fields[2].value = ASCIIToUTF16("11");
form.fields[3].value = ASCIIToUTF16("2017");
- EXPECT_CALL(autofill_client_, ConfirmSaveCreditCard(_)).Times(1);
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
FormSubmitted(form);
}
@@ -2703,7 +2754,7 @@ TEST_F(AutofillManagerTest, InvalidCreditCardNumberIsNotSaved) {
form.fields[1].value = ASCIIToUTF16(card);
form.fields[2].value = ASCIIToUTF16("11");
form.fields[3].value = ASCIIToUTF16("2017");
- EXPECT_CALL(autofill_client_, ConfirmSaveCreditCard(_)).Times(0);
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(0);
FormSubmitted(form);
}
@@ -3176,7 +3227,7 @@ TEST_F(AutofillManagerTest, DontSaveCvcInAutocompleteHistory) {
}
}
-TEST_F(AutofillManagerTest, DontOfferToSaveWalletCard) {
+TEST_F(AutofillManagerTest, DontOfferToSavePaymentsCard) {
FormData form;
CreditCard card;
PrepareForRealPanResponse(&form, &card);
@@ -3250,10 +3301,92 @@ TEST_F(AutofillManagerTest, FillInUpdatedExpirationDate) {
autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
"4012888888881881");
- EXPECT_EQ(ASCIIToUTF16("02"), autofill_manager_->unmasking_card_.GetRawInfo(
- CREDIT_CARD_EXP_MONTH));
- EXPECT_EQ(ASCIIToUTF16("2018"), autofill_manager_->unmasking_card_.GetRawInfo(
- CREDIT_CARD_EXP_4_DIGIT_YEAR));
+ EXPECT_EQ(ASCIIToUTF16("02"),
+ autofill_manager_->unmask_request_.card.GetRawInfo(
+ CREDIT_CARD_EXP_MONTH));
+ EXPECT_EQ(ASCIIToUTF16("2018"),
+ autofill_manager_->unmask_request_.card.GetRawInfo(
+ CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
+
+TEST_F(AutofillManagerTest, UploadCreditCard) {
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ // Edit the data, and submit
+ form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ form.fields[2].value = ASCIIToUTF16("11");
+ form.fields[3].value = ASCIIToUTF16("2017");
+ form.fields[4].value = ASCIIToUTF16("123");
+
+ FormSubmitted(form);
+ EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+}
+
+TEST_F(AutofillManagerTest, DontUploadCreditCardIfFeatureNotEnabled) {
+ autofill_manager_->set_credit_card_upload_enabled(false);
+
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ // Edit the data, and submit
+ form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ form.fields[2].value = ASCIIToUTF16("11");
+ form.fields[3].value = ASCIIToUTF16("2017");
+ form.fields[4].value = ASCIIToUTF16("123");
+
+ // The save prompt should be shown instead of doing an upload.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
+ FormSubmitted(form);
+ EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
+}
+
+TEST_F(AutofillManagerTest, DontUploadCreditCardIfCvcUnavailable) {
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ // Edit the data, and submit
+ form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ form.fields[2].value = ASCIIToUTF16("11");
+ form.fields[3].value = ASCIIToUTF16("2017");
+ form.fields[4].value = ASCIIToUTF16(""); // CVC
+
+ // The save prompt should be shown instead of doing an upload.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
+ FormSubmitted(form);
+ EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
+}
+
+TEST_F(AutofillManagerTest, DontUploadCreditCardIfUploadDetailsFails) {
+ // Anything other than "en-US" will cause GetUploadDetails to return a failure
+ // response.
+ autofill_manager_->set_app_locale("pt-BR");
+
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ // Edit the data, and submit
+ form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ form.fields[2].value = ASCIIToUTF16("11");
+ form.fields[3].value = ASCIIToUTF16("2017");
+ form.fields[4].value = ASCIIToUTF16("123");
+
+ // The save prompt should be shown instead of doing an upload.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
+ FormSubmitted(form);
+ EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
}
// Verify that typing "gmail" will match "theking@gmail.com" and
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index cacfe91..85a3370 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -391,34 +391,33 @@ void AutofillMetrics::LogTimeBeforeAbandonUnmasking(
// static
void AutofillMetrics::LogRealPanResult(
- AutofillClient::GetRealPanResult result) {
- GetRealPanResult metric_result;
+ AutofillClient::PaymentsRpcResult result) {
+ PaymentsRpcResult metric_result;
switch (result) {
case AutofillClient::SUCCESS:
- metric_result = GET_REAL_PAN_RESULT_SUCCESS;
+ metric_result = PAYMENTS_RESULT_SUCCESS;
break;
case AutofillClient::TRY_AGAIN_FAILURE:
- metric_result = GET_REAL_PAN_RESULT_TRY_AGAIN_FAILURE;
+ metric_result = PAYMENTS_RESULT_TRY_AGAIN_FAILURE;
break;
case AutofillClient::PERMANENT_FAILURE:
- metric_result = GET_REAL_PAN_RESULT_PERMANENT_FAILURE;
+ metric_result = PAYMENTS_RESULT_PERMANENT_FAILURE;
break;
case AutofillClient::NETWORK_ERROR:
- metric_result = GET_REAL_PAN_RESULT_NETWORK_ERROR;
+ metric_result = PAYMENTS_RESULT_NETWORK_ERROR;
break;
default:
NOTREACHED();
return;
}
UMA_HISTOGRAM_ENUMERATION("Autofill.UnmaskPrompt.GetRealPanResult",
- metric_result,
- NUM_GET_REAL_PAN_RESULTS);
+ metric_result, NUM_PAYMENTS_RESULTS);
}
// static
void AutofillMetrics::LogRealPanDuration(
const base::TimeDelta& duration,
- AutofillClient::GetRealPanResult result) {
+ AutofillClient::PaymentsRpcResult result) {
std::string suffix;
switch (result) {
case AutofillClient::SUCCESS:
@@ -444,7 +443,7 @@ void AutofillMetrics::LogRealPanDuration(
// static
void AutofillMetrics::LogUnmaskingDuration(
const base::TimeDelta& duration,
- AutofillClient::GetRealPanResult result) {
+ AutofillClient::PaymentsRpcResult result) {
std::string suffix;
switch (result) {
case AutofillClient::SUCCESS:
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h
index 1219c97..4688d05 100644
--- a/components/autofill/core/browser/autofill_metrics.h
+++ b/components/autofill/core/browser/autofill_metrics.h
@@ -348,17 +348,17 @@ class AutofillMetrics {
NUM_UNMASK_PROMPT_EVENTS,
};
- // Possible results of the GetRealPan call.
- enum GetRealPanResult {
+ // Possible results of Payments RPCs.
+ enum PaymentsRpcResult {
// Request succeeded.
- GET_REAL_PAN_RESULT_SUCCESS = 0,
+ PAYMENTS_RESULT_SUCCESS = 0,
// Request failed; try again.
- GET_REAL_PAN_RESULT_TRY_AGAIN_FAILURE,
+ PAYMENTS_RESULT_TRY_AGAIN_FAILURE,
// Request failed; don't try again.
- GET_REAL_PAN_RESULT_PERMANENT_FAILURE,
- // Unable to connect to Wallet servers.
- GET_REAL_PAN_RESULT_NETWORK_ERROR,
- NUM_GET_REAL_PAN_RESULTS,
+ PAYMENTS_RESULT_PERMANENT_FAILURE,
+ // Unable to connect to Payments servers.
+ PAYMENTS_RESULT_NETWORK_ERROR,
+ NUM_PAYMENTS_RESULTS,
};
// For measuring the network request time of various Wallet API calls. See
@@ -509,15 +509,15 @@ class AutofillMetrics {
static void LogTimeBeforeAbandonUnmasking(const base::TimeDelta& duration);
// Logs |result| to the get real pan result histogram.
- static void LogRealPanResult(AutofillClient::GetRealPanResult result);
+ static void LogRealPanResult(AutofillClient::PaymentsRpcResult result);
// Logs |result| to duration of the GetRealPan RPC.
static void LogRealPanDuration(const base::TimeDelta& duration,
- AutofillClient::GetRealPanResult result);
+ AutofillClient::PaymentsRpcResult result);
// Logs |result| to the get real pan result histogram.
static void LogUnmaskingDuration(const base::TimeDelta& duration,
- AutofillClient::GetRealPanResult result);
+ AutofillClient::PaymentsRpcResult result);
// Logs |metric| to the Wallet errors histogram.
static void LogWalletErrorMetric(WalletErrorMetric metric);
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index f91dcc2..ed36d53 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -16,10 +16,10 @@
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
-#include "components/autofill/core/browser/wallet/real_pan_wallet_client.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/form_data.h"
diff --git a/components/autofill/core/browser/card_unmask_delegate.cc b/components/autofill/core/browser/card_unmask_delegate.cc
index 709acc1..cb785d4 100644
--- a/components/autofill/core/browser/card_unmask_delegate.cc
+++ b/components/autofill/core/browser/card_unmask_delegate.cc
@@ -7,15 +7,7 @@
namespace autofill {
CardUnmaskDelegate::UnmaskResponse::UnmaskResponse()
- : should_store_pan(false),
- providing_risk_advisory_data(false) {
-#if defined(OS_IOS)
- // On iOS, we generate a RiskAdvisoryData instead of the
- // BrowserNativeFingerprinting produced on other platforms. This field
- // directs the Wallet client to configure the request accordingly.
- providing_risk_advisory_data = true;
-#endif
-}
+ : should_store_pan(false) {}
CardUnmaskDelegate::UnmaskResponse::~UnmaskResponse() {}
diff --git a/components/autofill/core/browser/card_unmask_delegate.h b/components/autofill/core/browser/card_unmask_delegate.h
index 73ec3b0..26103e0 100644
--- a/components/autofill/core/browser/card_unmask_delegate.h
+++ b/components/autofill/core/browser/card_unmask_delegate.h
@@ -28,13 +28,6 @@ class CardUnmaskDelegate {
// State of "copy to this device" checkbox.
bool should_store_pan;
-
- // Risk fingerprint.
- std::string risk_data;
-
- // Whether we're providing the alternative "risk advisory data" in risk_data
- // (as opposed to the normal browser fingerprint).
- bool providing_risk_advisory_data;
};
// Called when the user has attempted a verification. Prompt is still
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
new file mode 100644
index 0000000..aacd534
--- /dev/null
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -0,0 +1,484 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/payments/payments_client.h"
+
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/payments/payments_request.h"
+#include "components/autofill/core/common/autofill_switches.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "google_apis/gaia/identity_provider.h"
+#include "net/base/escape.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace autofill {
+namespace payments {
+
+namespace {
+
+const char kPaymentsRequestHost[] = "https://wallet.google.com";
+const char kPaymentsRequestHostSandbox[] = "https://sandbox.google.com";
+
+const char kUnmaskCardRequestPath[] =
+ "payments/apis-secure/creditcardservice/getrealpan?s7e_suffix=chromewallet";
+const char kUnmaskCardRequestFormat[] =
+ "requestContentType=application/json; charset=utf-8&request=%s"
+ "&s7e_13_cvc=%s";
+
+const char kGetUploadDetailsRequestPath[] =
+ "payments/apis/chromepaymentsservice/getdetailsforsavecard";
+
+const char kUploadCardRequestPath[] =
+ "payments/apis-secure/chromepaymentsservice/savecard"
+ "?s7e_suffix=chromewallet";
+const char kUploadCardRequestFormat[] =
+ "requestContentType=application/json; charset=utf-8&request=%s"
+ "&s7e_1_pan=%s&s7e_13_cvc=%s";
+
+const char kTokenServiceConsumerId[] = "wallet_client";
+const char kPaymentsOAuth2Scope[] =
+ "https://www.googleapis.com/auth/wallet.chrome";
+
+// This is mostly copied from wallet_service_url.cc, which is currently in
+// content/, hence inaccessible from here.
+bool IsPaymentsProductionEnabled() {
+ // If the command line flag exists, it takes precedence.
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ std::string sandbox_enabled(
+ command_line->GetSwitchValueASCII(switches::kWalletServiceUseSandbox));
+ if (!sandbox_enabled.empty())
+ return sandbox_enabled != "1";
+
+#if defined(ENABLE_PROD_WALLET_SERVICE)
+ return true;
+#else
+ return false;
+#endif
+}
+
+GURL GetRequestUrl(const std::string& path) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch("sync-url")) {
+ if (IsPaymentsProductionEnabled()) {
+ LOG(ERROR) << "You are using production Payments but you specified a "
+ "--sync-url. You likely want to disable the sync sandbox "
+ "or switch to sandbox Payments. Both are controlled in "
+ "about:flags.";
+ }
+ } else if (!IsPaymentsProductionEnabled()) {
+ LOG(ERROR) << "You are using sandbox Payments but you didn't specify a "
+ "--sync-url. You likely want to enable the sync sandbox "
+ "or switch to production Payments. Both are controlled in "
+ "about:flags.";
+ }
+
+ GURL base(IsPaymentsProductionEnabled() ? kPaymentsRequestHost
+ : kPaymentsRequestHostSandbox);
+ return base.Resolve(path);
+}
+
+scoped_ptr<base::DictionaryValue> BuildRiskDictionary(
+ const std::string& encoded_risk_data) {
+ scoped_ptr<base::DictionaryValue> risk_data(new base::DictionaryValue());
+#if defined(OS_IOS)
+ // Browser fingerprinting is not available on iOS. Instead, we generate
+ // RiskAdvisoryData.
+ risk_data->SetString("message_type", "RISK_ADVISORY_DATA");
+ risk_data->SetString("encoding_type", "BASE_64_URL");
+#else
+ risk_data->SetString("message_type", "BROWSER_NATIVE_FINGERPRINTING");
+ risk_data->SetString("encoding_type", "BASE_64");
+#endif
+
+ risk_data->SetString("value", encoded_risk_data);
+
+ return risk_data.Pass();
+}
+
+class UnmaskCardRequest : public PaymentsRequest {
+ public:
+ UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details)
+ : request_details_(request_details) {
+ DCHECK_EQ(CreditCard::MASKED_SERVER_CARD,
+ request_details.card.record_type());
+ }
+ ~UnmaskCardRequest() override {}
+
+ std::string GetRequestUrlPath() override { return kUnmaskCardRequestPath; }
+
+ std::string GetRequestContentType() override {
+ return "application/x-www-form-urlencoded";
+ }
+
+ std::string GetRequestContent() override {
+ base::DictionaryValue request_dict;
+ request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc");
+ request_dict.SetString("credit_card_id", request_details_.card.server_id());
+ request_dict.Set("risk_data_encoded",
+ BuildRiskDictionary(request_details_.risk_data));
+ request_dict.Set("context", make_scoped_ptr(new base::DictionaryValue()));
+
+ int value = 0;
+ if (base::StringToInt(request_details_.user_response.exp_month, &value))
+ request_dict.SetInteger("expiration_month", value);
+ if (base::StringToInt(request_details_.user_response.exp_year, &value))
+ request_dict.SetInteger("expiration_year", value);
+
+ std::string json_request;
+ base::JSONWriter::Write(request_dict, &json_request);
+ std::string request_content = base::StringPrintf(
+ kUnmaskCardRequestFormat,
+ net::EscapeUrlEncodedData(json_request, true).c_str(),
+ net::EscapeUrlEncodedData(
+ base::UTF16ToASCII(request_details_.user_response.cvc), true)
+ .c_str());
+ VLOG(3) << "getrealpan request body: " << request_content;
+ return request_content;
+ }
+
+ void ParseResponse(scoped_ptr<base::DictionaryValue> response) override {
+ response->GetString("pan", &real_pan_);
+ }
+
+ bool IsResponseComplete() override { return !real_pan_.empty(); }
+
+ void RespondToDelegate(PaymentsClientDelegate* delegate,
+ AutofillClient::PaymentsRpcResult result) override {
+ delegate->OnDidGetRealPan(result, real_pan_);
+ }
+
+ private:
+ PaymentsClient::UnmaskRequestDetails request_details_;
+ std::string real_pan_;
+};
+
+class GetUploadDetailsRequest : public PaymentsRequest {
+ public:
+ GetUploadDetailsRequest(const std::string& app_locale)
+ : app_locale_(app_locale) {}
+ ~GetUploadDetailsRequest() override {}
+
+ std::string GetRequestUrlPath() override {
+ return kGetUploadDetailsRequestPath;
+ }
+
+ std::string GetRequestContentType() override { return "application/json"; }
+
+ std::string GetRequestContent() override {
+ base::DictionaryValue request_dict;
+ scoped_ptr<base::DictionaryValue> context(new base::DictionaryValue());
+ context->SetString("language_code", app_locale_);
+ request_dict.Set("context", context.Pass());
+
+ std::string request_content;
+ base::JSONWriter::Write(request_dict, &request_content);
+ VLOG(3) << "getsavecarddetails request body: " << request_content;
+ return request_content;
+ }
+
+ void ParseResponse(scoped_ptr<base::DictionaryValue> response) override {
+ response->GetString("context_token", &context_token_);
+ base::DictionaryValue* unowned_legal_message;
+ if (response->GetDictionary("legal_message", &unowned_legal_message))
+ legal_message_ = unowned_legal_message->CreateDeepCopy();
+ }
+
+ bool IsResponseComplete() override {
+ return !context_token_.empty() && legal_message_;
+ }
+
+ void RespondToDelegate(PaymentsClientDelegate* delegate,
+ AutofillClient::PaymentsRpcResult result) override {
+ delegate->OnDidGetUploadDetails(result, context_token_,
+ legal_message_.Pass());
+ }
+
+ private:
+ std::string app_locale_;
+ base::string16 context_token_;
+ scoped_ptr<base::DictionaryValue> legal_message_;
+};
+
+class UploadCardRequest : public PaymentsRequest {
+ public:
+ UploadCardRequest(const PaymentsClient::UploadRequestDetails& request_details)
+ : request_details_(request_details) {}
+ ~UploadCardRequest() override {}
+
+ std::string GetRequestUrlPath() override { return kUploadCardRequestPath; }
+
+ std::string GetRequestContentType() override {
+ return "application/x-www-form-urlencoded";
+ }
+
+ std::string GetRequestContent() override {
+ base::DictionaryValue request_dict;
+ request_dict.SetString("encrypted_pan", "__param:s7e_1_pan");
+ request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc");
+ request_dict.Set("risk_data_encoded",
+ BuildRiskDictionary(request_details_.risk_data));
+
+ scoped_ptr<base::DictionaryValue> context(new base::DictionaryValue());
+ context->SetString("language_code", request_details_.app_locale);
+ request_dict.Set("context", context.Pass());
+
+ request_dict.SetString(
+ "cardholder_name",
+ request_details_.card.GetInfo(AutofillType(CREDIT_CARD_NAME),
+ request_details_.app_locale));
+
+ // TODO(jdonnelly): Get address(es) from the current session or available
+ // profiles and add to the request.
+
+ request_dict.SetString("context_token", request_details_.context_token);
+
+ int value = 0;
+ base::string16 exp_month = request_details_.card.GetInfo(
+ AutofillType(CREDIT_CARD_EXP_MONTH), request_details_.app_locale);
+ base::string16 exp_year = request_details_.card.GetInfo(
+ AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
+ request_details_.app_locale);
+ if (base::StringToInt(exp_month, &value))
+ request_dict.SetInteger("expiration_month", value);
+ if (base::StringToInt(exp_year, &value))
+ request_dict.SetInteger("expiration_year", value);
+
+ base::string16 pan = request_details_.card.GetInfo(
+ AutofillType(CREDIT_CARD_NUMBER), request_details_.app_locale);
+ std::string json_request;
+ base::JSONWriter::Write(request_dict, &json_request);
+ std::string request_content = base::StringPrintf(
+ kUploadCardRequestFormat,
+ net::EscapeUrlEncodedData(json_request, true).c_str(),
+ net::EscapeUrlEncodedData(base::UTF16ToASCII(pan), true).c_str(),
+ net::EscapeUrlEncodedData(base::UTF16ToASCII(request_details_.cvc),
+ true)
+ .c_str());
+ VLOG(3) << "savecard request body: " << request_content;
+ return request_content;
+ }
+
+ void ParseResponse(scoped_ptr<base::DictionaryValue> response) override {}
+
+ bool IsResponseComplete() override { return true; }
+
+ void RespondToDelegate(PaymentsClientDelegate* delegate,
+ AutofillClient::PaymentsRpcResult result) override {
+ delegate->OnDidUploadCard(result);
+ }
+
+ private:
+ PaymentsClient::UploadRequestDetails request_details_;
+};
+
+} // namespace
+
+PaymentsClient::UnmaskRequestDetails::UnmaskRequestDetails() {}
+PaymentsClient::UnmaskRequestDetails::~UnmaskRequestDetails() {}
+
+PaymentsClient::UploadRequestDetails::UploadRequestDetails() {}
+PaymentsClient::UploadRequestDetails::~UploadRequestDetails() {}
+
+PaymentsClient::PaymentsClient(net::URLRequestContextGetter* context_getter,
+ PaymentsClientDelegate* delegate)
+ : OAuth2TokenService::Consumer(kTokenServiceConsumerId),
+ context_getter_(context_getter),
+ delegate_(delegate),
+ has_retried_authorization_(false),
+ weak_ptr_factory_(this) {
+ DCHECK(delegate);
+}
+
+PaymentsClient::~PaymentsClient() {}
+
+void PaymentsClient::Prepare() {
+ if (access_token_.empty())
+ StartTokenFetch(false);
+}
+
+void PaymentsClient::UnmaskCard(
+ const PaymentsClient::UnmaskRequestDetails& request_details) {
+ IssueRequest(make_scoped_ptr(new UnmaskCardRequest(request_details)), true);
+}
+
+void PaymentsClient::GetUploadDetails(const std::string& app_locale) {
+ IssueRequest(make_scoped_ptr(new GetUploadDetailsRequest(app_locale)), false);
+}
+
+void PaymentsClient::UploadCard(
+ const PaymentsClient::UploadRequestDetails& request_details) {
+ IssueRequest(make_scoped_ptr(new UploadCardRequest(request_details)), true);
+}
+
+void PaymentsClient::IssueRequest(scoped_ptr<PaymentsRequest> request,
+ bool authenticate) {
+ request_ = request.Pass();
+ has_retried_authorization_ = false;
+ InitializeUrlFetcher();
+
+ if (!authenticate)
+ url_fetcher_->Start();
+ else if (access_token_.empty())
+ StartTokenFetch(false);
+ else
+ SetOAuth2TokenAndStartRequest();
+}
+
+void PaymentsClient::InitializeUrlFetcher() {
+ url_fetcher_ =
+ net::URLFetcher::Create(0, GetRequestUrl(request_->GetRequestUrlPath()),
+ net::URLFetcher::POST, this);
+
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ url_fetcher_.get(), data_use_measurement::DataUseUserData::AUTOFILL);
+ url_fetcher_->SetRequestContext(context_getter_.get());
+ url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DISABLE_CACHE);
+
+ url_fetcher_->SetUploadData(request_->GetRequestContentType(),
+ request_->GetRequestContent());
+}
+
+void PaymentsClient::CancelRequest() {
+ request_.reset();
+ url_fetcher_.reset();
+ access_token_request_.reset();
+ access_token_.clear();
+ has_retried_authorization_ = false;
+}
+
+void PaymentsClient::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK_EQ(source, url_fetcher_.get());
+
+ // |url_fetcher_|, which is aliased to |source|, might continue to be used in
+ // this method, but should be freed once control leaves the method.
+ scoped_ptr<net::URLFetcher> scoped_url_fetcher(url_fetcher_.Pass());
+ scoped_ptr<base::DictionaryValue> response_dict;
+ int response_code = source->GetResponseCode();
+ std::string data;
+ source->GetResponseAsString(&data);
+ VLOG(2) << "Got data: " << data;
+
+ AutofillClient::PaymentsRpcResult result = AutofillClient::SUCCESS;
+
+ switch (response_code) {
+ // Valid response.
+ case net::HTTP_OK: {
+ std::string error_code;
+ scoped_ptr<base::Value> message_value = base::JSONReader::Read(data);
+ if (message_value.get() &&
+ message_value->IsType(base::Value::TYPE_DICTIONARY)) {
+ response_dict.reset(
+ static_cast<base::DictionaryValue*>(message_value.release()));
+ response_dict->GetString("error.code", &error_code);
+ request_->ParseResponse(response_dict.Pass());
+ }
+
+ if (base::LowerCaseEqualsASCII(error_code, "internal"))
+ result = AutofillClient::TRY_AGAIN_FAILURE;
+ else if (!error_code.empty() || !request_->IsResponseComplete())
+ result = AutofillClient::PERMANENT_FAILURE;
+
+ break;
+ }
+
+ case net::HTTP_UNAUTHORIZED: {
+ if (has_retried_authorization_) {
+ result = AutofillClient::PERMANENT_FAILURE;
+ break;
+ }
+ has_retried_authorization_ = true;
+
+ InitializeUrlFetcher();
+ StartTokenFetch(true);
+ return;
+ }
+
+ // TODO(estade): is this actually how network connectivity issues are
+ // reported?
+ case net::HTTP_REQUEST_TIMEOUT: {
+ result = AutofillClient::NETWORK_ERROR;
+ break;
+ }
+
+ // Handle anything else as a generic (permanent) failure.
+ default: {
+ result = AutofillClient::PERMANENT_FAILURE;
+ break;
+ }
+ }
+
+ if (result != AutofillClient::SUCCESS) {
+ VLOG(1) << "Payments returned error: " << response_code
+ << " with data: " << data;
+ }
+
+ request_->RespondToDelegate(delegate_, result);
+}
+
+void PaymentsClient::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ DCHECK_EQ(request, access_token_request_.get());
+ access_token_ = access_token;
+ if (url_fetcher_)
+ SetOAuth2TokenAndStartRequest();
+
+ access_token_request_.reset();
+}
+
+void PaymentsClient::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ DCHECK_EQ(request, access_token_request_.get());
+ VLOG(1) << "Unhandled OAuth2 error: " << error.ToString();
+ if (url_fetcher_) {
+ url_fetcher_.reset();
+ request_->RespondToDelegate(delegate_, AutofillClient::PERMANENT_FAILURE);
+ }
+ access_token_request_.reset();
+}
+
+void PaymentsClient::StartTokenFetch(bool invalidate_old) {
+ // We're still waiting for the last request to come back.
+ if (!invalidate_old && access_token_request_)
+ return;
+
+ OAuth2TokenService::ScopeSet payments_scopes;
+ payments_scopes.insert(kPaymentsOAuth2Scope);
+ IdentityProvider* identity = delegate_->GetIdentityProvider();
+ if (invalidate_old) {
+ DCHECK(!access_token_.empty());
+ identity->GetTokenService()->InvalidateAccessToken(
+ identity->GetActiveAccountId(), payments_scopes, access_token_);
+ }
+ access_token_.clear();
+ access_token_request_ = identity->GetTokenService()->StartRequest(
+ identity->GetActiveAccountId(), payments_scopes, this);
+}
+
+void PaymentsClient::SetOAuth2TokenAndStartRequest() {
+ url_fetcher_->AddExtraRequestHeader(net::HttpRequestHeaders::kAuthorization +
+ std::string(": Bearer ") + access_token_);
+
+ url_fetcher_->Start();
+}
+
+} // namespace payments
+} // namespace autofill
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h
new file mode 100644
index 0000000..a6a23af
--- /dev/null
+++ b/components/autofill/core/browser/payments/payments_client.h
@@ -0,0 +1,171 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/card_unmask_delegate.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+class IdentityProvider;
+
+namespace net {
+class URLFetcher;
+class URLRequestContextGetter;
+}
+
+namespace autofill {
+
+namespace payments {
+
+class PaymentsRequest;
+
+class PaymentsClientDelegate {
+ public:
+ // The identity provider used to get OAuth2 tokens.
+ virtual IdentityProvider* GetIdentityProvider() = 0;
+
+ // Returns the real PAN retrieved from Payments. |real_pan| will be empty
+ // on failure.
+ virtual void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
+ const std::string& real_pan) = 0;
+
+ // Returns the legal message retrieved from Payments. On failure or not
+ // meeting Payments's conditions for upload, |legal_message| will contain
+ // nullptr.
+ virtual void OnDidGetUploadDetails(
+ AutofillClient::PaymentsRpcResult result,
+ const base::string16& context_token,
+ scoped_ptr<base::DictionaryValue> legal_message) = 0;
+
+ // Returns the result of an upload request.
+ virtual void OnDidUploadCard(AutofillClient::PaymentsRpcResult result) = 0;
+};
+
+// PaymentsClient issues Payments RPCs and manages responses and failure
+// conditions. Only one request may be active at a time. Initiating a new
+// request will cancel a pending request.
+// Tests are located in
+// src/components/autofill/content/browser/wallet/payments_client_unittest.cc.
+class PaymentsClient : public net::URLFetcherDelegate,
+ public OAuth2TokenService::Consumer {
+ public:
+ // A collection of the information required to make a credit card unmask
+ // request.
+ struct UnmaskRequestDetails {
+ UnmaskRequestDetails();
+ ~UnmaskRequestDetails();
+
+ CreditCard card;
+ std::string risk_data;
+ CardUnmaskDelegate::UnmaskResponse user_response;
+ };
+
+ // A collection of the information required to make a credit card upload
+ // request.
+ struct UploadRequestDetails {
+ UploadRequestDetails();
+ ~UploadRequestDetails();
+
+ CreditCard card;
+ base::string16 cvc;
+ base::string16 context_token;
+ std::string risk_data;
+ std::string app_locale;
+ };
+
+ // |context_getter| is reference counted so it has no lifetime or ownership
+ // requirements. |delegate| must outlive |this|. |source_url| is the url
+ // of the merchant page.
+ PaymentsClient(net::URLRequestContextGetter* context_getter,
+ PaymentsClientDelegate* delegate);
+
+ ~PaymentsClient() override;
+
+ // Starts fetching the OAuth2 token in anticipation of future Payments
+ // requests. Called as an optimization, but not strictly necessary. Should
+ // *not* be called in advance of GetUploadDetails or UploadCard because
+ // identifying information should not be sent until the user has explicitly
+ // accepted an upload prompt.
+ void Prepare();
+
+ // The user has attempted to unmask a card with the given cvc.
+ void UnmaskCard(const UnmaskRequestDetails& request_details);
+
+ // Determine if the user meets the Payments service's conditions for upload.
+ // If so, the required legal message for display will be returned via
+ // OnDidGetUploadDetails.
+ virtual void GetUploadDetails(const std::string& app_locale);
+
+ // The user has indicated that they would like to upload a card with the given
+ // cvc. This request will fail server-side if a successful call to
+ // GetUploadDetails has not already been made.
+ virtual void UploadCard(const UploadRequestDetails& details);
+
+ // Cancels and clears the current |request_|.
+ void CancelRequest();
+
+ private:
+ // Initiates a Payments request using the state in |request|. If
+ // |authenticate| is true, ensures that an OAuth token is avialble first.
+ // Takes ownership of |request|.
+ void IssueRequest(scoped_ptr<PaymentsRequest> request, bool authenticate);
+
+ // net::URLFetcherDelegate:
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+ // OAuth2TokenService::Consumer implementation.
+ void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) override;
+ void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) override;
+
+ // Creates |url_fetcher_| based on the current state of |request_|.
+ void InitializeUrlFetcher();
+
+ // Initiates a new OAuth2 token request.
+ void StartTokenFetch(bool invalidate_old);
+
+ // Adds the token to |url_fetcher_| and starts the request.
+ void SetOAuth2TokenAndStartRequest();
+
+ // The context for the request.
+ scoped_refptr<net::URLRequestContextGetter> context_getter_;
+
+ // Observer class that has its various On* methods called based on the results
+ // of a Payments request.
+ PaymentsClientDelegate* const delegate_; // must outlive |this|.
+
+ // The current request.
+ scoped_ptr<PaymentsRequest> request_;
+
+ // The fetcher being used to issue the current request.
+ scoped_ptr<net::URLFetcher> url_fetcher_;
+
+ // The current OAuth2 token request object.
+ scoped_ptr<OAuth2TokenService::Request> access_token_request_;
+
+ // The OAuth2 token, or empty if not fetched.
+ std::string access_token_;
+
+ // True if |request_| has already retried due to a 401 response from the
+ // server.
+ bool has_retried_authorization_;
+
+ base::WeakPtrFactory<PaymentsClient> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentsClient);
+};
+
+} // namespace payments
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
diff --git a/components/autofill/core/browser/payments/payments_request.h b/components/autofill/core/browser/payments/payments_request.h
new file mode 100644
index 0000000..be59661
--- /dev/null
+++ b/components/autofill/core/browser/payments/payments_request.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUEST_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUEST_H_
+
+namespace autofill {
+
+class AutofillClient;
+
+namespace payments {
+
+class PaymentsClientDelegate;
+
+// Interface for the various Payments request types.
+class PaymentsRequest {
+ public:
+ virtual ~PaymentsRequest() {}
+
+ // Returns the URL path for this type of request.
+ virtual std::string GetRequestUrlPath() = 0;
+
+ // Returns the content type that should be used in the HTTP request.
+ virtual std::string GetRequestContentType() = 0;
+
+ // Returns the content that should be provided in the HTTP request.
+ virtual std::string GetRequestContent() = 0;
+
+ // Parses the required elements of the HTTP response.
+ virtual void ParseResponse(scoped_ptr<base::DictionaryValue> response) = 0;
+
+ // Returns true if all of the required elements were successfully retrieved by
+ // a call to ParseResponse.
+ virtual bool IsResponseComplete() = 0;
+
+ // Invokes the appropriate callback in the delegate based on what type of
+ // request this is.
+ virtual void RespondToDelegate(PaymentsClientDelegate* delegate,
+ AutofillClient::PaymentsRpcResult result) = 0;
+};
+
+} // namespace payments
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUEST_H_
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc
index 0b1f279..f6c2278 100644
--- a/components/autofill/core/browser/test_autofill_client.cc
+++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -48,11 +48,20 @@ void TestAutofillClient::ShowUnmaskPrompt(
base::WeakPtr<CardUnmaskDelegate> delegate) {
}
-void TestAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) {
+void TestAutofillClient::OnUnmaskVerificationResult(PaymentsRpcResult result) {}
+
+void TestAutofillClient::ConfirmSaveCreditCardLocally(
+ const base::Closure& callback) {}
+
+void TestAutofillClient::ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) {
+ callback.Run();
}
-void TestAutofillClient::ConfirmSaveCreditCard(
- const base::Closure& save_card_callback) {
+void TestAutofillClient::LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) {
+ callback.Run("some risk data");
}
bool TestAutofillClient::HasCreditCardScanFeature() {
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index bc423d2..11bebc8 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -32,8 +32,13 @@ class TestAutofillClient : public AutofillClient {
void ShowAutofillSettings() override;
void ShowUnmaskPrompt(const CreditCard& card,
base::WeakPtr<CardUnmaskDelegate> delegate) override;
- void OnUnmaskVerificationResult(GetRealPanResult result) override;
- void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
+ void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
+ void ConfirmSaveCreditCardLocally(const base::Closure& callback) override;
+ void ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) override;
+ void LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(const CreditCardScanCallback& callback) override;
void ShowRequestAutocompleteDialog(const FormData& form,
diff --git a/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc b/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
index 22628d9..1ac9687 100644
--- a/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
+++ b/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
@@ -20,19 +20,16 @@
namespace autofill {
CardUnmaskPromptControllerImpl::CardUnmaskPromptControllerImpl(
- const RiskDataCallback& risk_data_callback,
PrefService* pref_service,
bool is_off_the_record)
- : risk_data_callback_(risk_data_callback),
- pref_service_(pref_service),
+ : pref_service_(pref_service),
new_card_link_clicked_(false),
is_off_the_record_(is_off_the_record),
card_unmask_view_(nullptr),
unmasking_result_(AutofillClient::NONE),
unmasking_initial_should_store_pan_(false),
unmasking_number_of_attempts_(0),
- weak_pointer_factory_(this) {
-}
+ weak_pointer_factory_(this) {}
CardUnmaskPromptControllerImpl::~CardUnmaskPromptControllerImpl() {
if (card_unmask_view_)
@@ -49,7 +46,6 @@ void CardUnmaskPromptControllerImpl::ShowPrompt(
new_card_link_clicked_ = false;
shown_timestamp_ = base::Time::Now();
pending_response_ = CardUnmaskDelegate::UnmaskResponse();
- LoadRiskFingerprint();
card_unmask_view_ = card_unmask_view;
card_ = card;
delegate_ = delegate;
@@ -61,7 +57,7 @@ void CardUnmaskPromptControllerImpl::ShowPrompt(
}
bool CardUnmaskPromptControllerImpl::AllowsRetry(
- AutofillClient::GetRealPanResult result) {
+ AutofillClient::PaymentsRpcResult result) {
if (result == AutofillClient::NETWORK_ERROR ||
result == AutofillClient::PERMANENT_FAILURE) {
return false;
@@ -70,7 +66,7 @@ bool CardUnmaskPromptControllerImpl::AllowsRetry(
}
void CardUnmaskPromptControllerImpl::OnVerificationResult(
- AutofillClient::GetRealPanResult result) {
+ AutofillClient::PaymentsRpcResult result) {
if (!card_unmask_view_)
return;
@@ -205,8 +201,7 @@ void CardUnmaskPromptControllerImpl::OnUnmaskResponse(
pending_response_.should_store_pan = false;
}
- if (!pending_response_.risk_data.empty())
- delegate_->OnUnmaskResponse(pending_response_);
+ delegate_->OnUnmaskResponse(pending_response_);
}
void CardUnmaskPromptControllerImpl::NewCardLinkClicked() {
@@ -311,17 +306,4 @@ base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration()
return base::TimeDelta::FromMilliseconds(500);
}
-void CardUnmaskPromptControllerImpl::LoadRiskFingerprint() {
- risk_data_callback_.Run(
- base::Bind(&CardUnmaskPromptControllerImpl::OnDidLoadRiskFingerprint,
- weak_pointer_factory_.GetWeakPtr()));
-}
-
-void CardUnmaskPromptControllerImpl::OnDidLoadRiskFingerprint(
- const std::string& risk_data) {
- pending_response_.risk_data = risk_data;
- if (!pending_response_.cvc.empty())
- delegate_->OnUnmaskResponse(pending_response_);
-}
-
} // namespace autofill
diff --git a/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h b/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
index 59ac7b7..df2b8c3 100644
--- a/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
+++ b/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
@@ -22,11 +22,7 @@ class CardUnmaskPromptView;
class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
public:
- typedef base::Callback<void(const base::Callback<void(const std::string&)>&)>
- RiskDataCallback;
-
CardUnmaskPromptControllerImpl(
- const RiskDataCallback& risk_data_callback,
PrefService* pref_service,
bool is_off_the_record);
virtual ~CardUnmaskPromptControllerImpl();
@@ -36,7 +32,7 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
const CreditCard& card,
base::WeakPtr<CardUnmaskDelegate> delegate);
// The CVC the user entered went through validation.
- void OnVerificationResult(AutofillClient::GetRealPanResult result);
+ void OnVerificationResult(AutofillClient::PaymentsRpcResult result);
// CardUnmaskPromptController implementation.
void OnUnmaskDialogClosed() override;
@@ -57,21 +53,14 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
base::TimeDelta GetSuccessMessageDuration() const override;
protected:
- // Virtual so tests can suppress it.
- virtual void LoadRiskFingerprint();
-
- // Protected so tests can call it.
- void OnDidLoadRiskFingerprint(const std::string& risk_data);
-
// Exposed for testing.
CardUnmaskPromptView* view() { return card_unmask_view_; }
private:
- bool AllowsRetry(AutofillClient::GetRealPanResult result);
+ bool AllowsRetry(AutofillClient::PaymentsRpcResult result);
void LogOnCloseEvents();
AutofillMetrics::UnmaskPromptEvent GetCloseReasonEvent();
- RiskDataCallback risk_data_callback_;
PrefService* pref_service_;
bool new_card_link_clicked_;
bool is_off_the_record_;
@@ -79,7 +68,7 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
base::WeakPtr<CardUnmaskDelegate> delegate_;
CardUnmaskPromptView* card_unmask_view_;
- AutofillClient::GetRealPanResult unmasking_result_;
+ AutofillClient::PaymentsRpcResult unmasking_result_;
bool unmasking_initial_should_store_pan_;
int unmasking_number_of_attempts_;
base::Time shown_timestamp_;
diff --git a/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc b/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
index f45e79e..e0ff1ea 100644
--- a/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
+++ b/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
@@ -54,23 +54,14 @@ class TestCardUnmaskPromptView : public CardUnmaskPromptView {
bool allow_retry) override {}
};
-void TestGetRiskData(const base::Callback<void(const std::string&)>& callback) {
- callback.Run("some risk data");
-}
-
class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
public:
explicit TestCardUnmaskPromptController(
TestingPrefServiceSimple* pref_service)
- : CardUnmaskPromptControllerImpl(
- base::Bind(&TestGetRiskData), pref_service, false),
+ : CardUnmaskPromptControllerImpl(pref_service, false),
can_store_locally_(true),
weak_factory_(this) {}
- void LoadRiskFingerprint() override {
- OnDidLoadRiskFingerprint("risk aversion");
- }
-
bool CanStoreLocally() const override { return can_store_locally_; }
void set_can_store_locally(bool can) { can_store_locally_ = can; }
@@ -394,9 +385,9 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogRealPanResultSuccess) {
base::HistogramTester histogram_tester;
controller_->OnVerificationResult(AutofillClient::SUCCESS);
- histogram_tester.ExpectBucketCount(
- "Autofill.UnmaskPrompt.GetRealPanResult",
- AutofillMetrics::GET_REAL_PAN_RESULT_SUCCESS, 1);
+ histogram_tester.ExpectBucketCount("Autofill.UnmaskPrompt.GetRealPanResult",
+ AutofillMetrics::PAYMENTS_RESULT_SUCCESS,
+ 1);
}
TEST_F(CardUnmaskPromptControllerImplTest, LogRealPanTryAgainFailure) {
@@ -407,7 +398,7 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogRealPanTryAgainFailure) {
histogram_tester.ExpectBucketCount(
"Autofill.UnmaskPrompt.GetRealPanResult",
- AutofillMetrics::GET_REAL_PAN_RESULT_TRY_AGAIN_FAILURE, 1);
+ AutofillMetrics::PAYMENTS_RESULT_TRY_AGAIN_FAILURE, 1);
}
TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskingDurationResultSuccess) {
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
deleted file mode 100644
index d9055b5..0000000
--- a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/wallet/real_pan_wallet_client.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/common/autofill_switches.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "google_apis/gaia/identity_provider.h"
-#include "net/base/escape.h"
-#include "net/base/load_flags.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
-
-namespace autofill {
-namespace wallet {
-
-namespace {
-
-const char kUnmaskCardRequestFormat[] =
- "requestContentType=application/json; charset=utf-8&request=%s"
- "&s7e_13_cvc=%s";
-
-const char kUnmaskCardRequestHost[] = "https://wallet.google.com";
-const char kUnmaskCardRequestHostSandbox[] = "https://sandbox.google.com";
-const char kUnmaskCardRequestPath[] =
- "payments/apis-secure/creditcardservice/getrealpan?s7e_suffix=chromewallet";
-
-const char kTokenServiceConsumerId[] = "real_pan_wallet_client";
-const char kWalletOAuth2Scope[] =
- "https://www.googleapis.com/auth/wallet.chrome";
-
-// This is mostly copied from wallet_service_url.cc, which is currently in
-// content/, hence inaccessible from here.
-bool IsWalletProductionEnabled() {
- // If the command line flag exists, it takes precedence.
- const base::CommandLine* command_line =
- base::CommandLine::ForCurrentProcess();
- std::string sandbox_enabled(
- command_line->GetSwitchValueASCII(switches::kWalletServiceUseSandbox));
- if (!sandbox_enabled.empty())
- return sandbox_enabled != "1";
-
-#if defined(ENABLE_PROD_WALLET_SERVICE)
- return true;
-#else
- return false;
-#endif
-}
-
-GURL GetUnmaskCardRequestUrl() {
- if (base::CommandLine::ForCurrentProcess()->HasSwitch("sync-url")) {
- if (IsWalletProductionEnabled()) {
- LOG(ERROR) << "You are using production Wallet but you specified a "
- "--sync-url. You likely want to disable the sync sandbox "
- "or switch to sandbox Wallet. Both are controlled in "
- "about:flags.";
- }
- } else if (!IsWalletProductionEnabled()) {
- LOG(ERROR) << "You are using sandbox Wallet but you didn't specify a "
- "--sync-url. You likely want to enable the sync sandbox "
- "or switch to production Wallet. Both are controlled in "
- "about:flags.";
- }
-
- GURL base(IsWalletProductionEnabled() ? kUnmaskCardRequestHost
- : kUnmaskCardRequestHostSandbox);
- return base.Resolve(kUnmaskCardRequestPath);
-}
-
-} // namespace
-
-RealPanWalletClient::RealPanWalletClient(
- net::URLRequestContextGetter* context_getter,
- Delegate* delegate)
- : OAuth2TokenService::Consumer(kTokenServiceConsumerId),
- context_getter_(context_getter),
- delegate_(delegate),
- has_retried_authorization_(false),
- weak_ptr_factory_(this) {
- DCHECK(delegate);
-}
-
-RealPanWalletClient::~RealPanWalletClient() {
-}
-
-void RealPanWalletClient::Prepare() {
- if (access_token_.empty())
- StartTokenFetch(false);
-}
-
-void RealPanWalletClient::UnmaskCard(
- const CreditCard& card,
- const CardUnmaskDelegate::UnmaskResponse& response) {
- DCHECK_EQ(CreditCard::MASKED_SERVER_CARD, card.record_type());
- card_ = card;
- response_ = response;
- has_retried_authorization_ = false;
-
- CreateRequest();
- if (access_token_.empty())
- StartTokenFetch(false);
- else
- SetOAuth2TokenAndStartRequest();
-}
-
-void RealPanWalletClient::CancelRequest() {
- request_.reset();
-}
-
-void RealPanWalletClient::OnURLFetchComplete(const net::URLFetcher* source) {
- DCHECK_EQ(source, request_.get());
-
- // |request_|, which is aliased to |source|, might continue to be used in this
- // |method, but should be freed once control leaves the method.
- scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
- scoped_ptr<base::DictionaryValue> response_dict;
- int response_code = source->GetResponseCode();
- std::string data;
- source->GetResponseAsString(&data);
- VLOG(2) << "Got data: " << data;
-
- std::string real_pan;
- AutofillClient::GetRealPanResult result = AutofillClient::SUCCESS;
-
- switch (response_code) {
- // Valid response.
- case net::HTTP_OK: {
- std::string error_code;
- scoped_ptr<base::Value> message_value = base::JSONReader::Read(data);
- if (message_value.get() &&
- message_value->IsType(base::Value::TYPE_DICTIONARY)) {
- response_dict.reset(
- static_cast<base::DictionaryValue*>(message_value.release()));
- response_dict->GetString("pan", &real_pan);
- response_dict->GetString("error.code", &error_code);
- }
-
- if (base::LowerCaseEqualsASCII(error_code, "internal"))
- result = AutofillClient::TRY_AGAIN_FAILURE;
- else if (real_pan.empty() || !error_code.empty())
- result = AutofillClient::PERMANENT_FAILURE;
-
- break;
- }
-
- case net::HTTP_UNAUTHORIZED: {
- if (has_retried_authorization_) {
- result = AutofillClient::PERMANENT_FAILURE;
- break;
- }
- has_retried_authorization_ = true;
-
- CreateRequest();
- StartTokenFetch(true);
- return;
- }
-
- // TODO(estade): is this actually how network connectivity issues are
- // reported?
- case net::HTTP_REQUEST_TIMEOUT: {
- result = AutofillClient::NETWORK_ERROR;
- break;
- }
-
- // Handle anything else as a generic (permanent) failure.
- default: {
- result = AutofillClient::PERMANENT_FAILURE;
- break;
- }
- }
-
- if (real_pan.empty()) {
- VLOG(1) << "Wallet returned error: " << response_code
- << " with data: " << data;
- }
-
- DCHECK_EQ(result != AutofillClient::SUCCESS, real_pan.empty());
- delegate_->OnDidGetRealPan(result, real_pan);
-}
-
-void RealPanWalletClient::OnGetTokenSuccess(
- const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) {
- DCHECK_EQ(request, access_token_request_.get());
- access_token_ = access_token;
- if (request_)
- SetOAuth2TokenAndStartRequest();
-
- access_token_request_.reset();
-}
-
-void RealPanWalletClient::OnGetTokenFailure(
- const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) {
- DCHECK_EQ(request, access_token_request_.get());
- VLOG(1) << "Unhandled OAuth2 error: " << error.ToString();
- if (request_) {
- request_.reset();
- delegate_->OnDidGetRealPan(AutofillClient::PERMANENT_FAILURE,
- std::string());
- }
- access_token_request_.reset();
-}
-
-void RealPanWalletClient::CreateRequest() {
- request_ = net::URLFetcher::Create(0, GetUnmaskCardRequestUrl(),
- net::URLFetcher::POST, this);
- data_use_measurement::DataUseUserData::AttachToFetcher(
- request_.get(), data_use_measurement::DataUseUserData::AUTOFILL);
- request_->SetRequestContext(context_getter_.get());
- request_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
- net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DISABLE_CACHE);
-
- base::DictionaryValue request_dict;
- request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc");
- request_dict.SetString("credit_card_id", card_.server_id());
- scoped_ptr<base::DictionaryValue> risk_data(new base::DictionaryValue());
- if (response_.providing_risk_advisory_data) {
- risk_data->SetString("message_type", "RISK_ADVISORY_DATA");
- risk_data->SetString("encoding_type", "BASE_64_URL");
- } else {
- risk_data->SetString("message_type", "BROWSER_NATIVE_FINGERPRINTING");
- risk_data->SetString("encoding_type", "BASE_64");
- }
- risk_data->SetString("value", response_.risk_data);
- request_dict.Set("risk_data_encoded", risk_data.Pass());
- request_dict.Set("context", make_scoped_ptr(new base::DictionaryValue()));
-
- int value = 0;
- if (base::StringToInt(response_.exp_month, &value))
- request_dict.SetInteger("expiration_month", value);
- if (base::StringToInt(response_.exp_year, &value))
- request_dict.SetInteger("expiration_year", value);
-
- std::string json_request;
- base::JSONWriter::Write(request_dict, &json_request);
- std::string post_body =
- base::StringPrintf(kUnmaskCardRequestFormat,
- net::EscapeUrlEncodedData(json_request, true).c_str(),
- net::EscapeUrlEncodedData(
- base::UTF16ToASCII(response_.cvc), true).c_str());
- VLOG(3) << "getrealpan request body: " << post_body;
- request_->SetUploadData("application/x-www-form-urlencoded", post_body);
-}
-
-void RealPanWalletClient::StartTokenFetch(bool invalidate_old) {
- // We're still waiting for the last request to come back.
- if (!invalidate_old && access_token_request_)
- return;
-
- OAuth2TokenService::ScopeSet wallet_scopes;
- wallet_scopes.insert(kWalletOAuth2Scope);
- IdentityProvider* identity = delegate_->GetIdentityProvider();
- if (invalidate_old) {
- DCHECK(!access_token_.empty());
- identity->GetTokenService()->InvalidateAccessToken(
- identity->GetActiveAccountId(), wallet_scopes, access_token_);
- }
- access_token_.clear();
- access_token_request_ = identity->GetTokenService()->StartRequest(
- identity->GetActiveAccountId(), wallet_scopes, this);
-}
-
-void RealPanWalletClient::SetOAuth2TokenAndStartRequest() {
- request_->AddExtraRequestHeader(net::HttpRequestHeaders::kAuthorization +
- std::string(": Bearer ") + access_token_);
-
- request_->Start();
-}
-
-} // namespace wallet
-} // namespace autofill
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.h b/components/autofill/core/browser/wallet/real_pan_wallet_client.h
deleted file mode 100644
index b656d4a..0000000
--- a/components/autofill/core/browser/wallet/real_pan_wallet_client.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WALLET_REAL_PAN_WALLET_CLIENT_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_WALLET_REAL_PAN_WALLET_CLIENT_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/card_unmask_delegate.h"
-#include "components/autofill/core/browser/credit_card.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-#include "net/url_request/url_fetcher_delegate.h"
-
-class IdentityProvider;
-
-namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
-}
-
-namespace autofill {
-
-namespace wallet {
-
-// RealPanWalletClient is modelled on WalletClient. Whereas the latter is used
-// for requestAutocomplete-related requests, RealPanWalletClient is used to
-// import user data from Wallet for normal web Autofill.
-// Tests: See content/browser/wallet/real_pan_wallet_client_unittest.cc
-class RealPanWalletClient : public net::URLFetcherDelegate,
- public OAuth2TokenService::Consumer {
- public:
- class Delegate {
- public:
- // The identity provider used to get OAuth2 tokens.
- virtual IdentityProvider* GetIdentityProvider() = 0;
-
- // Returns the real PAN retrieved from Wallet. |real_pan| will be empty
- // on failure.
- virtual void OnDidGetRealPan(AutofillClient::GetRealPanResult result,
- const std::string& real_pan) = 0;
- };
-
- // |context_getter| is reference counted so it has no lifetime or ownership
- // requirements. |delegate| must outlive |this|. |source_url| is the url
- // of the merchant page.
- RealPanWalletClient(net::URLRequestContextGetter* context_getter,
- Delegate* delegate);
-
- ~RealPanWalletClient() override;
-
- // Starts fetching the OAuth2 token in anticipation of future wallet requests.
- // Called as an optimization, but not strictly necessary.
- void Prepare();
-
- // The user has attempted to unmask a card with the given cvc.
- void UnmaskCard(const CreditCard& card,
- const CardUnmaskDelegate::UnmaskResponse& response);
-
- // Cancels and clears the current |request_|.
- void CancelRequest();
-
- private:
- // net::URLFetcherDelegate:
- void OnURLFetchComplete(const net::URLFetcher* source) override;
-
- // OAuth2TokenService::Consumer implementation.
- void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) override;
- void OnGetTokenFailure(const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) override;
-
- // Creates |request_| from |card_| and |response_|.
- void CreateRequest();
-
- // Initiates a new OAuth2 token request.
- void StartTokenFetch(bool invalidate_old);
-
- // Adds the token to |request_| and starts the request.
- void SetOAuth2TokenAndStartRequest();
-
- // The context for the request.
- scoped_refptr<net::URLRequestContextGetter> context_getter_;
-
- // Observer class that has its various On* methods called based on the results
- // of a request to Online Wallet.
- Delegate* const delegate_; // must outlive |this|.
-
- // The card and response for the latest unmask request.
- CreditCard card_;
- CardUnmaskDelegate::UnmaskResponse response_;
-
- // The current Wallet request object.
- scoped_ptr<net::URLFetcher> request_;
-
- // The current OAuth2 token request object;
- scoped_ptr<OAuth2TokenService::Request> access_token_request_;
-
- // The OAuth2 token, or empty if not fetched.
- std::string access_token_;
-
- // True if |this| has already retried due to a 401 response from the server.
- bool has_retried_authorization_;
-
- base::WeakPtrFactory<RealPanWalletClient> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(RealPanWalletClient);
-};
-
-} // namespace wallet
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WALLET_REAL_PAN_WALLET_CLIENT_H_
diff --git a/components/autofill/core/common/autofill_switches.cc b/components/autofill/core/common/autofill_switches.cc
index 79e8db4..63edd24 100644
--- a/components/autofill/core/common/autofill_switches.cc
+++ b/components/autofill/core/common/autofill_switches.cc
@@ -24,6 +24,10 @@ const char kDisableFullFormAutofillIOS[] = "disable-full-form-autofill-ios";
const char kDisableOfferStoreUnmaskedWalletCards[] =
"disable-offer-store-unmasked-wallet-cards";
+// Disables offering to upload credit cards.
+const char kDisableOfferUploadCreditCards[] =
+ "disable-offer-upload-credit-cards";
+
// Disables password generation when we detect that the user is going through
// account creation.
const char kDisablePasswordGeneration[] = "disable-password-generation";
@@ -53,6 +57,9 @@ const char kEnableFullFormAutofillIOS[] = "enable-full-form-autofill-ios";
const char kEnableOfferStoreUnmaskedWalletCards[] =
"enable-offer-store-unmasked-wallet-cards";
+// Enables offering to upload credit cards.
+const char kEnableOfferUploadCreditCards[] = "enable-offer-upload-credit-cards";
+
// Enables password generation when we detect that the user is going through
// account creation.
const char kEnablePasswordGeneration[] = "enable-password-generation";
diff --git a/components/autofill/core/common/autofill_switches.h b/components/autofill/core/common/autofill_switches.h
index b4e7a35..1c34827 100644
--- a/components/autofill/core/common/autofill_switches.h
+++ b/components/autofill/core/common/autofill_switches.h
@@ -16,6 +16,7 @@ extern const char kDisableCreditCardScan[];
extern const char kDisableFillOnAccountSelect[];
extern const char kDisableFullFormAutofillIOS[];
extern const char kDisableOfferStoreUnmaskedWalletCards[];
+extern const char kDisableOfferUploadCreditCards[];
extern const char kDisablePasswordGeneration[];
extern const char kDisableSingleClickAutofill[];
extern const char kEnableCreditCardScan[];
@@ -23,6 +24,7 @@ extern const char kEnableFillOnAccountSelect[];
extern const char kEnableFillOnAccountSelectNoHighlighting[];
extern const char kEnableFullFormAutofillIOS[];
extern const char kEnableOfferStoreUnmaskedWalletCards[];
+extern const char kEnableOfferUploadCreditCards[];
extern const char kEnablePasswordGeneration[];
extern const char kEnableSingleClickAutofill[];
extern const char kEnableSuggestionsWithSubstringMatch[];
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index f9975f0..bb5cb2c 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -19,8 +19,8 @@
'autofill/content/browser/content_autofill_driver_unittest.cc',
'autofill/content/browser/request_autocomplete_manager_unittest.cc',
'autofill/content/browser/wallet/full_wallet_unittest.cc',
- 'autofill/content/browser/wallet/real_pan_wallet_client_unittest.cc',
'autofill/content/browser/wallet/wallet_address_unittest.cc',
+ 'autofill/content/browser/wallet/payments_client_unittest.cc',
'autofill/content/browser/wallet/wallet_service_url_unittest.cc',
'autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc',
'autofill/core/browser/address_field_unittest.cc',
diff --git a/ios/chrome/browser/ui/autofill/autofill_client_ios.h b/ios/chrome/browser/ui/autofill/autofill_client_ios.h
index 856bc24..34d51a11 100644
--- a/ios/chrome/browser/ui/autofill/autofill_client_ios.h
+++ b/ios/chrome/browser/ui/autofill/autofill_client_ios.h
@@ -53,8 +53,13 @@ class AutofillClientIOS : public AutofillClient {
void ShowAutofillSettings() override;
void ShowUnmaskPrompt(const CreditCard& card,
base::WeakPtr<CardUnmaskDelegate> delegate) override;
- void OnUnmaskVerificationResult(GetRealPanResult result) override;
- void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
+ void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
+ void ConfirmSaveCreditCardLocally(const base::Closure& callback) override;
+ void ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) override;
+ void LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(const CreditCardScanCallback& callback) override;
void ShowRequestAutocompleteDialog(
diff --git a/ios/chrome/browser/ui/autofill/autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/autofill_client_ios.mm
index 7f8afc5..1aefa98 100644
--- a/ios/chrome/browser/ui/autofill/autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/autofill_client_ios.mm
@@ -21,11 +21,6 @@
namespace autofill {
-void GetRiskDataWithCallback(
- const base::Callback<void(const std::string&)>& callback) {
- callback.Run(ios::GetChromeBrowserProvider()->GetRiskData());
-}
-
AutofillClientIOS::AutofillClientIOS(
ios::ChromeBrowserState* browser_state,
infobars::InfoBarManager* infobar_manager,
@@ -37,10 +32,8 @@ AutofillClientIOS::AutofillClientIOS(
bridge_(bridge),
password_generation_manager_(password_generation_manager),
identity_provider_(identity_provider.Pass()),
- unmask_controller_(base::Bind(&GetRiskDataWithCallback),
- browser_state->GetPrefs(),
- browser_state->IsOffTheRecord()) {
-}
+ unmask_controller_(browser_state->GetPrefs(),
+ browser_state->IsOffTheRecord()) {}
AutofillClientIOS::~AutofillClientIOS() {
HideAutofillPopup();
@@ -79,18 +72,29 @@ void AutofillClientIOS::ShowUnmaskPrompt(
delegate);
}
-void AutofillClientIOS::OnUnmaskVerificationResult(GetRealPanResult result) {
+void AutofillClientIOS::OnUnmaskVerificationResult(PaymentsRpcResult result) {
unmask_controller_.OnVerificationResult(result);
}
-void AutofillClientIOS::ConfirmSaveCreditCard(
- const base::Closure& save_card_callback) {
+void AutofillClientIOS::ConfirmSaveCreditCardLocally(
+ const base::Closure& callback) {
// This method is invoked synchronously from
// AutofillManager::OnFormSubmitted(); at the time of detecting that a form
// was submitted, the WebContents is guaranteed to be live. Since the
// InfoBarService is a WebContentsUserData, it must also be alive at this
// time.
- AutofillCCInfoBarDelegate::Create(infobar_manager_, this, save_card_callback);
+ AutofillCCInfoBarDelegate::Create(infobar_manager_, this, callback);
+}
+
+void AutofillClientIOS::ConfirmSaveCreditCardToCloud(
+ const base::Closure& callback,
+ scoped_ptr<base::DictionaryValue> legal_message) {
+ NOTIMPLEMENTED();
+}
+
+void AutofillClientIOS::LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) {
+ callback.Run(ios::GetChromeBrowserProvider()->GetRiskData());
}
bool AutofillClientIOS::HasCreditCardScanFeature() {