Making the encryption/escrow process required to get a FullWallet or save an instrument opaque to users of WalletClient.
Currently users on WalletClient need to do escrow and encryption themselves
before calling the methods they are actually interested in. This CL hides
those implementation details.
BUG=174991,169595
Review URL: https://chromiumcodereview.appspot.com/12211074
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@183586 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/autofill/wallet/cart.cc b/chrome/browser/autofill/wallet/cart.cc
index 25db991..bca2e35 100644
--- a/chrome/browser/autofill/wallet/cart.cc
+++ b/chrome/browser/autofill/wallet/cart.cc
@@ -6,6 +6,7 @@
#include "base/values.h"
+namespace autofill {
namespace wallet {
Cart::Cart(const std::string& total_price, const std::string& currency_code)
@@ -21,4 +22,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/cart.h b/chrome/browser/autofill/wallet/cart.h
index 620478a..e8e41128 100644
--- a/chrome/browser/autofill/wallet/cart.h
+++ b/chrome/browser/autofill/wallet/cart.h
@@ -14,6 +14,7 @@
class DictionaryValue;
}
+namespace autofill {
namespace wallet {
// Container object for purchase data provided by the browser. The enclosed data
@@ -42,6 +43,6 @@
};
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_CART_H_
-
diff --git a/chrome/browser/autofill/wallet/cart_unittest.cc b/chrome/browser/autofill/wallet/cart_unittest.cc
index a094913e..c53b5f4 100644
--- a/chrome/browser/autofill/wallet/cart_unittest.cc
+++ b/chrome/browser/autofill/wallet/cart_unittest.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/autofill/wallet/cart.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace autofill {
namespace wallet {
TEST(Cart, ToDictionary) {
@@ -17,4 +18,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/encryption_escrow_client.cc b/chrome/browser/autofill/wallet/encryption_escrow_client.cc
new file mode 100644
index 0000000..8144bec
--- /dev/null
+++ b/chrome/browser/autofill/wallet/encryption_escrow_client.cc
@@ -0,0 +1,164 @@
+// Copyright 2013 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 "chrome/browser/autofill/wallet/encryption_escrow_client.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/wallet/encryption_escrow_client_observer.h"
+#include "chrome/browser/autofill/wallet/instrument.h"
+#include "chrome/browser/autofill/wallet/wallet_service_url.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/escape.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 {
+
+const char kEncryptOtpBodyFormat[] = "cvv=%s:%s";
+const char kEscrowSensitiveInformationFormat[] = "gid=%s&cardNumber=%s&cvv=%s";
+const char kApplicationMimeType[] = "application/x-www-form-urlencoded";
+
+// The maximum number of bits in the one time pad that the server is willing to
+// accept.
+const size_t kMaxBits = 56;
+
+// The minimum number of bits in the one time pad that the server is willing to
+// accept.
+const size_t kMinBits = 40;
+
+} // anonymous namespace
+
+namespace autofill {
+namespace wallet {
+
+EncryptionEscrowClient::EncryptionEscrowClient(
+ net::URLRequestContextGetter* context_getter)
+ : context_getter_(context_getter),
+ request_type_(NO_PENDING_REQUEST) {
+ DCHECK(context_getter);
+}
+
+EncryptionEscrowClient::~EncryptionEscrowClient() {}
+
+void EncryptionEscrowClient::EncryptOneTimePad(
+ const std::vector<uint8>& one_time_pad,
+ base::WeakPtr<EncryptionEscrowClientObserver> observer) {
+ DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
+ size_t num_bits = one_time_pad.size() * 8;
+ DCHECK_LE(num_bits, kMaxBits);
+ DCHECK_GE(num_bits, kMinBits);
+
+ request_type_ = ENCRYPT_ONE_TIME_PAD;
+
+ std::string post_body = StringPrintf(
+ kEncryptOtpBodyFormat,
+ base::HexEncode(&num_bits, 1).c_str(),
+ base::HexEncode(&(one_time_pad[0]), one_time_pad.size()).c_str());
+
+ MakeRequest(GetEncryptionUrl(), post_body, observer);
+}
+
+void EncryptionEscrowClient::EscrowSensitiveInformation(
+ const Instrument& new_instrument,
+ const std::string& obfuscated_gaia_id,
+ base::WeakPtr<EncryptionEscrowClientObserver> observer) {
+ DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
+ request_type_ = ESCROW_SENSITIVE_INFORMATION;
+
+ const std::string& primary_account_number =
+ net::EscapeUrlEncodedData(
+ UTF16ToUTF8(new_instrument.primary_account_number()), true);
+ const std::string& card_verification_number =
+ net::EscapeUrlEncodedData(
+ UTF16ToUTF8(new_instrument.card_verification_number()), true);
+
+ std::string post_body = StringPrintf(
+ kEscrowSensitiveInformationFormat,
+ obfuscated_gaia_id.c_str(),
+ primary_account_number.c_str(),
+ card_verification_number.c_str());
+
+ MakeRequest(GetEscrowUrl(), post_body, observer);
+}
+
+void EncryptionEscrowClient::MakeRequest(
+ const GURL& url,
+ const std::string& post_body,
+ base::WeakPtr<EncryptionEscrowClientObserver> observer) {
+ DCHECK(!request_.get());
+ DCHECK(observer);
+
+ observer_ = observer;
+
+ request_.reset(net::URLFetcher::Create(
+ 1, url, net::URLFetcher::POST, this));
+ request_->SetRequestContext(context_getter_);
+ DVLOG(1) << "url=" << url << ", post_body=" << post_body;
+ request_->SetUploadData(kApplicationMimeType, post_body);
+ request_->Start();
+}
+
+// TODO(ahutter): Add manual retry logic if it's necessary.
+void EncryptionEscrowClient::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+ scoped_ptr<net::URLFetcher> old_request = request_.Pass();
+ DCHECK_EQ(source, old_request.get());
+
+ DVLOG(1) << "Got response from " << source->GetOriginalURL();
+
+ RequestType type = request_type_;
+ request_type_ = NO_PENDING_REQUEST;
+
+ std::string data;
+ source->GetResponseAsString(&data);
+ DVLOG(1) << "Response body: " << data;
+
+ if (source->GetResponseCode() != net::HTTP_OK) {
+ observer_->OnNetworkError(source->GetResponseCode());
+ return;
+ }
+
+ if (data.empty()) {
+ HandleMalformedResponse(old_request.get());
+ return;
+ }
+
+ switch (type) {
+ case ENCRYPT_ONE_TIME_PAD: {
+ std::vector<std::string> splits;
+ // The response from the server should be formatted as
+ // "<session material>|<encrypted one time pad>".
+ base::SplitString(data, '|', &splits);
+ if (splits.size() == 2) {
+ if (observer_)
+ observer_->OnDidEncryptOneTimePad(splits[1], splits[0]);
+ } else {
+ HandleMalformedResponse(old_request.get());
+ }
+ break;
+ }
+ case ESCROW_SENSITIVE_INFORMATION:
+ if (observer_)
+ observer_->OnDidEscrowSensitiveInformation(data);
+ break;
+ case NO_PENDING_REQUEST:
+ NOTREACHED();
+ }
+}
+
+void EncryptionEscrowClient::HandleMalformedResponse(net::URLFetcher* request) {
+ // Called to inform exponential backoff logic of the error.
+ request->ReceivedContentWasMalformed();
+ if (observer_)
+ observer_->OnMalformedResponse();
+}
+
+} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/encryption_escrow_client.h b/chrome/browser/autofill/wallet/encryption_escrow_client.h
new file mode 100644
index 0000000..bfabfb7
--- /dev/null
+++ b/chrome/browser/autofill/wallet/encryption_escrow_client.h
@@ -0,0 +1,91 @@
+// Copyright 2013 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 CHROME_BROWSER_AUTOFILL_WALLET_ENCRYPTION_ESCROW_CLIENT_H_
+#define CHROME_BROWSER_AUTOFILL_WALLET_ENCRYPTION_ESCROW_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+class GURL;
+
+namespace net {
+class URLFetcher;
+class URLRequestContextGetter;
+}
+
+namespace autofill {
+namespace wallet {
+
+class EncryptionEscrowClientObserver;
+class Instrument;
+
+// EncrytionEscrowClient is responsible for making calls to the Online Wallet
+// encryption and escrow backend.
+class EncryptionEscrowClient : public net::URLFetcherDelegate {
+ public:
+ explicit EncryptionEscrowClient(net::URLRequestContextGetter* context_getter);
+ virtual ~EncryptionEscrowClient();
+
+ // Sends |one_time_pad|, a vector of cryptographically secure random bytes, to
+ // Online Wallet to be encrypted. These bytes must be generated using
+ // crypto/random.h. |observer| is notified when the request is complete.
+ void EncryptOneTimePad(
+ const std::vector<uint8>& one_time_pad,
+ base::WeakPtr<EncryptionEscrowClientObserver> observer);
+
+ // Escrows the primary account number and card verfication number of
+ // |new_instrument| with Online Wallet. The escrow is keyed off of
+ // |obfuscated_gaia_id|. |observer| is notified when the request is complete.
+ void EscrowSensitiveInformation(
+ const Instrument& new_instrument,
+ const std::string& obfuscated_gaia_id,
+ base::WeakPtr<EncryptionEscrowClientObserver> observer);
+
+ private:
+ enum RequestType {
+ NO_PENDING_REQUEST,
+ ENCRYPT_ONE_TIME_PAD,
+ ESCROW_SENSITIVE_INFORMATION,
+ };
+
+ // Posts |post_body| to |url|. When the request is complete, the |observer|
+ // is notified of the result.
+ void MakeRequest(
+ const GURL& url,
+ const std::string& post_body,
+ base::WeakPtr<EncryptionEscrowClientObserver> observer);
+
+ // Performs bookkeeping tasks for any invalid requests.
+ void HandleMalformedResponse(net::URLFetcher* request);
+
+ // net::URLFetcherDelegate:
+ virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+ // The context for the request. Ensures the gdToken cookie is set as a header
+ // in the requests to Online Wallet if it is present.
+ 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.
+ base::WeakPtr<EncryptionEscrowClientObserver> observer_;
+
+ // The current request object.
+ scoped_ptr<net::URLFetcher> request_;
+
+ // The type of the current request. Must be NO_PENDING_REQUEST for a request
+ // to be initiated as only one request may be running at a given time.
+ RequestType request_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(EncryptionEscrowClient);
+};
+
+} // namespace wallet
+} // namespace autofill
+
+#endif // CHROME_BROWSER_AUTOFILL_WALLET_ENCRYPTION_ESCROW_CLIENT_H_
diff --git a/chrome/browser/autofill/wallet/encryption_escrow_client_observer.h b/chrome/browser/autofill/wallet/encryption_escrow_client_observer.h
new file mode 100644
index 0000000..35c674b
--- /dev/null
+++ b/chrome/browser/autofill/wallet/encryption_escrow_client_observer.h
@@ -0,0 +1,44 @@
+// Copyright 2013 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 CHROME_BROWSER_AUTOFILL_WALLET_ENCRYPTION_ESCROW_CLIENT_OBSERVER_H_
+#define CHROME_BROWSER_AUTOFILL_WALLET_ENCRYPTION_ESCROW_CLIENT_OBSERVER_H_
+
+#include <string>
+
+namespace autofill {
+namespace wallet {
+
+// EncryptionEscrowClientObserver is to be implemented by any classes making
+// calls with EncryptionEscrowClient. The appropriate callback method will be
+// called on EncryptionEscrowClientObserver with the response from the Online
+// Wallet encryption and escrow backend.
+class EncryptionEscrowClientObserver {
+ public:
+ // Called when an EncryptOneTimePad request finishes successfully.
+ // |encrypted_one_time_pad| and |session_material| must be used when getting a
+ // FullWallet.
+ virtual void OnDidEncryptOneTimePad(const std::string& encrypted_one_time_pad,
+ const std::string& session_material) = 0;
+
+ // Called when an EscrowSensitiveInformation request finishes successfully.
+ // |escrow_handle| must be used when saving a new instrument.
+ virtual void OnDidEscrowSensitiveInformation(
+ const std::string& escrow_handle) = 0;
+
+ // Called when a request fails due to a network error or if the response was
+ // invalid.
+ virtual void OnNetworkError(int response_code) = 0;
+
+ // Called when a request fails due to a malformed response.
+ virtual void OnMalformedResponse() = 0;
+
+ protected:
+ virtual ~EncryptionEscrowClientObserver() {}
+};
+
+} // namespace wallet
+} // namespace autofill
+
+#endif // CHROME_BROWSER_AUTOFILL_WALLET_ENCRYPTION_ESCROW_CLIENT_OBSERVER_H_
diff --git a/chrome/browser/autofill/wallet/encryption_escrow_client_unittest.cc b/chrome/browser/autofill/wallet/encryption_escrow_client_unittest.cc
new file mode 100644
index 0000000..d62b81e
--- /dev/null
+++ b/chrome/browser/autofill/wallet/encryption_escrow_client_unittest.cc
@@ -0,0 +1,174 @@
+// Copyright 2013 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 "chrome/browser/autofill/wallet/encryption_escrow_client.h"
+#include "chrome/browser/autofill/wallet/encryption_escrow_client_observer.h"
+#include "chrome/browser/autofill/wallet/instrument.h"
+#include "chrome/browser/autofill/wallet/wallet_test_util.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kEncryptOtpRequest[] = "cvv=30:000102030405";
+const char kEncryptOtpResponse[] = "session_material|encrypted_one_time_pad";
+const char kEscrowSensitiveInformationRequest[] =
+ "gid=obfuscated_gaia_id&cardNumber=4444444444444448&cvv=123";
+
+} // namespace
+
+namespace autofill {
+namespace wallet {
+
+class MockEncryptionEscrowClientObserver :
+ public EncryptionEscrowClientObserver,
+ public base::SupportsWeakPtr<MockEncryptionEscrowClientObserver> {
+ public:
+ MockEncryptionEscrowClientObserver() {}
+ ~MockEncryptionEscrowClientObserver() {}
+
+ MOCK_METHOD2(OnDidEncryptOneTimePad,
+ void(const std::string& encrypted_one_time_pad,
+ const std::string& session_material));
+ MOCK_METHOD1(OnDidEscrowSensitiveInformation,
+ void(const std::string& escrow_handle));
+ MOCK_METHOD0(OnMalformedResponse, void());
+ MOCK_METHOD1(OnNetworkError, void(int response_code));
+};
+
+class EncryptionEscrowClientTest : public testing::Test {
+ public:
+ EncryptionEscrowClientTest() : io_thread_(content::BrowserThread::IO) {}
+
+ virtual void SetUp() {
+ io_thread_.StartIOThread();
+ profile_.CreateRequestContext();
+ }
+
+ std::vector<uint8> MakeOneTimePad() {
+ std::vector<uint8> one_time_pad;
+ one_time_pad.push_back(0);
+ one_time_pad.push_back(1);
+ one_time_pad.push_back(2);
+ one_time_pad.push_back(3);
+ one_time_pad.push_back(4);
+ one_time_pad.push_back(5);
+ return one_time_pad;
+ }
+
+ virtual void TearDown() {
+ profile_.ResetRequestContext();
+ io_thread_.Stop();
+ }
+
+ void VerifyAndFinishRequest(const net::TestURLFetcherFactory& fetcher_factory,
+ net::HttpStatusCode response_code,
+ const std::string& request_body,
+ const std::string& response_body) {
+ net::TestURLFetcher* fetcher = fetcher_factory.GetFetcherByID(1);
+ ASSERT_TRUE(fetcher);
+ EXPECT_EQ(request_body, fetcher->upload_data());
+ fetcher->set_response_code(response_code);
+ fetcher->SetResponseString(response_body);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ }
+
+ protected:
+ TestingProfile profile_;
+
+ private:
+ // The profile's request context must be released on the IO thread.
+ content::TestBrowserThread io_thread_;
+};
+
+TEST_F(EncryptionEscrowClientTest, NetworkError) {
+ MockEncryptionEscrowClientObserver observer;
+ EXPECT_CALL(observer, OnNetworkError(net::HTTP_UNAUTHORIZED)).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ scoped_ptr<Instrument> instrument = GetTestInstrument();
+ EncryptionEscrowClient encryption_escrow_client(profile_.GetRequestContext());
+ encryption_escrow_client.EscrowSensitiveInformation(*instrument,
+ "obfuscated_gaia_id",
+ observer.AsWeakPtr());
+ VerifyAndFinishRequest(factory,
+ net::HTTP_UNAUTHORIZED,
+ kEscrowSensitiveInformationRequest,
+ std::string());
+}
+
+TEST_F(EncryptionEscrowClientTest, EscrowSensitiveInformationSuccess) {
+ MockEncryptionEscrowClientObserver observer;
+ EXPECT_CALL(observer, OnDidEscrowSensitiveInformation("abc")).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ scoped_ptr<Instrument> instrument = GetTestInstrument();
+ EncryptionEscrowClient encryption_escrow_client(profile_.GetRequestContext());
+ encryption_escrow_client.EscrowSensitiveInformation(*instrument,
+ "obfuscated_gaia_id",
+ observer.AsWeakPtr());
+ VerifyAndFinishRequest(factory,
+ net::HTTP_OK,
+ kEscrowSensitiveInformationRequest,
+ "abc");
+}
+
+TEST_F(EncryptionEscrowClientTest, EscrowSensitiveInformationFailure) {
+ MockEncryptionEscrowClientObserver observer;
+ EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
+
+ net::TestURLFetcherFactory factory;
+ scoped_ptr<Instrument> instrument = GetTestInstrument();
+ EncryptionEscrowClient encryption_escrow_client(profile_.GetRequestContext());
+ encryption_escrow_client.EscrowSensitiveInformation(*instrument,
+ "obfuscated_gaia_id",
+ observer.AsWeakPtr());
+ VerifyAndFinishRequest(factory,
+ net::HTTP_OK,
+ kEscrowSensitiveInformationRequest,
+ std::string());
+}
+
+TEST_F(EncryptionEscrowClientTest, EncryptOneTimePadSuccess) {
+ MockEncryptionEscrowClientObserver observer;
+ EXPECT_CALL(observer,
+ OnDidEncryptOneTimePad("encrypted_one_time_pad",
+ "session_material")).Times(1);
+
+ net::TestURLFetcherFactory factory;
+ EncryptionEscrowClient encryption_escrow_client(profile_.GetRequestContext());
+ encryption_escrow_client.EncryptOneTimePad(MakeOneTimePad(),
+ observer.AsWeakPtr());
+ VerifyAndFinishRequest(factory,
+ net::HTTP_OK,
+ kEncryptOtpRequest,
+ kEncryptOtpResponse);
+}
+
+TEST_F(EncryptionEscrowClientTest, EncryptOneTimePadFailure) {
+ MockEncryptionEscrowClientObserver observer;
+ EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
+
+ net::TestURLFetcherFactory factory;
+ EncryptionEscrowClient encryption_escrow_client(profile_.GetRequestContext());
+ encryption_escrow_client.EncryptOneTimePad(MakeOneTimePad(),
+ observer.AsWeakPtr());
+ VerifyAndFinishRequest(factory,
+ net::HTTP_OK,
+ kEncryptOtpRequest,
+ std::string());
+}
+
+} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/full_wallet.cc b/chrome/browser/autofill/wallet/full_wallet.cc
index 9217727b..ee9b5e76 100644
--- a/chrome/browser/autofill/wallet/full_wallet.cc
+++ b/chrome/browser/autofill/wallet/full_wallet.cc
@@ -16,6 +16,7 @@
} // anonymous namespace
+namespace autofill {
namespace wallet {
FullWallet::FullWallet(int expiration_month,
@@ -159,19 +160,19 @@
return !(*this == other);
}
-const std::string& FullWallet::GetPan(void* otp, size_t length) {
- if (cvn_.empty())
- DecryptCardInfo(reinterpret_cast<uint8*>(otp), length);
+const std::string& FullWallet::GetPan() {
+ if (pan_.empty())
+ DecryptCardInfo();
return pan_;
}
-const std::string& FullWallet::GetCvn(void* otp, size_t length) {
- if (pan_.empty())
- DecryptCardInfo(reinterpret_cast<uint8*>(otp), length);
+const std::string& FullWallet::GetCvn() {
+ if (cvn_.empty())
+ DecryptCardInfo();
return cvn_;
}
-void FullWallet::DecryptCardInfo(uint8* otp, size_t length) {
+void FullWallet::DecryptCardInfo() {
std::vector<uint8> operating_data;
// Convert |encrypted_rest_| to bytes so we can decrypt it with |otp|.
if (!base::HexStringToBytes(encrypted_rest_, &operating_data)) {
@@ -179,18 +180,18 @@
return;
}
- // Ensure |otp| and |encrypted_rest_| are of the same length otherwise
- // something has gone wrong and we can't decrypt the data.
- DCHECK_EQ(length, operating_data.size());
+ // Ensure |one_time_pad_| and |encrypted_rest_| are of the same length
+ // otherwise something has gone wrong and we can't decrypt the data.
+ DCHECK_EQ(one_time_pad_.size(), operating_data.size());
- scoped_array<uint8> result(new uint8[length]);
+ std::vector<uint8> results;
// XOR |otp| with the encrypted data to decrypt.
- for (size_t i = 0; i < length; ++i)
- result.get()[i] = otp[i] ^ operating_data[i];
+ for (size_t i = 0; i < one_time_pad_.size(); ++i)
+ results.push_back(one_time_pad_[i] ^ operating_data[i]);
// There is no uint8* to int64 so convert the decrypted data to hex and then
// parse the hex to an int64 before getting the int64 as a string.
- std::string hex_decrypted = base::HexEncode(result.get(), length);
+ std::string hex_decrypted = base::HexEncode(&(results[0]), results.size());
int64 decrypted;
if (!base::HexStringToInt64(hex_decrypted, &decrypted)) {
@@ -213,4 +214,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/full_wallet.h b/chrome/browser/autofill/wallet/full_wallet.h
index 9debc93..c7db6de 100644
--- a/chrome/browser/autofill/wallet/full_wallet.h
+++ b/chrome/browser/autofill/wallet/full_wallet.h
@@ -18,6 +18,7 @@
class DictionaryValue;
}
+namespace autofill {
namespace wallet {
class FullWalletTest;
@@ -36,13 +37,13 @@
static scoped_ptr<FullWallet>
CreateFullWallet(const base::DictionaryValue& dictionary);
- // Decrypts and returns primary account number (PAN) using generated one time
- // pad, |otp|.
- const std::string& GetPan(void* otp, size_t length);
+ // Decrypts and returns the primary account number (PAN) using the generated
+ // one time pad, |one_time_pad_|.
+ const std::string& GetPan();
- // Decrypts and returns card verification number (CVN) using generated one
- // time pad, |otp|.
- const std::string& GetCvn(void* otp, size_t length);
+ // Decrypts and returns the card verification number (CVN) using the generated
+ // one time pad, |one_time_pad_|.
+ const std::string& GetCvn();
bool operator==(const FullWallet& other) const;
bool operator!=(const FullWallet& other) const;
@@ -60,6 +61,10 @@
int expiration_month() const { return expiration_month_; }
int expiration_year() const { return expiration_year_; }
+ void set_one_time_pad(const std::vector<uint8>& one_time_pad) {
+ one_time_pad_ = one_time_pad;
+ }
+
private:
friend class FullWalletTest;
FRIEND_TEST_ALL_PREFIXES(FullWalletTest, CreateFullWallet);
@@ -71,7 +76,7 @@
scoped_ptr<Address> billing_address,
scoped_ptr<Address> shipping_address,
const std::vector<RequiredAction>& required_actions);
- void DecryptCardInfo(uint8* otp, size_t length);
+ void DecryptCardInfo();
// The expiration month of the proxy card. It should be 1-12.
int expiration_month_;
@@ -101,10 +106,13 @@
// issued to them by the Online Wallet service.
std::vector<RequiredAction> required_actions_;
+ // The one time pad used for FullWallet encryption.
+ std::vector<uint8> one_time_pad_;
+
DISALLOW_COPY_AND_ASSIGN(FullWallet);
};
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_FULL_WALLET_H_
-
diff --git a/chrome/browser/autofill/wallet/full_wallet_unittest.cc b/chrome/browser/autofill/wallet/full_wallet_unittest.cc
index 86d955d..3dcc833 100644
--- a/chrome/browser/autofill/wallet/full_wallet_unittest.cc
+++ b/chrome/browser/autofill/wallet/full_wallet_unittest.cc
@@ -343,6 +343,7 @@
} // anonymous namespace
+namespace autofill {
namespace wallet {
class FullWalletTest : public testing::Test {
@@ -457,5 +458,7 @@
ASSERT_EQ(full_wallet, *FullWallet::CreateFullWallet(*dict));
}
-} // namespace wallet
+// TODO(ahutter): Add tests for GetPan and GetCvn.
+} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/instrument.cc b/chrome/browser/autofill/wallet/instrument.cc
index 94ce9ac..cc059d22 100644
--- a/chrome/browser/autofill/wallet/instrument.cc
+++ b/chrome/browser/autofill/wallet/instrument.cc
@@ -11,22 +11,24 @@
#include "chrome/browser/autofill/validation.h"
#include "chrome/browser/autofill/wallet/wallet_address.h"
+namespace autofill {
+namespace wallet {
+
namespace {
-std::string FormOfPaymentToString(
- wallet::Instrument::FormOfPayment form_of_payment) {
+std::string FormOfPaymentToString(Instrument::FormOfPayment form_of_payment) {
switch (form_of_payment) {
- case wallet::Instrument::UNKNOWN:
+ case Instrument::UNKNOWN:
return "UNKNOWN";
- case wallet::Instrument::VISA:
+ case Instrument::VISA:
return "VISA";
- case wallet::Instrument::MASTER_CARD:
+ case Instrument::MASTER_CARD:
return "MASTER_CARD";
- case wallet::Instrument::AMEX:
+ case Instrument::AMEX:
return "AMEX";
- case wallet::Instrument::DISCOVER:
+ case Instrument::DISCOVER:
return "DISCOVER";
- case wallet::Instrument::JCB:
+ case Instrument::JCB:
return "JCB";
}
NOTREACHED();
@@ -35,8 +37,6 @@
} // namespace
-namespace wallet {
-
Instrument::Instrument(const string16& primary_account_number,
const string16& card_verification_number,
int expiration_month,
@@ -93,3 +93,4 @@
}
} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/instrument.h b/chrome/browser/autofill/wallet/instrument.h
index 9c31b638..a1a240e 100644
--- a/chrome/browser/autofill/wallet/instrument.h
+++ b/chrome/browser/autofill/wallet/instrument.h
@@ -14,6 +14,7 @@
class DictionaryValue;
}
+namespace autofill {
namespace wallet {
class Address;
@@ -84,6 +85,6 @@
};
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_INSTRUMENT_H_
-
diff --git a/chrome/browser/autofill/wallet/instrument_unittest.cc b/chrome/browser/autofill/wallet/instrument_unittest.cc
index 321546e..83c98f02 100644
--- a/chrome/browser/autofill/wallet/instrument_unittest.cc
+++ b/chrome/browser/autofill/wallet/instrument_unittest.cc
@@ -17,6 +17,7 @@
}
+namespace autofill {
namespace wallet {
TEST(Instrument, LastFourDigits) {
@@ -185,3 +186,4 @@
}
} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/required_action.cc b/chrome/browser/autofill/wallet/required_action.cc
index 4b41c3a3..3557862 100644
--- a/chrome/browser/autofill/wallet/required_action.cc
+++ b/chrome/browser/autofill/wallet/required_action.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "base/string_util.h"
+namespace autofill {
namespace wallet {
bool ActionAppliesToFullWallet(RequiredAction action) {
@@ -50,3 +51,4 @@
}
} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/required_action.h b/chrome/browser/autofill/wallet/required_action.h
index 4778220b..bbb7a2a 100644
--- a/chrome/browser/autofill/wallet/required_action.h
+++ b/chrome/browser/autofill/wallet/required_action.h
@@ -7,6 +7,7 @@
#include <string>
+namespace autofill {
namespace wallet {
// Required actions are steps that must be taken before the current transaction
@@ -35,5 +36,6 @@
RequiredAction ParseRequiredActionFromString(const std::string& str);
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_REQUIRED_ACTION_H_
diff --git a/chrome/browser/autofill/wallet/wallet_address.cc b/chrome/browser/autofill/wallet/wallet_address.cc
index eb34483..76e3893 100644
--- a/chrome/browser/autofill/wallet/wallet_address.cc
+++ b/chrome/browser/autofill/wallet/wallet_address.cc
@@ -8,6 +8,7 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
+namespace autofill {
namespace wallet {
Address::Address() {}
@@ -231,4 +232,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_address.h b/chrome/browser/autofill/wallet/wallet_address.h
index adba56e..9804709 100644
--- a/chrome/browser/autofill/wallet/wallet_address.h
+++ b/chrome/browser/autofill/wallet/wallet_address.h
@@ -16,6 +16,7 @@
class DictionaryValue;
}
+namespace autofill {
namespace wallet {
// TODO(ahutter): This address is a lot like chrome/browser/autofill/address.h.
@@ -152,6 +153,6 @@
};
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_WALLET_ADDRESS_H_
-
diff --git a/chrome/browser/autofill/wallet/wallet_address_unittest.cc b/chrome/browser/autofill/wallet/wallet_address_unittest.cc
index 06dc9f7..747e034 100644
--- a/chrome/browser/autofill/wallet/wallet_address_unittest.cc
+++ b/chrome/browser/autofill/wallet/wallet_address_unittest.cc
@@ -150,6 +150,7 @@
} // anonymous namespace
+namespace autofill {
namespace wallet {
class WalletAddressTest : public testing::Test {
@@ -291,4 +292,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_client.cc b/chrome/browser/autofill/wallet/wallet_client.cc
index 5398cc1..c735a3d 100644
--- a/chrome/browser/autofill/wallet/wallet_client.cc
+++ b/chrome/browser/autofill/wallet/wallet_client.cc
@@ -8,18 +8,13 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/string_split.h"
-#include "base/stringprintf.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
#include "chrome/browser/autofill/wallet/cart.h"
-#include "chrome/browser/autofill/wallet/full_wallet.h"
#include "chrome/browser/autofill/wallet/instrument.h"
#include "chrome/browser/autofill/wallet/wallet_address.h"
#include "chrome/browser/autofill/wallet/wallet_client_observer.h"
#include "chrome/browser/autofill/wallet/wallet_items.h"
#include "chrome/browser/autofill/wallet/wallet_service_url.h"
+#include "crypto/random.h"
#include "google_apis/google_api_keys.h"
#include "googleurl/src/gurl.h"
#include "net/http/http_status_code.h"
@@ -28,11 +23,8 @@
namespace {
-const char kEncryptOtpBodyFormat[] = "cvv=%s:%s";
-const char kEscrowSensitiveInformationFormat[] = "gid=%s&cardNumber=%s&cvv=%s";
const char kJsonMimeType[] = "application/json";
-const char kApplicationMimeType[] = "application/x-www-form-urlencoded";
-const size_t kMaxBits = 63;
+const size_t kOneTimePadLength = 6;
std::string AutocheckoutStatusToString(autofill::AutocheckoutStatus status) {
switch (status) {
@@ -53,8 +45,21 @@
} // anonymous namespace
+namespace autofill {
namespace wallet {
+WalletClient::WalletClient(net::URLRequestContextGetter* context_getter)
+ : context_getter_(context_getter),
+ observer_(NULL),
+ request_type_(NO_PENDING_REQUEST),
+ one_time_pad_(kOneTimePadLength),
+ encryption_escrow_client_(context_getter),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
+ DCHECK(context_getter);
+}
+
+WalletClient::~WalletClient() {}
+
void WalletClient::AcceptLegalDocuments(
const std::vector<std::string>& document_ids,
const std::string& google_transaction_id,
@@ -62,7 +67,7 @@
DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
request_type_ = ACCEPT_LEGAL_DOCUMENTS;
- DictionaryValue request_dict;
+ base::DictionaryValue request_dict;
request_dict.SetString("api_key", google_apis::GetAPIKey());
request_dict.SetString("google_transaction_id", google_transaction_id);
ListValue* docs_list = new ListValue();
@@ -76,89 +81,47 @@
std::string post_body;
base::JSONWriter::Write(&request_dict, &post_body);
- MakeWalletRequest(GetAcceptLegalDocumentsUrl(),
- post_body,
- observer,
- kJsonMimeType);
+ MakeWalletRequest(GetAcceptLegalDocumentsUrl(), post_body, observer);
}
-void WalletClient::EncryptOtp(const void* otp,
- size_t length,
- WalletClientObserver* observer) {
- DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
- size_t num_bits = length * 8;
- DCHECK_LT(num_bits, kMaxBits);
-
- request_type_ = ENCRYPT_OTP;
-
- std::string post_body = base::StringPrintf(
- kEncryptOtpBodyFormat,
- base::HexEncode(&num_bits, 1).c_str(),
- base::HexEncode(otp, length).c_str());
-
- MakeWalletRequest(GetEncryptionUrl(),
- post_body,
- observer,
- kApplicationMimeType);
-}
-
-void WalletClient::EscrowSensitiveInformation(
- const Instrument& new_instrument,
- const std::string& obfuscated_gaia_id,
- WalletClientObserver* observer) {
- DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
- request_type_ = ESCROW_SENSITIVE_INFORMATION;
-
- std::string post_body = base::StringPrintf(
- kEscrowSensitiveInformationFormat,
- obfuscated_gaia_id.c_str(),
- UTF16ToUTF8(new_instrument.primary_account_number()).c_str(),
- UTF16ToUTF8(new_instrument.card_verification_number()).c_str());
-
- MakeWalletRequest(GetEscrowUrl(), post_body, observer, kApplicationMimeType);
-}
-
-
void WalletClient::GetFullWallet(const std::string& instrument_id,
const std::string& address_id,
const std::string& merchant_domain,
const Cart& cart,
const std::string& google_transaction_id,
- const std::string& encrypted_otp,
- const std::string& session_material,
WalletClientObserver* observer) {
DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
+ DCHECK(observer);
+ DCHECK(pending_request_body_.empty());
request_type_ = GET_FULL_WALLET;
+ observer_ = observer;
- DictionaryValue request_dict;
- request_dict.SetString("api_key", google_apis::GetAPIKey());
- request_dict.SetString("risk_params", GetRiskParams());
- request_dict.SetString("selected_instrument_id", instrument_id);
- request_dict.SetString("selected_address_id", address_id);
- request_dict.SetString("merchant_domain", merchant_domain);
- request_dict.SetString("google_transaction_id", google_transaction_id);
- request_dict.Set("cart", cart.ToDictionary().release());
- request_dict.SetString("encrypted_otp", encrypted_otp);
- request_dict.SetString("session_material", session_material);
+ pending_request_body_.SetString("api_key", google_apis::GetAPIKey());
+ pending_request_body_.SetString("risk_params", GetRiskParams());
+ pending_request_body_.SetString("selected_instrument_id", instrument_id);
+ pending_request_body_.SetString("selected_address_id", address_id);
+ pending_request_body_.SetString("merchant_domain", merchant_domain);
+ pending_request_body_.SetString("google_transaction_id",
+ google_transaction_id);
+ pending_request_body_.Set("cart", cart.ToDictionary().release());
- std::string post_body;
- base::JSONWriter::Write(&request_dict, &post_body);
-
- MakeWalletRequest(GetGetFullWalletUrl(), post_body, observer, kJsonMimeType);
+ crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
+ encryption_escrow_client_.EncryptOneTimePad(one_time_pad_,
+ weak_ptr_factory_.GetWeakPtr());
}
void WalletClient::GetWalletItems(WalletClientObserver* observer) {
DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
request_type_ = GET_WALLET_ITEMS;
- DictionaryValue request_dict;
+ base::DictionaryValue request_dict;
request_dict.SetString("api_key", google_apis::GetAPIKey());
request_dict.SetString("risk_params", GetRiskParams());
std::string post_body;
base::JSONWriter::Write(&request_dict, &post_body);
- MakeWalletRequest(GetGetWalletItemsUrl(), post_body, observer, kJsonMimeType);
+ MakeWalletRequest(GetGetWalletItemsUrl(), post_body, observer);
}
void WalletClient::SaveAddress(const Address& shipping_address,
@@ -166,61 +129,66 @@
DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
request_type_ = SAVE_ADDRESS;
- SaveToWallet(NULL,
- std::string(),
- &shipping_address,
- observer);
-}
-
-void WalletClient::SaveInstrument(const Instrument& instrument,
- const std::string& escrow_handle,
- WalletClientObserver* observer) {
- DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
- request_type_ = SAVE_INSTRUMENT;
-
- SaveToWallet(&instrument,
- escrow_handle,
- NULL,
- observer);
-}
-
-void WalletClient::SaveInstrumentAndAddress(const Instrument& instrument,
- const std::string& escrow_handle,
- const Address& address,
- WalletClientObserver* observer) {
- DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
- request_type_ = SAVE_INSTRUMENT_AND_ADDRESS;
-
- SaveToWallet(&instrument,
- escrow_handle,
- &address,
- observer);
-}
-
-void WalletClient::SaveToWallet(const Instrument* instrument,
- const std::string& escrow_handle,
- const Address* shipping_address,
- WalletClientObserver* observer) {
- DictionaryValue request_dict;
+ base::DictionaryValue request_dict;
request_dict.SetString("api_key", google_apis::GetAPIKey());
request_dict.SetString("risk_params", GetRiskParams());
- if (instrument) {
- request_dict.Set("instrument", instrument->ToDictionary().release());
- request_dict.SetString("instrument_escrow_handle", escrow_handle);
- request_dict.SetString("instrument_phone_number",
- instrument->address().phone_number());
- }
-
- if (shipping_address) {
- request_dict.Set("shipping_address",
- shipping_address->ToDictionaryWithID().release());
- }
+ request_dict.Set("shipping_address",
+ shipping_address.ToDictionaryWithID().release());
std::string post_body;
base::JSONWriter::Write(&request_dict, &post_body);
- MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer, kJsonMimeType);
+ MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer);
+}
+
+void WalletClient::SaveInstrument(const Instrument& instrument,
+ const std::string& obfuscated_gaia_id,
+ WalletClientObserver* observer) {
+ DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
+ DCHECK(observer);
+ DCHECK(pending_request_body_.empty());
+ request_type_ = SAVE_INSTRUMENT;
+ observer_ = observer;
+
+ pending_request_body_.SetString("api_key", google_apis::GetAPIKey());
+ pending_request_body_.SetString("risk_params", GetRiskParams());
+
+ pending_request_body_.Set("instrument", instrument.ToDictionary().release());
+ pending_request_body_.SetString("instrument_phone_number",
+ instrument.address().phone_number());
+
+ encryption_escrow_client_.EscrowSensitiveInformation(
+ instrument,
+ obfuscated_gaia_id,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+void WalletClient::SaveInstrumentAndAddress(
+ const Instrument& instrument,
+ const Address& address,
+ const std::string& obfuscated_gaia_id,
+ WalletClientObserver* observer) {
+ DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
+ DCHECK(observer);
+ DCHECK(pending_request_body_.empty());
+ request_type_ = SAVE_INSTRUMENT_AND_ADDRESS;
+ observer_ = observer;
+
+ pending_request_body_.SetString("api_key", google_apis::GetAPIKey());
+ pending_request_body_.SetString("risk_params", GetRiskParams());
+
+ pending_request_body_.Set("instrument", instrument.ToDictionary().release());
+ pending_request_body_.SetString("instrument_phone_number",
+ instrument.address().phone_number());
+
+ pending_request_body_.Set("shipping_address",
+ address.ToDictionaryWithID().release());
+
+ encryption_escrow_client_.EscrowSensitiveInformation(
+ instrument,
+ obfuscated_gaia_id,
+ weak_ptr_factory_.GetWeakPtr());
}
void WalletClient::SendAutocheckoutStatus(
@@ -231,7 +199,7 @@
DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
request_type_ = SEND_STATUS;
- DictionaryValue request_dict;
+ base::DictionaryValue request_dict;
request_dict.SetString("api_key", google_apis::GetAPIKey());
bool success = status == autofill::SUCCESS;
request_dict.SetBoolean("success", success);
@@ -244,7 +212,7 @@
std::string post_body;
base::JSONWriter::Write(&request_dict, &post_body);
- MakeWalletRequest(GetSendStatusUrl(), post_body, observer, kJsonMimeType);
+ MakeWalletRequest(GetSendStatusUrl(), post_body, observer);
}
void WalletClient::UpdateInstrument(const std::string& instrument_id,
@@ -253,7 +221,7 @@
DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
request_type_ = UPDATE_INSTRUMENT;
- DictionaryValue request_dict;
+ base::DictionaryValue request_dict;
request_dict.SetString("api_key", google_apis::GetAPIKey());
request_dict.SetString("upgraded_instrument_id", instrument_id);
request_dict.SetString("instrument_phone_number",
@@ -264,7 +232,7 @@
std::string post_body;
base::JSONWriter::Write(&request_dict, &post_body);
- MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer, kJsonMimeType);
+ MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer);
}
bool WalletClient::HasRequestInProgress() const {
@@ -273,8 +241,7 @@
void WalletClient::MakeWalletRequest(const GURL& url,
const std::string& post_body,
- WalletClientObserver* observer,
- const std::string& content_type) {
+ WalletClientObserver* observer) {
DCHECK(!HasRequestInProgress());
DCHECK(observer);
@@ -283,9 +250,8 @@
request_.reset(net::URLFetcher::Create(
0, url, net::URLFetcher::POST, this));
request_->SetRequestContext(context_getter_);
- DVLOG(1) << "url=" << url << ", post_body=" << post_body
- << ", content_type=" << content_type;
- request_->SetUploadData(content_type, post_body);
+ DVLOG(1) << "url=" << url << ", post_body=" << post_body;
+ request_->SetUploadData(kJsonMimeType, post_body);
request_->Start();
}
@@ -300,7 +266,7 @@
source->GetResponseAsString(&data);
DVLOG(1) << "Response body: " << data;
- scoped_ptr<DictionaryValue> response_dict;
+ scoped_ptr<base::DictionaryValue> response_dict;
int response_code = source->GetResponseCode();
switch (response_code) {
@@ -318,7 +284,7 @@
if (message_value.get() &&
message_value->IsType(Value::TYPE_DICTIONARY)) {
response_dict.reset(
- static_cast<DictionaryValue*>(message_value.release()));
+ static_cast<base::DictionaryValue*>(message_value.release()));
}
if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
request_type_ = NO_PENDING_REQUEST;
@@ -340,6 +306,11 @@
RequestType type = request_type_;
request_type_ = NO_PENDING_REQUEST;
+ if (!(type == ACCEPT_LEGAL_DOCUMENTS || SEND_STATUS) && !response_dict) {
+ HandleMalformedResponse(old_request.get());
+ return;
+ }
+
switch (type) {
case ACCEPT_LEGAL_DOCUMENTS:
observer_->OnDidAcceptLegalDocuments();
@@ -347,100 +318,66 @@
case SEND_STATUS:
observer_->OnDidSendAutocheckoutStatus();
break;
- case ENCRYPT_OTP:
- if (!data.empty()) {
- std::vector<std::string> splits;
- base::SplitString(data, '|', &splits);
- if (splits.size() == 2)
- observer_->OnDidEncryptOtp(splits[1], splits[0]);
- else
- HandleMalformedResponse(old_request.get());
+ case GET_FULL_WALLET: {
+ scoped_ptr<FullWallet> full_wallet(
+ FullWallet::CreateFullWallet(*response_dict));
+ if (full_wallet) {
+ full_wallet->set_one_time_pad(one_time_pad_);
+ observer_->OnDidGetFullWallet(full_wallet.Pass());
} else {
HandleMalformedResponse(old_request.get());
}
break;
- case ESCROW_SENSITIVE_INFORMATION:
- if (!data.empty())
- observer_->OnDidEscrowSensitiveInformation(data);
+ }
+ case GET_WALLET_ITEMS: {
+ scoped_ptr<WalletItems> wallet_items(
+ WalletItems::CreateWalletItems(*response_dict));
+ if (wallet_items)
+ observer_->OnDidGetWalletItems(wallet_items.Pass());
else
HandleMalformedResponse(old_request.get());
break;
- case GET_FULL_WALLET:
- if (response_dict) {
- scoped_ptr<FullWallet> full_wallet(
- FullWallet::CreateFullWallet(*response_dict));
- if (full_wallet)
- observer_->OnDidGetFullWallet(full_wallet.Pass());
- else
- HandleMalformedResponse(old_request.get());
+ }
+ case SAVE_ADDRESS: {
+ std::string shipping_address_id;
+ if (response_dict->GetString("shipping_address_id",
+ &shipping_address_id))
+ observer_->OnDidSaveAddress(shipping_address_id);
+ else
+ HandleMalformedResponse(old_request.get());
+ break;
+ }
+ case SAVE_INSTRUMENT: {
+ std::string instrument_id;
+ if (response_dict->GetString("instrument_id", &instrument_id))
+ observer_->OnDidSaveInstrument(instrument_id);
+ else
+ HandleMalformedResponse(old_request.get());
+ break;
+ }
+ case SAVE_INSTRUMENT_AND_ADDRESS: {
+ std::string instrument_id;
+ response_dict->GetString("instrument_id", &instrument_id);
+ std::string shipping_address_id;
+ response_dict->GetString("shipping_address_id",
+ &shipping_address_id);
+ if (!instrument_id.empty() && !shipping_address_id.empty()) {
+ observer_->OnDidSaveInstrumentAndAddress(instrument_id,
+ shipping_address_id);
} else {
HandleMalformedResponse(old_request.get());
}
break;
- case GET_WALLET_ITEMS:
- if (response_dict) {
- scoped_ptr<WalletItems> wallet_items(
- WalletItems::CreateWalletItems(*response_dict));
- if (wallet_items)
- observer_->OnDidGetWalletItems(wallet_items.Pass());
- else
- HandleMalformedResponse(old_request.get());
- } else {
+ }
+ case UPDATE_INSTRUMENT: {
+ std::string instrument_id;
+ response_dict->GetString("instrument_id", &instrument_id);
+ if (!instrument_id.empty())
+ observer_->OnDidUpdateInstrument(instrument_id);
+ else
HandleMalformedResponse(old_request.get());
- }
break;
- case SAVE_ADDRESS:
- if (response_dict) {
- std::string shipping_address_id;
- if (response_dict->GetString("shipping_address_id",
- &shipping_address_id))
- observer_->OnDidSaveAddress(shipping_address_id);
- else
- HandleMalformedResponse(old_request.get());
- } else {
- HandleMalformedResponse(old_request.get());
- }
- break;
- case SAVE_INSTRUMENT:
- if (response_dict) {
- std::string instrument_id;
- if (response_dict->GetString("instrument_id", &instrument_id))
- observer_->OnDidSaveInstrument(instrument_id);
- else
- HandleMalformedResponse(old_request.get());
- } else {
- HandleMalformedResponse(old_request.get());
- }
- break;
- case SAVE_INSTRUMENT_AND_ADDRESS:
- if (response_dict) {
- std::string instrument_id;
- response_dict->GetString("instrument_id", &instrument_id);
- std::string shipping_address_id;
- response_dict->GetString("shipping_address_id",
- &shipping_address_id);
- if (!instrument_id.empty() && !shipping_address_id.empty()) {
- observer_->OnDidSaveInstrumentAndAddress(instrument_id,
- shipping_address_id);
- } else {
- HandleMalformedResponse(old_request.get());
- }
- } else {
- HandleMalformedResponse(old_request.get());
- }
- break;
- case UPDATE_INSTRUMENT:
- if (response_dict) {
- std::string instrument_id;
- response_dict->GetString("instrument_id", &instrument_id);
- if (!instrument_id.empty())
- observer_->OnDidUpdateInstrument(instrument_id);
- else
- HandleMalformedResponse(old_request.get());
- } else {
- HandleMalformedResponse(old_request.get());
- }
- break;
+ }
case NO_PENDING_REQUEST:
NOTREACHED();
}
@@ -452,14 +389,41 @@
observer_->OnMalformedResponse();
}
-WalletClient::WalletClient(net::URLRequestContextGetter* context_getter)
- : context_getter_(context_getter),
- observer_(NULL),
- request_type_(NO_PENDING_REQUEST) {
- DCHECK(context_getter);
+void WalletClient::OnDidEncryptOneTimePad(
+ const std::string& encrypted_one_time_pad,
+ const std::string& session_material) {
+ DCHECK_EQ(GET_FULL_WALLET, request_type_);
+ pending_request_body_.SetString("encrypted_otp", encrypted_one_time_pad);
+ pending_request_body_.SetString("session_material", session_material);
+
+ std::string post_body;
+ base::JSONWriter::Write(&pending_request_body_, &post_body);
+ pending_request_body_.Clear();
+
+ MakeWalletRequest(GetGetFullWalletUrl(), post_body, observer_);
}
-WalletClient::~WalletClient() {}
+void WalletClient::OnDidEscrowSensitiveInformation(
+ const std::string& escrow_handle) {
+ DCHECK(request_type_ == SAVE_INSTRUMENT ||
+ request_type_ == SAVE_INSTRUMENT_AND_ADDRESS);
+
+ pending_request_body_.SetString("instrument_escrow_handle", escrow_handle);
+
+ std::string post_body;
+ base::JSONWriter::Write(&pending_request_body_, &post_body);
+ pending_request_body_.Clear();
+
+ MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer_);
+}
+
+void WalletClient::OnNetworkError(int response_code) {
+ observer_->OnNetworkError(response_code);
+}
+
+void WalletClient::OnMalformedResponse() {
+ observer_->OnMalformedResponse();
+}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_client.h b/chrome/browser/autofill/wallet/wallet_client.h
index cd8cf3d..108c1987 100644
--- a/chrome/browser/autofill/wallet/wallet_client.h
+++ b/chrome/browser/autofill/wallet/wallet_client.h
@@ -9,16 +9,22 @@
#include <vector>
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/autofill/wallet/encryption_escrow_client.h"
+#include "chrome/browser/autofill/wallet/encryption_escrow_client_observer.h"
+#include "chrome/browser/autofill/wallet/full_wallet.h"
#include "chrome/common/autofill/autocheckout_status.h"
#include "net/url_request/url_fetcher_delegate.h"
class GURL;
namespace net {
-class URLRequestContextGetter;
class URLFetcher;
+class URLRequestContextGetter;
}
+namespace autofill {
namespace wallet {
class Address;
@@ -30,7 +36,9 @@
// WalletClient is responsible for making calls to the Online Wallet backend on
// the user's behalf.
-class WalletClient : public net::URLFetcherDelegate {
+class WalletClient
+ : public net::URLFetcherDelegate,
+ public EncryptionEscrowClientObserver {
public:
explicit WalletClient(net::URLRequestContextGetter* context_getter);
virtual ~WalletClient();
@@ -48,51 +56,31 @@
const std::string& google_transaction_id,
WalletClientObserver* observer);
- // Before calling GetFullWallet, the client must encrypt a one time pad,
- // |otp|, of crytographically secure random bytes. These bytes must be
- // generated using crypto/random.h.
- void EncryptOtp(const void* otp,
- size_t length,
- WalletClientObserver* observer);
-
- // Before calling SaveInstrument or SaveAddressAndInstrument, the client must
- // escrow the primary account number and card verfication number of
- // |new_instrument| with Google Wallet.
- void EscrowSensitiveInformation(const Instrument& new_instrument,
- const std::string& obfuscated_gaia_id,
- WalletClientObserver* observer);
-
// GetFullWallet retrieves the a FullWallet for the user. |instrument_id| and
// |adddress_id| should have been selected by the user in some UI,
// |merchant_domain| should come from the BrowserContext, the |cart|
- // information will have been provided by the browser, |google_transaction_id|
- // is the same one that GetWalletItems returns, and |encrypted_otp| and
- // |session_material| are the results of the EncryptOtp call.
+ // information will have been provided by the browser, and
+ // |google_transaction_id| is the same one that GetWalletItems returns.
void GetFullWallet(const std::string& instrument_id,
const std::string& address_id,
const std::string& merchant_domain,
const Cart& cart,
const std::string& google_transaction_id,
- const std::string& encrypted_otp,
- const std::string& session_material,
WalletClientObserver* observer);
// SaveAddress saves a new shipping address.
void SaveAddress(const Address& address,
WalletClientObserver* observer);
- // SaveInstrument saves a new instrument. |escrow_handle| must have been
- // retrieved from Google Wallet through an EscrowSensitiveInformation call.
+ // SaveInstrument saves a new instrument.
void SaveInstrument(const Instrument& instrument,
- const std::string& escrow_handle,
+ const std::string& obfuscated_gaia_id,
WalletClientObserver* observer);
// SaveInstrumentAndAddress saves a new instrument and address.
- // |escrow_handle| must have been retrieved from Google Wallet through an
- // EscrowSensitiveInformation call.
void SaveInstrumentAndAddress(const Instrument& instrument,
- const std::string& escrow_handle,
const Address& shipping_address,
+ const std::string& obfuscated_gaia_id,
WalletClientObserver* observer);
// SendAutocheckoutStatus is used for tracking the success of Autocheckout
@@ -123,8 +111,6 @@
enum RequestType {
NO_PENDING_REQUEST,
ACCEPT_LEGAL_DOCUMENTS,
- ENCRYPT_OTP,
- ESCROW_SENSITIVE_INFORMATION,
GET_FULL_WALLET,
GET_WALLET_ITEMS,
SAVE_ADDRESS,
@@ -134,16 +120,26 @@
UPDATE_INSTRUMENT,
};
+ // Posts |post_body| to |url| and notifies |observer| when the request is
+ // complete.
void MakeWalletRequest(const GURL& url,
const std::string& post_body,
- WalletClientObserver* observer,
- const std::string& content_type);
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+ WalletClientObserver* observer);
+
+ // Performs bookkeeping tasks for any invalid requests.
void HandleMalformedResponse(net::URLFetcher* request);
- void SaveToWallet(const Instrument* instrument,
- const std::string& escrow_handle,
- const Address* address,
- WalletClientObserver* observer);
+
+ // net::URLFetcherDelegate:
+ virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+ // EncryptionEscrowClientObserver:
+ virtual void OnDidEncryptOneTimePad(
+ const std::string& encrypted_one_time_pad,
+ const std::string& session_material) OVERRIDE;
+ virtual void OnDidEscrowSensitiveInformation(
+ const std::string& escrow_handle) OVERRIDE;
+ virtual void OnNetworkError(int response_code) OVERRIDE;
+ virtual void OnMalformedResponse() OVERRIDE;
// The context for the request. Ensures the gdToken cookie is set as a header
// in the requests to Online Wallet if it is present.
@@ -160,10 +156,24 @@
// to be initiated as only one request may be running at a given time.
RequestType request_type_;
+ // The one time pad used for GetFullWallet encryption.
+ std::vector<uint8> one_time_pad_;
+
+ // GetFullWallet requests and requests that alter instruments rely on requests
+ // made through the |encryption_escrow_client_| finishing first. The request
+ // body is saved here while that those requests are in flight.
+ base::DictionaryValue pending_request_body_;
+
+ // This client is repsonsible for making encryption and escrow calls to Online
+ // Wallet.
+ EncryptionEscrowClient encryption_escrow_client_;
+
+ base::WeakPtrFactory<WalletClient> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WalletClient);
};
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_WALLET_CLIENT_H_
-
diff --git a/chrome/browser/autofill/wallet/wallet_client_observer.h b/chrome/browser/autofill/wallet/wallet_client_observer.h
index afec444e8..66af614 100644
--- a/chrome/browser/autofill/wallet/wallet_client_observer.h
+++ b/chrome/browser/autofill/wallet/wallet_client_observer.h
@@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h"
+namespace autofill {
namespace wallet {
class FullWallet;
@@ -22,17 +23,6 @@
// Called when an AcceptLegalDocuments request finishes successfully.
virtual void OnDidAcceptLegalDocuments() = 0;
- // Called when an EncryptOtp request finishes successfully. |encrypted_otp|
- // and |session_material| must be used when calling GetFullWallet.
- virtual void OnDidEncryptOtp(const std::string& encrypted_otp,
- const std::string& session_material) = 0;
-
- // Called when an EscrowSensitiveInformation request finishes successfully.
- // |escrow_handle| must be used when saving a new instrument using
- // SaveInstrument or SaveAdressAndInstrument.
- virtual void OnDidEscrowSensitiveInformation(
- const std::string& escrow_handle) = 0;
-
// Called when a GetFullWallet request finishes successfully. Ownership is
// transferred to implementer of this interface.
virtual void OnDidGetFullWallet(scoped_ptr<FullWallet> full_wallet) = 0;
@@ -78,5 +68,6 @@
};
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_WALLET_CLIENT_OBSERVER_H_
diff --git a/chrome/browser/autofill/wallet/wallet_client_unittest.cc b/chrome/browser/autofill/wallet/wallet_client_unittest.cc
index 11208ad..24e1532 100644
--- a/chrome/browser/autofill/wallet/wallet_client_unittest.cc
+++ b/chrome/browser/autofill/wallet/wallet_client_unittest.cc
@@ -79,6 +79,11 @@
" ]"
"}";
+const char kGetFullWalletInvalidResponse[] =
+ "{"
+ " \"garbage\":123"
+ "}";
+
const char kGetWalletItemsValidResponse[] =
"{"
" \"required_action\":"
@@ -183,7 +188,7 @@
"\"currency_code\":\"currency_code\","
"\"total_price\":\"currency_code\""
"},"
- "\"encrypted_otp\":\"encrypted_otp\","
+ "\"encrypted_otp\":\"encrypted_one_time_pad\","
"\"google_transaction_id\":\"google_transaction_id\","
"\"merchant_domain\":\"merchant_domain\","
"\"risk_params\":\"\","
@@ -332,11 +337,9 @@
"\"upgraded_instrument_id\":\"instrument_id\""
"}";
-const char kEscrowSensitiveInformationRequest[] =
- "gid=obfuscated_gaia_id&cardNumber=4444444444444448&cvv=123";
-
} // anonymous namespace
+namespace autofill {
namespace wallet {
class WalletClientTest : public testing::Test {
@@ -394,10 +397,6 @@
~MockWalletClientObserver() {}
MOCK_METHOD0(OnDidAcceptLegalDocuments, void());
- MOCK_METHOD2(OnDidEncryptOtp, void(const std::string& encrypted_otp,
- const std::string& session_material));
- MOCK_METHOD1(OnDidEscrowSensitiveInformation,
- void(const std::string& escrow_handle));
MOCK_METHOD1(OnDidSaveAddress, void(const std::string& address_id));
MOCK_METHOD1(OnDidSaveInstrument, void(const std::string& instrument_id));
MOCK_METHOD2(OnDidSaveInstrumentAndAddress,
@@ -457,8 +456,7 @@
net::TestURLFetcherFactory factory;
WalletClient wallet_client(profile_.GetRequestContext());
- Cart cart("currency_code", "currency_code");
- wallet_client.GetFullWallet("", "", "", cart, "", "", "", &observer);
+ wallet_client.GetWalletItems(&observer);
net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_INTERNAL_SERVER_ERROR);
@@ -489,8 +487,7 @@
net::TestURLFetcherFactory factory;
WalletClient wallet_client(profile_.GetRequestContext());
- Cart cart("currency_code", "currency_code");
- wallet_client.GetFullWallet("", "", "", cart, "", "", "", &observer);
+ wallet_client.GetWalletItems(&observer);
net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
@@ -514,44 +511,7 @@
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
-// TODO(ahutter): Add test for EncryptOtp.
-// TODO(ahutter): Add failure tests for EncryptOtp, GetWalletItems,
-// GetFullWallet for when data is missing or invalid.
-
-TEST_F(WalletClientTest, EscrowSensitiveInformationSuccess) {
- MockWalletClientObserver observer;
- EXPECT_CALL(observer, OnDidEscrowSensitiveInformation("abc")).Times(1);
-
- net::TestURLFetcherFactory factory;
-
- scoped_ptr<Instrument> instrument = GetTestInstrument();
- WalletClient wallet_client(profile_.GetRequestContext());
- wallet_client.EscrowSensitiveInformation(*instrument,
- "obfuscated_gaia_id",
- &observer);
- VerifyAndFinishRequest(factory,
- net::HTTP_OK,
- kEscrowSensitiveInformationRequest,
- "abc");
-}
-
-TEST_F(WalletClientTest, EscrowSensitiveInformationFailure) {
- MockWalletClientObserver observer;
- EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
-
- net::TestURLFetcherFactory factory;
- scoped_ptr<Instrument> instrument = GetTestInstrument();
- WalletClient wallet_client(profile_.GetRequestContext());
- wallet_client.EscrowSensitiveInformation(*instrument,
- "obfuscated_gaia_id",
- &observer);
- VerifyAndFinishRequest(factory,
- net::HTTP_OK,
- kEscrowSensitiveInformationRequest,
- std::string());
-}
-
-TEST_F(WalletClientTest, GetFullWallet) {
+TEST_F(WalletClientTest, GetFullWalletSuccess) {
MockWalletClientObserver observer;
net::TestURLFetcherFactory factory;
@@ -562,19 +522,101 @@
"merchant_domain",
cart,
"google_transaction_id",
- "encrypted_otp",
- "session_material",
&observer);
- net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
- ASSERT_TRUE(fetcher);
- EXPECT_EQ(kGetFullWalletValidRequest, GetData(fetcher));
- fetcher->set_response_code(net::HTTP_OK);
- fetcher->SetResponseString(kGetFullWalletValidResponse);
- fetcher->delegate()->OnURLFetchComplete(fetcher);
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString(
+ "session_material|encrypted_one_time_pad");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
+ VerifyAndFinishRequest(factory,
+ net::HTTP_OK,
+ kGetFullWalletValidRequest,
+ kGetFullWalletValidResponse);
EXPECT_EQ(1U, observer.full_wallets_received());
}
+TEST_F(WalletClientTest, GetFullWalletEncryptionDown) {
+ MockWalletClientObserver observer;
+ EXPECT_CALL(observer,
+ OnNetworkError(net::HTTP_INTERNAL_SERVER_ERROR)).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ WalletClient wallet_client(profile_.GetRequestContext());
+ Cart cart("currency_code", "currency_code");
+ wallet_client.GetFullWallet("instrument_id",
+ "shipping_address_id",
+ "merchant_domain",
+ cart,
+ "google_transaction_id",
+ &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_INTERNAL_SERVER_ERROR);
+ encryption_fetcher->SetResponseString(std::string());
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
+ EXPECT_EQ(0U, observer.full_wallets_received());
+}
+
+TEST_F(WalletClientTest, GetFullWalletEncryptionMalformed) {
+ MockWalletClientObserver observer;
+ EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ WalletClient wallet_client(profile_.GetRequestContext());
+ Cart cart("currency_code", "currency_code");
+ wallet_client.GetFullWallet("instrument_id",
+ "shipping_address_id",
+ "merchant_domain",
+ cart,
+ "google_transaction_id",
+ &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString(
+ "session_material:encrypted_one_time_pad");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
+ EXPECT_EQ(0U, observer.full_wallets_received());
+}
+
+TEST_F(WalletClientTest, GetFullWalletMalformedResponse) {
+ MockWalletClientObserver observer;
+ EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ WalletClient wallet_client(profile_.GetRequestContext());
+ Cart cart("currency_code", "currency_code");
+ wallet_client.GetFullWallet("instrument_id",
+ "shipping_address_id",
+ "merchant_domain",
+ cart,
+ "google_transaction_id",
+ &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString(
+ "session_material|encrypted_one_time_pad");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
+ VerifyAndFinishRequest(factory,
+ net::HTTP_OK,
+ kGetFullWalletValidRequest,
+ kGetFullWalletInvalidResponse);
+ EXPECT_EQ(0U, observer.full_wallets_received());
+}
+
TEST_F(WalletClientTest, AcceptLegalDocuments) {
MockWalletClientObserver observer;
EXPECT_CALL(observer, OnDidAcceptLegalDocuments()).Times(1);
@@ -595,6 +637,8 @@
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
+// TODO(ahutter): Add failure tests for GetWalletItems.
+
TEST_F(WalletClientTest, GetWalletItems) {
MockWalletClientObserver observer;
net::TestURLFetcherFactory factory;
@@ -652,13 +696,61 @@
scoped_ptr<Instrument> instrument = GetTestInstrument();
WalletClient wallet_client(profile_.GetRequestContext());
- wallet_client.SaveInstrument(*instrument, "escrow_handle", &observer);
+ wallet_client.SaveInstrument(*instrument, "obfuscated_gaia_id", &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString("escrow_handle");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
VerifyAndFinishRequest(factory,
net::HTTP_OK,
kSaveInstrumentValidRequest,
kSaveInstrumentValidResponse);
}
+TEST_F(WalletClientTest, SaveInstrumentEscrowDown) {
+ MockWalletClientObserver observer;
+ EXPECT_CALL(observer,
+ OnNetworkError(net::HTTP_INTERNAL_SERVER_ERROR)).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ scoped_ptr<Instrument> instrument = GetTestInstrument();
+
+ WalletClient wallet_client(profile_.GetRequestContext());
+ wallet_client.SaveInstrument(*instrument,
+ "obfuscated_gaia_id",
+ &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_INTERNAL_SERVER_ERROR);
+ encryption_fetcher->SetResponseString(std::string());
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+}
+
+TEST_F(WalletClientTest, SaveInstrumentEscrowMalformed) {
+ MockWalletClientObserver observer;
+ EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ scoped_ptr<Instrument> instrument = GetTestInstrument();
+
+ WalletClient wallet_client(profile_.GetRequestContext());
+ wallet_client.SaveInstrument(*instrument,
+ "obfuscated_gaia_id",
+ &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString(std::string());
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+}
+
TEST_F(WalletClientTest, SaveInstrumentFailedMalformedResponse) {
MockWalletClientObserver observer;
EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
@@ -668,7 +760,14 @@
scoped_ptr<Instrument> instrument = GetTestInstrument();
WalletClient wallet_client(profile_.GetRequestContext());
- wallet_client.SaveInstrument(*instrument, "escrow_handle", &observer);
+ wallet_client.SaveInstrument(*instrument, "obfuscated_gaia_id", &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString("escrow_handle");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
VerifyAndFinishRequest(factory,
net::HTTP_OK,
kSaveInstrumentValidRequest,
@@ -689,15 +788,68 @@
WalletClient wallet_client(profile_.GetRequestContext());
wallet_client.SaveInstrumentAndAddress(*instrument,
- "escrow_handle",
*address,
+ "obfuscated_gaia_id",
&observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString("escrow_handle");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
VerifyAndFinishRequest(factory,
net::HTTP_OK,
kSaveInstrumentAndAddressValidRequest,
kSaveInstrumentAndAddressValidResponse);
}
+TEST_F(WalletClientTest, SaveInstrumentAndAddressEscrowDown) {
+ MockWalletClientObserver observer;
+ EXPECT_CALL(observer,
+ OnNetworkError(net::HTTP_INTERNAL_SERVER_ERROR)).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ scoped_ptr<Instrument> instrument = GetTestInstrument();
+
+ scoped_ptr<Address> address = GetTestShippingAddress();
+
+ WalletClient wallet_client(profile_.GetRequestContext());
+ wallet_client.SaveInstrumentAndAddress(*instrument,
+ *address,
+ "obfuscated_gaia_id",
+ &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_INTERNAL_SERVER_ERROR);
+ encryption_fetcher->SetResponseString(std::string());
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+}
+
+TEST_F(WalletClientTest, SaveInstrumentAndAddressEscrowMalformed) {
+ MockWalletClientObserver observer;
+ EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
+
+ net::TestURLFetcherFactory factory;
+
+ scoped_ptr<Instrument> instrument = GetTestInstrument();
+
+ scoped_ptr<Address> address = GetTestShippingAddress();
+
+ WalletClient wallet_client(profile_.GetRequestContext());
+ wallet_client.SaveInstrumentAndAddress(*instrument,
+ *address,
+ "obfuscated_gaia_id",
+ &observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString(std::string());
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+}
+
TEST_F(WalletClientTest, SaveInstrumentAndAddressFailedAddressMissing) {
MockWalletClientObserver observer;
EXPECT_CALL(observer, OnMalformedResponse()).Times(1);
@@ -710,9 +862,16 @@
WalletClient wallet_client(profile_.GetRequestContext());
wallet_client.SaveInstrumentAndAddress(*instrument,
- "escrow_handle",
*address,
+ "obfuscated_gaia_id",
&observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString("escrow_handle");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
VerifyAndFinishRequest(factory,
net::HTTP_OK,
kSaveInstrumentAndAddressValidRequest,
@@ -731,9 +890,16 @@
WalletClient wallet_client(profile_.GetRequestContext());
wallet_client.SaveInstrumentAndAddress(*instrument,
- "escrow_handle",
*address,
+ "obfuscated_gaia_id",
&observer);
+
+ net::TestURLFetcher* encryption_fetcher = factory.GetFetcherByID(1);
+ ASSERT_TRUE(encryption_fetcher);
+ encryption_fetcher->set_response_code(net::HTTP_OK);
+ encryption_fetcher->SetResponseString("escrow_handle");
+ encryption_fetcher->delegate()->OnURLFetchComplete(encryption_fetcher);
+
VerifyAndFinishRequest(factory,
net::HTTP_OK,
kSaveInstrumentAndAddressValidRequest,
@@ -831,4 +997,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_items.cc b/chrome/browser/autofill/wallet/wallet_items.cc
index 9a89478e..d5a4273 100644
--- a/chrome/browser/autofill/wallet/wallet_items.cc
+++ b/chrome/browser/autofill/wallet/wallet_items.cc
@@ -8,51 +8,52 @@
#include "base/values.h"
#include "googleurl/src/gurl.h"
+namespace autofill {
+namespace wallet {
+
namespace {
const char kLegalDocumentUrl[] =
"https://wallet.google.com/customer/gadget/legaldocument.html?docId=";
-wallet::WalletItems::MaskedInstrument::Type
+WalletItems::MaskedInstrument::Type
TypeFromString(const std::string& type_string) {
if (type_string == "VISA")
- return wallet::WalletItems::MaskedInstrument::VISA;
+ return WalletItems::MaskedInstrument::VISA;
if (type_string == "MASTER_CARD")
- return wallet::WalletItems::MaskedInstrument::MASTER_CARD;
+ return WalletItems::MaskedInstrument::MASTER_CARD;
if (type_string == "AMEX")
- return wallet::WalletItems::MaskedInstrument::AMEX;
+ return WalletItems::MaskedInstrument::AMEX;
if (type_string == "DISCOVER")
- return wallet::WalletItems::MaskedInstrument::DISCOVER;
+ return WalletItems::MaskedInstrument::DISCOVER;
if (type_string == "SOLO")
- return wallet::WalletItems::MaskedInstrument::SOLO;
+ return WalletItems::MaskedInstrument::SOLO;
if (type_string == "MAESTRO")
- return wallet::WalletItems::MaskedInstrument::MAESTRO;
+ return WalletItems::MaskedInstrument::MAESTRO;
if (type_string == "SWITCH")
- return wallet::WalletItems::MaskedInstrument::SWITCH;
- return wallet::WalletItems::MaskedInstrument::UNKNOWN;
+ return WalletItems::MaskedInstrument::SWITCH;
+ return WalletItems::MaskedInstrument::UNKNOWN;
}
-wallet::WalletItems::MaskedInstrument::Status
+WalletItems::MaskedInstrument::Status
StatusFromString(const std::string& status_string) {
if (status_string == "PENDING")
- return wallet::WalletItems::MaskedInstrument::PENDING;
+ return WalletItems::MaskedInstrument::PENDING;
if (status_string == "VALID")
- return wallet::WalletItems::MaskedInstrument::VALID;
+ return WalletItems::MaskedInstrument::VALID;
if (status_string == "DECLINED")
- return wallet::WalletItems::MaskedInstrument::DECLINED;
+ return WalletItems::MaskedInstrument::DECLINED;
if (status_string == "UNSUPPORTED_COUNTRY")
- return wallet::WalletItems::MaskedInstrument::UNSUPPORTED_COUNTRY;
+ return WalletItems::MaskedInstrument::UNSUPPORTED_COUNTRY;
if (status_string == "EXPIRED")
- return wallet::WalletItems::MaskedInstrument::EXPIRED;
+ return WalletItems::MaskedInstrument::EXPIRED;
if (status_string == "BILLING_INCOMPLETE")
- return wallet::WalletItems::MaskedInstrument::BILLING_INCOMPLETE;
- return wallet::WalletItems::MaskedInstrument::INAPPLICABLE;
+ return WalletItems::MaskedInstrument::BILLING_INCOMPLETE;
+ return WalletItems::MaskedInstrument::INAPPLICABLE;
}
} // anonymous namespace
-namespace wallet {
-
WalletItems::MaskedInstrument::MaskedInstrument(
const string16& descriptive_name,
const WalletItems::MaskedInstrument::Type& type,
@@ -362,4 +363,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_items.h b/chrome/browser/autofill/wallet/wallet_items.h
index ed5130db..442f1b2 100644
--- a/chrome/browser/autofill/wallet/wallet_items.h
+++ b/chrome/browser/autofill/wallet/wallet_items.h
@@ -23,6 +23,7 @@
class DictionaryValue;
}
+namespace autofill {
namespace wallet {
class WalletItemsTest;
@@ -244,6 +245,6 @@
};
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_WALLET_ITEMS_H_
-
diff --git a/chrome/browser/autofill/wallet/wallet_items_unittest.cc b/chrome/browser/autofill/wallet/wallet_items_unittest.cc
index 1e585ef..e52040b 100644
--- a/chrome/browser/autofill/wallet/wallet_items_unittest.cc
+++ b/chrome/browser/autofill/wallet/wallet_items_unittest.cc
@@ -345,6 +345,7 @@
} // anonymous namespace
+namespace autofill {
namespace wallet {
class WalletItemsTest : public testing::Test {
@@ -536,4 +537,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_service_url.cc b/chrome/browser/autofill/wallet/wallet_service_url.cc
index 4a1bdad..c72feabd 100644
--- a/chrome/browser/autofill/wallet/wallet_service_url.cc
+++ b/chrome/browser/autofill/wallet/wallet_service_url.cc
@@ -42,6 +42,7 @@
} // anonymous namespace
+namespace autofill {
namespace wallet {
GURL GetGetWalletItemsUrl() {
@@ -99,3 +100,4 @@
}
} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_service_url.h b/chrome/browser/autofill/wallet/wallet_service_url.h
index 52f8a3e..fa4ac45 100644
--- a/chrome/browser/autofill/wallet/wallet_service_url.h
+++ b/chrome/browser/autofill/wallet/wallet_service_url.h
@@ -7,6 +7,7 @@
class GURL;
+namespace autofill {
namespace wallet {
GURL GetGetWalletItemsUrl();
@@ -28,7 +29,8 @@
// Returns true if |url| is an acceptable variant of the sign-in continue
// url. Can be used for detection of navigation to the continue url.
bool IsSignInContinueUrl(const GURL& url);
+
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_WALLET_SERVICE_URL_H_
-
diff --git a/chrome/browser/autofill/wallet/wallet_service_url_unittest.cc b/chrome/browser/autofill/wallet/wallet_service_url_unittest.cc
index 7f60980..3108a8d 100644
--- a/chrome/browser/autofill/wallet/wallet_service_url_unittest.cc
+++ b/chrome/browser/autofill/wallet/wallet_service_url_unittest.cc
@@ -6,6 +6,7 @@
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace autofill {
namespace wallet {
TEST(WalletServiceUrl, CheckDefaultUrls) {
@@ -33,4 +34,4 @@
}
} // namespace wallet
-
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_test_util.cc b/chrome/browser/autofill/wallet/wallet_test_util.cc
index 4ff4ee9..6b729b6c 100644
--- a/chrome/browser/autofill/wallet/wallet_test_util.cc
+++ b/chrome/browser/autofill/wallet/wallet_test_util.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/autofill/wallet/instrument.h"
#include "chrome/browser/autofill/wallet/wallet_address.h"
+namespace autofill {
namespace wallet {
scoped_ptr<Instrument> GetTestInstrument() {
@@ -45,3 +46,4 @@
}
} // namespace wallet
+} // namespace autofill
diff --git a/chrome/browser/autofill/wallet/wallet_test_util.h b/chrome/browser/autofill/wallet/wallet_test_util.h
index 1f18b95..5075657 100644
--- a/chrome/browser/autofill/wallet/wallet_test_util.h
+++ b/chrome/browser/autofill/wallet/wallet_test_util.h
@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h"
+namespace autofill {
namespace wallet {
class Instrument;
@@ -17,5 +18,6 @@
scoped_ptr<Address> GetTestAddress();
} // namespace wallet
+} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_WALLET_WALLET_TEST_UTIL_H_
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 41dcd3a7..a30732d 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -790,17 +790,6 @@
NOTIMPLEMENTED();
}
-void AutofillDialogControllerImpl::OnDidEncryptOtp(
- const std::string& encrypted_otp, const std::string& session_material) {
- NOTIMPLEMENTED() << " encrypted_otp=" << encrypted_otp
- << ", session_material=" << session_material;
-}
-
-void AutofillDialogControllerImpl::OnDidEscrowSensitiveInformation(
- const std::string& escrow_handle) {
- NOTIMPLEMENTED() << " escrow_handle=" << escrow_handle;
-}
-
void AutofillDialogControllerImpl::OnDidGetFullWallet(
scoped_ptr<wallet::FullWallet> full_wallet) {
NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
index dddda71d..398b214 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -136,10 +136,6 @@
// wallet::WalletClientObserver implementation.
virtual void OnDidAcceptLegalDocuments() OVERRIDE;
- virtual void OnDidEncryptOtp(const std::string& encrypted_otp,
- const std::string& session_material) OVERRIDE;
- virtual void OnDidEscrowSensitiveInformation(
- const std::string& escrow_handle) OVERRIDE;
virtual void OnDidGetFullWallet(
scoped_ptr<wallet::FullWallet> full_wallet) OVERRIDE;
virtual void OnDidGetWalletItems(
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index e1a9754..4a776a4 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -257,6 +257,9 @@
'browser/autofill/validation.h',
'browser/autofill/wallet/cart.cc',
'browser/autofill/wallet/cart.h',
+ 'browser/autofill/wallet/encryption_escrow_client.cc',
+ 'browser/autofill/wallet/encryption_escrow_client.h',
+ 'browser/autofill/wallet/encryption_escrow_client_observer.h',
'browser/autofill/wallet/full_wallet.cc',
'browser/autofill/wallet/full_wallet.h',
'browser/autofill/wallet/instrument.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 42058876..a10febd 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -497,6 +497,7 @@
'browser/autofill/phone_number_i18n_unittest.cc',
'browser/autofill/validation_unittest.cc',
'browser/autofill/wallet/cart_unittest.cc',
+ 'browser/autofill/wallet/encryption_escrow_client_unittest.cc',
'browser/autofill/wallet/full_wallet_unittest.cc',
'browser/autofill/wallet/instrument_unittest.cc',
'browser/autofill/wallet/wallet_address_unittest.cc',