• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/autofill/content/browser/wallet/wallet_client.h"
6 
7 #include "base/bind.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "components/autofill/content/browser/wallet/form_field_error.h"
18 #include "components/autofill/content/browser/wallet/instrument.h"
19 #include "components/autofill/content/browser/wallet/wallet_address.h"
20 #include "components/autofill/content/browser/wallet/wallet_client_delegate.h"
21 #include "components/autofill/content/browser/wallet/wallet_items.h"
22 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
23 #include "components/autofill/core/browser/autofill_metrics.h"
24 #include "crypto/random.h"
25 #include "google_apis/google_api_keys.h"
26 #include "net/base/escape.h"
27 #include "net/http/http_status_code.h"
28 #include "net/url_request/url_fetcher.h"
29 #include "net/url_request/url_request_context_getter.h"
30 
31 namespace autofill {
32 namespace wallet {
33 
34 namespace {
35 
36 const char kFormEncodedMimeType[] = "application/x-www-form-urlencoded";
37 const char kJsonMimeType[] = "application/json";
38 const char kEscrowNewInstrumentFormat[] =
39     "request_content_type=application/json&request=%s&cvn=%s&card_number=%s";
40 const char kEscrowCardVerificationNumberFormat[] =
41     "request_content_type=application/json&request=%s&cvn=%s";
42 const char kGetFullWalletRequestFormat[] =
43     "request_content_type=application/json&request=%s&otp=%s:%s";
44 const size_t kOneTimePadLength = 6;
45 
46 // The maximum number of bits in the one time pad that the server is willing to
47 // accept.
48 const size_t kMaxBits = 56;
49 
50 // The minimum number of bits in the one time pad that the server is willing to
51 // accept.
52 const size_t kMinBits = 40;
53 
RiskCapabilityToString(WalletClient::RiskCapability risk_capability)54 std::string RiskCapabilityToString(
55     WalletClient::RiskCapability risk_capability) {
56   switch (risk_capability) {
57     case WalletClient::RELOGIN:
58       return "RELOGIN";
59     case WalletClient::VERIFY_CVC:
60       return "VERIFY_CVC";
61   }
62   NOTREACHED();
63   return "NOT_POSSIBLE";
64 }
65 
StringToErrorType(const std::string & error_type)66 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
67   std::string trimmed;
68   base::TrimWhitespaceASCII(error_type, base::TRIM_ALL, &trimmed);
69   if (LowerCaseEqualsASCII(trimmed, "buyer_account_error"))
70     return WalletClient::BUYER_ACCOUNT_ERROR;
71   if (LowerCaseEqualsASCII(trimmed, "unsupported_merchant"))
72     return WalletClient::UNSUPPORTED_MERCHANT;
73   if (LowerCaseEqualsASCII(trimmed, "internal_error"))
74     return WalletClient::INTERNAL_ERROR;
75   if (LowerCaseEqualsASCII(trimmed, "invalid_params"))
76     return WalletClient::INVALID_PARAMS;
77   if (LowerCaseEqualsASCII(trimmed, "service_unavailable"))
78     return WalletClient::SERVICE_UNAVAILABLE;
79   if (LowerCaseEqualsASCII(trimmed, "unsupported_api_version"))
80     return WalletClient::UNSUPPORTED_API_VERSION;
81   if (LowerCaseEqualsASCII(trimmed, "unsupported_user_agent"))
82     return WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY;
83   if (LowerCaseEqualsASCII(trimmed, "spending_limit_exceeded"))
84     return WalletClient::SPENDING_LIMIT_EXCEEDED;
85 
86   DVLOG(1) << "Unknown wallet error string: \"" << error_type << '"';
87   return WalletClient::UNKNOWN_ERROR;
88 }
89 
90 // Get the more specific WalletClient::ErrorType when the error is
91 // |BUYER_ACCOUNT_ERROR|.
BuyerErrorStringToErrorType(const std::string & message_type_for_buyer)92 WalletClient::ErrorType BuyerErrorStringToErrorType(
93     const std::string& message_type_for_buyer) {
94   std::string trimmed;
95   base::TrimWhitespaceASCII(message_type_for_buyer, base::TRIM_ALL, &trimmed);
96   if (LowerCaseEqualsASCII(trimmed, "bla_country_not_supported"))
97     return WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
98   if (LowerCaseEqualsASCII(trimmed, "buyer_kyc_error"))
99     return WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
100 
101   return WalletClient::BUYER_ACCOUNT_ERROR;
102 }
103 
104 // Gets and parses required actions from a SaveToWallet response. Returns
105 // false if any unknown required actions are seen and true otherwise.
GetRequiredActionsForSaveToWallet(const base::DictionaryValue & dict,std::vector<RequiredAction> * required_actions)106 void GetRequiredActionsForSaveToWallet(
107     const base::DictionaryValue& dict,
108     std::vector<RequiredAction>* required_actions) {
109   const base::ListValue* required_action_list;
110   if (!dict.GetList("required_action", &required_action_list))
111     return;
112 
113   for (size_t i = 0; i < required_action_list->GetSize(); ++i) {
114     std::string action_string;
115     if (required_action_list->GetString(i, &action_string)) {
116       RequiredAction action = ParseRequiredActionFromString(action_string);
117       if (!ActionAppliesToSaveToWallet(action)) {
118         DLOG(ERROR) << "Response from Google wallet with bad required action:"
119                        " \"" << action_string << "\"";
120         required_actions->clear();
121         return;
122       }
123       required_actions->push_back(action);
124     }
125   }
126 }
127 
GetFormFieldErrors(const base::DictionaryValue & dict,std::vector<FormFieldError> * form_errors)128 void GetFormFieldErrors(const base::DictionaryValue& dict,
129                         std::vector<FormFieldError>* form_errors) {
130   DCHECK(form_errors->empty());
131   const base::ListValue* form_errors_list;
132   if (!dict.GetList("form_field_error", &form_errors_list))
133     return;
134 
135   for (size_t i = 0; i < form_errors_list->GetSize(); ++i) {
136     const base::DictionaryValue* dictionary;
137     if (form_errors_list->GetDictionary(i, &dictionary))
138       form_errors->push_back(FormFieldError::CreateFormFieldError(*dictionary));
139   }
140 }
141 
142 // Converts the |error_type| to the corresponding value from the stable UMA
143 // metric enumeration.
ErrorTypeToUmaMetric(WalletClient::ErrorType error_type)144 AutofillMetrics::WalletErrorMetric ErrorTypeToUmaMetric(
145     WalletClient::ErrorType error_type) {
146   switch (error_type) {
147     case WalletClient::BAD_REQUEST:
148       return AutofillMetrics::WALLET_BAD_REQUEST;
149     case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
150       return AutofillMetrics::WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
151     case WalletClient::BUYER_ACCOUNT_ERROR:
152       return AutofillMetrics::WALLET_BUYER_ACCOUNT_ERROR;
153     case WalletClient::INTERNAL_ERROR:
154       return AutofillMetrics::WALLET_INTERNAL_ERROR;
155     case WalletClient::INVALID_PARAMS:
156       return AutofillMetrics::WALLET_INVALID_PARAMS;
157     case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
158       return AutofillMetrics::WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
159     case WalletClient::SERVICE_UNAVAILABLE:
160       return AutofillMetrics::WALLET_SERVICE_UNAVAILABLE;
161     case WalletClient::UNSUPPORTED_API_VERSION:
162       return AutofillMetrics::WALLET_UNSUPPORTED_API_VERSION;
163     case WalletClient::UNSUPPORTED_MERCHANT:
164       return AutofillMetrics::WALLET_UNSUPPORTED_MERCHANT;
165     case WalletClient::SPENDING_LIMIT_EXCEEDED:
166       return AutofillMetrics::WALLET_SPENDING_LIMIT_EXCEEDED;
167     case WalletClient::MALFORMED_RESPONSE:
168       return AutofillMetrics::WALLET_MALFORMED_RESPONSE;
169     case WalletClient::NETWORK_ERROR:
170       return AutofillMetrics::WALLET_NETWORK_ERROR;
171     case WalletClient::UNKNOWN_ERROR:
172       return AutofillMetrics::WALLET_UNKNOWN_ERROR;
173     case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
174       return AutofillMetrics::WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY;
175   }
176 
177   NOTREACHED();
178   return AutofillMetrics::WALLET_UNKNOWN_ERROR;
179 }
180 
181 // Converts the |required_action| to the corresponding value from the stable UMA
182 // metric enumeration.
RequiredActionToUmaMetric(RequiredAction required_action)183 AutofillMetrics::WalletRequiredActionMetric RequiredActionToUmaMetric(
184     RequiredAction required_action) {
185   switch (required_action) {
186     case UNKNOWN_TYPE:
187       return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
188     case CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
189       return AutofillMetrics::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS;
190     case SETUP_WALLET:
191       return AutofillMetrics::SETUP_WALLET;
192     case ACCEPT_TOS:
193       return AutofillMetrics::ACCEPT_TOS;
194     case GAIA_AUTH:
195       return AutofillMetrics::GAIA_AUTH;
196     case UPDATE_EXPIRATION_DATE:
197       return AutofillMetrics::UPDATE_EXPIRATION_DATE;
198     case UPGRADE_MIN_ADDRESS:
199       return AutofillMetrics::UPGRADE_MIN_ADDRESS;
200     case INVALID_FORM_FIELD:
201       return AutofillMetrics::INVALID_FORM_FIELD;
202     case VERIFY_CVV:
203       return AutofillMetrics::VERIFY_CVV;
204     case PASSIVE_GAIA_AUTH:
205       return AutofillMetrics::PASSIVE_GAIA_AUTH;
206     case REQUIRE_PHONE_NUMBER:
207       return AutofillMetrics::REQUIRE_PHONE_NUMBER;
208   }
209 
210   NOTREACHED();
211   return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
212 }
213 
214 // Keys for JSON communication with the Online Wallet server.
215 const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
216 const char kApiKeyKey[] = "api_key";
217 const char kAuthResultKey[] = "auth_result";
218 const char kErrorTypeKey[] = "wallet_error.error_type";
219 const char kFeatureKey[] = "feature";
220 const char kGoogleTransactionIdKey[] = "google_transaction_id";
221 const char kInstrumentIdKey[] = "instrument_id";
222 const char kInstrumentKey[] = "instrument";
223 const char kInstrumentExpMonthKey[] = "instrument.credit_card.exp_month";
224 const char kInstrumentExpYearKey[] = "instrument.credit_card.exp_year";
225 const char kInstrumentType[] = "instrument.type";
226 const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
227 const char kMerchantDomainKey[] = "merchant_domain";
228 const char kMessageTypeForBuyerKey[] = "wallet_error.message_type_for_buyer";
229 const char kNewWalletUser[] = "new_wallet_user";
230 const char kPhoneNumberRequired[] = "phone_number_required";
231 const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
232 const char kRiskParamsKey[] = "risk_params";
233 const char kSelectedAddressIdKey[] = "selected_address_id";
234 const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
235 const char kShippingAddressIdKey[] = "shipping_address_id";
236 const char kShippingAddressKey[] = "shipping_address";
237 const char kShippingAddressRequired[] = "shipping_address_required";
238 const char kTransactionAmountKey[] = "estimated_total_price";
239 const char kTransactionCurrencyKey[] = "currency_code";
240 const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
241 const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
242 const char kUseMinimalAddresses[] = "use_minimal_addresses";
243 
244 }  // namespace
245 
FullWalletRequest(const std::string & instrument_id,const std::string & address_id,const std::string & google_transaction_id,const std::vector<RiskCapability> risk_capabilities,bool new_wallet_user)246 WalletClient::FullWalletRequest::FullWalletRequest(
247     const std::string& instrument_id,
248     const std::string& address_id,
249     const std::string& google_transaction_id,
250     const std::vector<RiskCapability> risk_capabilities,
251     bool new_wallet_user)
252     : instrument_id(instrument_id),
253       address_id(address_id),
254       google_transaction_id(google_transaction_id),
255       risk_capabilities(risk_capabilities),
256       new_wallet_user(new_wallet_user) {}
257 
~FullWalletRequest()258 WalletClient::FullWalletRequest::~FullWalletRequest() {}
259 
WalletClient(net::URLRequestContextGetter * context_getter,WalletClientDelegate * delegate,const GURL & source_url)260 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter,
261                            WalletClientDelegate* delegate,
262                            const GURL& source_url)
263     : context_getter_(context_getter),
264       delegate_(delegate),
265       user_index_(0U),
266       source_url_(source_url),
267       request_type_(NO_REQUEST),
268       one_time_pad_(kOneTimePadLength),
269       weak_ptr_factory_(this) {
270   DCHECK(context_getter_.get());
271   DCHECK(delegate_);
272 }
273 
~WalletClient()274 WalletClient::~WalletClient() {}
275 
AcceptLegalDocuments(const std::vector<WalletItems::LegalDocument * > & documents,const std::string & google_transaction_id)276 void WalletClient::AcceptLegalDocuments(
277     const std::vector<WalletItems::LegalDocument*>& documents,
278     const std::string& google_transaction_id) {
279   if (documents.empty())
280     return;
281 
282   std::vector<std::string> document_ids;
283   for (size_t i = 0; i < documents.size(); ++i) {
284     document_ids.push_back(documents[i]->id());
285   }
286   DoAcceptLegalDocuments(document_ids, google_transaction_id);
287 }
288 
AuthenticateInstrument(const std::string & instrument_id,const std::string & card_verification_number)289 void WalletClient::AuthenticateInstrument(
290     const std::string& instrument_id,
291     const std::string& card_verification_number) {
292   base::DictionaryValue request_dict;
293   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
294   request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
295   request_dict.SetString(kInstrumentIdKey, instrument_id);
296 
297   std::string json_payload;
298   base::JSONWriter::Write(&request_dict, &json_payload);
299 
300   std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
301       card_verification_number, true);
302 
303   std::string post_body = base::StringPrintf(
304       kEscrowCardVerificationNumberFormat,
305       net::EscapeUrlEncodedData(json_payload, true).c_str(),
306       escaped_card_verification_number.c_str());
307 
308   MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
309                     post_body,
310                     kFormEncodedMimeType,
311                     AUTHENTICATE_INSTRUMENT);
312 }
313 
GetFullWallet(const FullWalletRequest & full_wallet_request)314 void WalletClient::GetFullWallet(const FullWalletRequest& full_wallet_request) {
315   base::DictionaryValue request_dict;
316   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
317   request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
318   request_dict.SetBoolean(kUseMinimalAddresses, false);
319   request_dict.SetBoolean(kPhoneNumberRequired, true);
320   request_dict.SetBoolean(kNewWalletUser, full_wallet_request.new_wallet_user);
321 
322   request_dict.SetString(kSelectedInstrumentIdKey,
323                          full_wallet_request.instrument_id);
324   request_dict.SetString(kSelectedAddressIdKey, full_wallet_request.address_id);
325   request_dict.SetString(
326       kMerchantDomainKey,
327       source_url_.GetWithEmptyPath().spec());
328   request_dict.SetString(kGoogleTransactionIdKey,
329                          full_wallet_request.google_transaction_id);
330   request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
331 
332   scoped_ptr<base::ListValue> risk_capabilities_list(new base::ListValue());
333   for (std::vector<RiskCapability>::const_iterator it =
334            full_wallet_request.risk_capabilities.begin();
335        it != full_wallet_request.risk_capabilities.end();
336        ++it) {
337     risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
338   }
339   request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
340 
341   std::string json_payload;
342   base::JSONWriter::Write(&request_dict, &json_payload);
343 
344   crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
345 
346   size_t num_bits = one_time_pad_.size() * 8;
347   DCHECK_LE(num_bits, kMaxBits);
348   DCHECK_GE(num_bits, kMinBits);
349 
350   std::string post_body = base::StringPrintf(
351       kGetFullWalletRequestFormat,
352       net::EscapeUrlEncodedData(json_payload, true).c_str(),
353       base::HexEncode(&num_bits, 1).c_str(),
354       base::HexEncode(&(one_time_pad_[0]), one_time_pad_.size()).c_str());
355 
356   MakeWalletRequest(GetGetFullWalletUrl(user_index_),
357                     post_body,
358                     kFormEncodedMimeType,
359                     GET_FULL_WALLET);
360 }
361 
SaveToWallet(scoped_ptr<Instrument> instrument,scoped_ptr<Address> address,const WalletItems::MaskedInstrument * reference_instrument,const Address * reference_address)362 void WalletClient::SaveToWallet(
363     scoped_ptr<Instrument> instrument,
364     scoped_ptr<Address> address,
365     const WalletItems::MaskedInstrument* reference_instrument,
366     const Address* reference_address) {
367   DCHECK(instrument || address);
368 
369   base::DictionaryValue request_dict;
370   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
371   request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
372   request_dict.SetString(kMerchantDomainKey,
373                          source_url_.GetWithEmptyPath().spec());
374   request_dict.SetBoolean(kUseMinimalAddresses, false);
375   request_dict.SetBoolean(kPhoneNumberRequired, true);
376 
377   std::string primary_account_number;
378   std::string card_verification_number;
379   if (instrument) {
380     primary_account_number = net::EscapeUrlEncodedData(
381         base::UTF16ToUTF8(instrument->primary_account_number()), true);
382     card_verification_number = net::EscapeUrlEncodedData(
383         base::UTF16ToUTF8(instrument->card_verification_number()), true);
384 
385     if (!reference_instrument) {
386       request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
387       request_dict.SetString(kInstrumentPhoneNumberKey,
388                              instrument->address()->phone_number());
389     } else {
390       DCHECK(!reference_instrument->object_id().empty());
391 
392       int new_month = instrument->expiration_month();
393       int new_year = instrument->expiration_year();
394       bool expiration_date_changed =
395           new_month != reference_instrument->expiration_month() ||
396           new_year != reference_instrument->expiration_year();
397 
398       DCHECK(instrument->address() || expiration_date_changed);
399 
400       request_dict.SetString(kUpgradedInstrumentIdKey,
401                              reference_instrument->object_id());
402 
403       if (instrument->address()) {
404         request_dict.SetString(kInstrumentPhoneNumberKey,
405                                instrument->address()->phone_number());
406         request_dict.Set(
407             kUpgradedBillingAddressKey,
408             instrument->address()->ToDictionaryWithoutID().release());
409       }
410 
411       if (expiration_date_changed) {
412         // Updating expiration date requires a CVC.
413         DCHECK(!instrument->card_verification_number().empty());
414         request_dict.SetInteger(kInstrumentExpMonthKey,
415                                 instrument->expiration_month());
416         request_dict.SetInteger(kInstrumentExpYearKey,
417                                 instrument->expiration_year());
418       }
419 
420       if (request_dict.HasKey(kInstrumentKey))
421         request_dict.SetString(kInstrumentType, "CREDIT_CARD");
422     }
423   }
424   if (address) {
425     if (reference_address) {
426       address->set_object_id(reference_address->object_id());
427       DCHECK(!address->object_id().empty());
428     }
429     request_dict.Set(kShippingAddressKey,
430                      address->ToDictionaryWithID().release());
431   }
432 
433   std::string json_payload;
434   base::JSONWriter::Write(&request_dict, &json_payload);
435 
436   if (!card_verification_number.empty()) {
437     std::string post_body;
438     if (!primary_account_number.empty()) {
439       post_body = base::StringPrintf(
440           kEscrowNewInstrumentFormat,
441           net::EscapeUrlEncodedData(json_payload, true).c_str(),
442           card_verification_number.c_str(),
443           primary_account_number.c_str());
444     } else {
445       post_body = base::StringPrintf(
446           kEscrowCardVerificationNumberFormat,
447           net::EscapeUrlEncodedData(json_payload, true).c_str(),
448           card_verification_number.c_str());
449     }
450     MakeWalletRequest(GetSaveToWalletUrl(user_index_),
451                       post_body,
452                       kFormEncodedMimeType,
453                       SAVE_TO_WALLET);
454   } else {
455     MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
456                       json_payload,
457                       kJsonMimeType,
458                       SAVE_TO_WALLET);
459   }
460 }
461 
GetWalletItems(const base::string16 & amount,const base::string16 & currency)462 void WalletClient::GetWalletItems(const base::string16& amount,
463                                   const base::string16& currency) {
464   base::DictionaryValue request_dict;
465   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
466   request_dict.SetString(kMerchantDomainKey,
467                          source_url_.GetWithEmptyPath().spec());
468   request_dict.SetBoolean(kShippingAddressRequired,
469                           delegate_->IsShippingAddressRequired());
470   request_dict.SetBoolean(kUseMinimalAddresses, false);
471   request_dict.SetBoolean(kPhoneNumberRequired, true);
472 
473   if (!amount.empty())
474     request_dict.SetString(kTransactionAmountKey, amount);
475   if (!currency.empty())
476     request_dict.SetString(kTransactionCurrencyKey, currency);
477 
478   std::string post_body;
479   base::JSONWriter::Write(&request_dict, &post_body);
480 
481   MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
482                     post_body,
483                     kJsonMimeType,
484                     GET_WALLET_ITEMS);
485 }
486 
HasRequestInProgress() const487 bool WalletClient::HasRequestInProgress() const {
488   return request_;
489 }
490 
CancelRequest()491 void WalletClient::CancelRequest() {
492   request_.reset();
493   request_type_ = NO_REQUEST;
494 }
495 
SetUserIndex(size_t user_index)496 void WalletClient::SetUserIndex(size_t user_index) {
497   CancelRequest();
498   user_index_ = user_index;
499 }
500 
DoAcceptLegalDocuments(const std::vector<std::string> & document_ids,const std::string & google_transaction_id)501 void WalletClient::DoAcceptLegalDocuments(
502     const std::vector<std::string>& document_ids,
503     const std::string& google_transaction_id) {
504   base::DictionaryValue request_dict;
505   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
506   request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
507   request_dict.SetString(kMerchantDomainKey,
508                          source_url_.GetWithEmptyPath().spec());
509   scoped_ptr<base::ListValue> docs_list(new base::ListValue());
510   for (std::vector<std::string>::const_iterator it = document_ids.begin();
511        it != document_ids.end(); ++it) {
512     if (!it->empty())
513       docs_list->AppendString(*it);
514   }
515   request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
516 
517   std::string post_body;
518   base::JSONWriter::Write(&request_dict, &post_body);
519 
520   MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
521                     post_body,
522                     kJsonMimeType,
523                     ACCEPT_LEGAL_DOCUMENTS);
524 }
525 
MakeWalletRequest(const GURL & url,const std::string & post_body,const std::string & mime_type,RequestType request_type)526 void WalletClient::MakeWalletRequest(const GURL& url,
527                                      const std::string& post_body,
528                                      const std::string& mime_type,
529                                      RequestType request_type) {
530   DCHECK_EQ(request_type_, NO_REQUEST);
531   request_type_ = request_type;
532 
533   request_.reset(net::URLFetcher::Create(
534       0, url, net::URLFetcher::POST, this));
535   request_->SetRequestContext(context_getter_.get());
536   DVLOG(1) << "Making request to " << url << " with post_body=" << post_body;
537   request_->SetUploadData(mime_type, post_body);
538   request_->AddExtraRequestHeader("Authorization: GoogleLogin auth=" +
539                                   delegate_->GetWalletCookieValue());
540   DVLOG(1) << "Setting authorization header value to "
541            << delegate_->GetWalletCookieValue();
542   request_started_timestamp_ = base::Time::Now();
543   request_->Start();
544 
545   delegate_->GetMetricLogger().LogWalletErrorMetric(
546       AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
547   delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
548       AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
549 }
550 
551 // TODO(ahutter): Add manual retry logic if it's necessary.
OnURLFetchComplete(const net::URLFetcher * source)552 void WalletClient::OnURLFetchComplete(
553     const net::URLFetcher* source) {
554   delegate_->GetMetricLogger().LogWalletApiCallDuration(
555       RequestTypeToUmaMetric(request_type_),
556       base::Time::Now() - request_started_timestamp_);
557 
558   DCHECK_EQ(source, request_.get());
559   DVLOG(1) << "Got response from " << source->GetOriginalURL();
560 
561   // |request_|, which is aliased to |source|, might continue to be used in this
562   // |method, but should be freed once control leaves the method.
563   scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
564 
565   std::string data;
566   source->GetResponseAsString(&data);
567   DVLOG(1) << "Response body: " << data;
568 
569   scoped_ptr<base::DictionaryValue> response_dict;
570 
571   int response_code = source->GetResponseCode();
572   delegate_->GetMetricLogger().LogWalletResponseCode(response_code);
573 
574   switch (response_code) {
575     // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
576     case net::HTTP_BAD_REQUEST: {
577       request_type_ = NO_REQUEST;
578       HandleWalletError(BAD_REQUEST);
579       return;
580     }
581 
582     // Valid response.
583     case net::HTTP_OK: {
584       scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
585       if (message_value.get() &&
586           message_value->IsType(base::Value::TYPE_DICTIONARY)) {
587         response_dict.reset(
588             static_cast<base::DictionaryValue*>(message_value.release()));
589       }
590       break;
591     }
592 
593     // Response contains an error to show the user.
594     case net::HTTP_FORBIDDEN:
595     case net::HTTP_INTERNAL_SERVER_ERROR: {
596       scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
597       if (message_value.get() &&
598           message_value->IsType(base::Value::TYPE_DICTIONARY)) {
599         response_dict.reset(
600             static_cast<base::DictionaryValue*>(message_value.release()));
601       }
602 
603       request_type_ = NO_REQUEST;
604 
605       std::string error_type_string;
606       if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
607         HandleWalletError(UNKNOWN_ERROR);
608         return;
609       }
610       WalletClient::ErrorType error_type = StringToErrorType(error_type_string);
611       if (error_type == BUYER_ACCOUNT_ERROR) {
612         // If the error_type is |BUYER_ACCOUNT_ERROR|, then
613         // message_type_for_buyer field contains more specific information
614         // about the error.
615         std::string message_type_for_buyer_string;
616         if (response_dict->GetString(kMessageTypeForBuyerKey,
617                                      &message_type_for_buyer_string)) {
618           error_type =
619               BuyerErrorStringToErrorType(message_type_for_buyer_string);
620         }
621       }
622 
623       HandleWalletError(error_type);
624       return;
625     }
626 
627     // Handle anything else as a generic error.
628     default:
629       request_type_ = NO_REQUEST;
630       HandleWalletError(NETWORK_ERROR);
631       return;
632   }
633 
634   RequestType type = request_type_;
635   request_type_ = NO_REQUEST;
636 
637   if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
638     HandleMalformedResponse(type, scoped_request.get());
639     return;
640   }
641 
642   switch (type) {
643     case ACCEPT_LEGAL_DOCUMENTS:
644       delegate_->OnDidAcceptLegalDocuments();
645       break;
646 
647     case AUTHENTICATE_INSTRUMENT: {
648       std::string auth_result;
649       if (response_dict->GetString(kAuthResultKey, &auth_result)) {
650         std::string trimmed;
651         base::TrimWhitespaceASCII(auth_result, base::TRIM_ALL, &trimmed);
652         delegate_->OnDidAuthenticateInstrument(
653             LowerCaseEqualsASCII(trimmed, "success"));
654       } else {
655         HandleMalformedResponse(type, scoped_request.get());
656       }
657       break;
658     }
659 
660     case GET_FULL_WALLET: {
661       scoped_ptr<FullWallet> full_wallet(
662           FullWallet::CreateFullWallet(*response_dict));
663       if (full_wallet) {
664         full_wallet->set_one_time_pad(one_time_pad_);
665         LogRequiredActions(full_wallet->required_actions());
666         delegate_->OnDidGetFullWallet(full_wallet.Pass());
667       } else {
668         HandleMalformedResponse(type, scoped_request.get());
669       }
670       break;
671     }
672 
673     case GET_WALLET_ITEMS: {
674       scoped_ptr<WalletItems> wallet_items(
675           WalletItems::CreateWalletItems(*response_dict));
676       if (wallet_items) {
677         LogRequiredActions(wallet_items->required_actions());
678         delegate_->OnDidGetWalletItems(wallet_items.Pass());
679       } else {
680         HandleMalformedResponse(type, scoped_request.get());
681       }
682       break;
683     }
684 
685     case SAVE_TO_WALLET: {
686       std::string instrument_id;
687       response_dict->GetString(kInstrumentIdKey, &instrument_id);
688       std::string shipping_address_id;
689       response_dict->GetString(kShippingAddressIdKey,
690                                &shipping_address_id);
691       std::vector<RequiredAction> required_actions;
692       GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
693       std::vector<FormFieldError> form_errors;
694       GetFormFieldErrors(*response_dict, &form_errors);
695       if (instrument_id.empty() && shipping_address_id.empty() &&
696           required_actions.empty()) {
697         HandleMalformedResponse(type, scoped_request.get());
698       } else {
699         LogRequiredActions(required_actions);
700         delegate_->OnDidSaveToWallet(instrument_id,
701                                      shipping_address_id,
702                                      required_actions,
703                                      form_errors);
704       }
705       break;
706     }
707 
708     case NO_REQUEST:
709       NOTREACHED();
710   }
711 }
712 
HandleMalformedResponse(RequestType request_type,net::URLFetcher * request)713 void WalletClient::HandleMalformedResponse(RequestType request_type,
714                                            net::URLFetcher* request) {
715   // Called to inform exponential backoff logic of the error.
716   request->ReceivedContentWasMalformed();
717   // Record failed API call in metrics.
718   delegate_->GetMetricLogger().LogWalletMalformedResponseMetric(
719     RequestTypeToUmaMetric(request_type));
720   HandleWalletError(MALFORMED_RESPONSE);
721 }
722 
HandleWalletError(WalletClient::ErrorType error_type)723 void WalletClient::HandleWalletError(WalletClient::ErrorType error_type) {
724   std::string error_message;
725   switch (error_type) {
726     case WalletClient::BAD_REQUEST:
727       error_message = "WALLET_BAD_REQUEST";
728       break;
729     case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
730       error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
731       break;
732     case WalletClient::BUYER_ACCOUNT_ERROR:
733       error_message = "WALLET_BUYER_ACCOUNT_ERROR";
734       break;
735     case WalletClient::INTERNAL_ERROR:
736       error_message = "WALLET_INTERNAL_ERROR";
737       break;
738     case WalletClient::INVALID_PARAMS:
739       error_message = "WALLET_INVALID_PARAMS";
740       break;
741     case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
742       error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
743       break;
744     case WalletClient::SPENDING_LIMIT_EXCEEDED:
745       error_message = "SPENDING_LIMIT_EXCEEDED";
746       break;
747     case WalletClient::SERVICE_UNAVAILABLE:
748       error_message = "WALLET_SERVICE_UNAVAILABLE";
749       break;
750     case WalletClient::UNSUPPORTED_API_VERSION:
751       error_message = "WALLET_UNSUPPORTED_API_VERSION";
752       break;
753     case WalletClient::UNSUPPORTED_MERCHANT:
754       error_message = "WALLET_UNSUPPORTED_MERCHANT";
755       break;
756     case WalletClient::MALFORMED_RESPONSE:
757       error_message = "WALLET_MALFORMED_RESPONSE";
758       break;
759     case WalletClient::NETWORK_ERROR:
760       error_message = "WALLET_NETWORK_ERROR";
761       break;
762     case WalletClient::UNKNOWN_ERROR:
763       error_message = "WALLET_UNKNOWN_ERROR";
764       break;
765     case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
766       error_message = "WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY";
767       break;
768   }
769 
770   DVLOG(1) << "Wallet encountered a " << error_message;
771 
772   delegate_->OnWalletError(error_type);
773   delegate_->GetMetricLogger().LogWalletErrorMetric(
774       ErrorTypeToUmaMetric(error_type));
775 }
776 
777 // Logs an UMA metric for each of the |required_actions|.
LogRequiredActions(const std::vector<RequiredAction> & required_actions) const778 void WalletClient::LogRequiredActions(
779     const std::vector<RequiredAction>& required_actions) const {
780   for (size_t i = 0; i < required_actions.size(); ++i) {
781     delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
782         RequiredActionToUmaMetric(required_actions[i]));
783   }
784 }
785 
RequestTypeToUmaMetric(RequestType request_type) const786 AutofillMetrics::WalletApiCallMetric WalletClient::RequestTypeToUmaMetric(
787     RequestType request_type) const {
788   switch (request_type) {
789     case ACCEPT_LEGAL_DOCUMENTS:
790       return AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS;
791     case AUTHENTICATE_INSTRUMENT:
792       return AutofillMetrics::AUTHENTICATE_INSTRUMENT;
793     case GET_FULL_WALLET:
794       return AutofillMetrics::GET_FULL_WALLET;
795     case GET_WALLET_ITEMS:
796       return AutofillMetrics::GET_WALLET_ITEMS;
797     case SAVE_TO_WALLET:
798       return AutofillMetrics::SAVE_TO_WALLET;
799     case NO_REQUEST:
800       NOTREACHED();
801       return AutofillMetrics::UNKNOWN_API_CALL;
802   }
803 
804   NOTREACHED();
805   return AutofillMetrics::UNKNOWN_API_CALL;
806 }
807 
808 }  // namespace wallet
809 }  // namespace autofill
810