Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: chrome/browser/autofill/wallet/wallet_client.cc

Issue 12434004: Move remaining Autofill code to //components/autofill. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/browser/autofill/wallet/wallet_client.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/string_util.h"
12 #include "chrome/browser/autofill/wallet/cart.h"
13 #include "chrome/browser/autofill/wallet/instrument.h"
14 #include "chrome/browser/autofill/wallet/wallet_address.h"
15 #include "chrome/browser/autofill/wallet/wallet_client_observer.h"
16 #include "chrome/browser/autofill/wallet/wallet_items.h"
17 #include "chrome/browser/autofill/wallet/wallet_service_url.h"
18 #include "crypto/random.h"
19 #include "google_apis/google_api_keys.h"
20 #include "googleurl/src/gurl.h"
21 #include "net/http/http_status_code.h"
22 #include "net/url_request/url_fetcher.h"
23 #include "net/url_request/url_request_context_getter.h"
24
25 namespace autofill {
26 namespace wallet {
27
28 namespace {
29
30 const char kJsonMimeType[] = "application/json";
31 const size_t kOneTimePadLength = 6;
32
33 std::string AutocheckoutStatusToString(AutocheckoutStatus status) {
34 switch (status) {
35 case MISSING_FIELDMAPPING:
36 return "MISSING_FIELDMAPPING";
37 case MISSING_ADVANCE:
38 return "MISSING_ADVANCE";
39 case CANNOT_PROCEED:
40 return "CANNOT_PROCEED";
41 case SUCCESS:
42 // SUCCESS cannot be sent to the server as it will result in a failure.
43 NOTREACHED();
44 return "ERROR";
45 }
46 NOTREACHED();
47 return "NOT_POSSIBLE";
48 }
49
50 // Gets and parses required actions from a SaveToWallet response. Returns
51 // false if any unknown required actions are seen and true otherwise.
52 void GetRequiredActionsForSaveToWallet(
53 const base::DictionaryValue& dict,
54 std::vector<RequiredAction>* required_actions) {
55 const ListValue* required_action_list;
56 if (!dict.GetList("required_action", &required_action_list))
57 return;
58
59 for (size_t i = 0; i < required_action_list->GetSize(); ++i) {
60 std::string action_string;
61 if (required_action_list->GetString(i, &action_string)) {
62 RequiredAction action = ParseRequiredActionFromString(action_string);
63 if (!ActionAppliesToSaveToWallet(action)) {
64 DLOG(ERROR) << "Response from Google wallet with bad required action:"
65 " \"" << action_string << "\"";
66 required_actions->clear();
67 return;
68 }
69 required_actions->push_back(action);
70 }
71 }
72 }
73
74 // Keys for JSON communication with the Online Wallet server.
75 const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
76 const char kApiKeyKey[] = "api_key";
77 const char kAuthResultKey[] = "auth_result";
78 const char kCartKey[] = "cart";
79 const char kEncryptedOtpKey[] = "encrypted_otp";
80 const char kGoogleTransactionIdKey[] = "google_transaction_id";
81 const char kInstrumentIdKey[] = "instrument_id";
82 const char kInstrumentKey[] = "instrument";
83 const char kInstrumentEscrowHandleKey[] = "instrument_escrow_handle";
84 const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
85 const char kMerchantDomainKey[] = "merchant_domain";
86 const char kReasonKey[] = "reason";
87 const char kRiskParamsKey[] = "risk_params";
88 const char kSelectedAddressIdKey[] = "selected_address_id";
89 const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
90 const char kSessionMaterialKey[] = "session_material";
91 const char kShippingAddressIdKey[] = "shipping_address_id";
92 const char kShippingAddressKey[] = "shipping_address";
93 const char kSuccessKey[] = "success";
94 const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
95 const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
96
97 } // namespace
98
99
100 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter)
101 : context_getter_(context_getter),
102 request_type_(NO_PENDING_REQUEST),
103 one_time_pad_(kOneTimePadLength),
104 encryption_escrow_client_(context_getter),
105 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
106 DCHECK(context_getter);
107 }
108
109 WalletClient::~WalletClient() {}
110
111 void WalletClient::AcceptLegalDocuments(
112 const std::vector<std::string>& document_ids,
113 const std::string& google_transaction_id,
114 const GURL& source_url,
115 base::WeakPtr<WalletClientObserver> observer) {
116 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
117 request_type_ = ACCEPT_LEGAL_DOCUMENTS;
118
119 base::DictionaryValue request_dict;
120 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
121 request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
122 request_dict.SetString(kMerchantDomainKey,
123 source_url.GetWithEmptyPath().spec());
124 ListValue* docs_list = new ListValue();
125 for (std::vector<std::string>::const_iterator it = document_ids.begin();
126 it != document_ids.end();
127 ++it) {
128 docs_list->AppendString(*it);
129 }
130 request_dict.Set(kAcceptedLegalDocumentKey, docs_list);
131
132 std::string post_body;
133 base::JSONWriter::Write(&request_dict, &post_body);
134
135 MakeWalletRequest(GetAcceptLegalDocumentsUrl(), post_body, observer);
136 }
137
138 void WalletClient::AuthenticateInstrument(
139 const std::string& instrument_id,
140 const std::string& card_verification_number,
141 const std::string& obfuscated_gaia_id,
142 base::WeakPtr<WalletClientObserver> observer) {
143 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
144 DCHECK(observer);
145 DCHECK(pending_request_body_.empty());
146 request_type_ = AUTHENTICATE_INSTRUMENT;
147 observer_ = observer;
148
149 pending_request_body_.SetString(kApiKeyKey, google_apis::GetAPIKey());
150 pending_request_body_.SetString(kRiskParamsKey, GetRiskParams());
151 pending_request_body_.SetString(kInstrumentIdKey, instrument_id);
152
153 encryption_escrow_client_.EscrowCardVerificationNumber(
154 card_verification_number,
155 obfuscated_gaia_id,
156 weak_ptr_factory_.GetWeakPtr());
157 }
158
159 void WalletClient::GetFullWallet(const std::string& instrument_id,
160 const std::string& address_id,
161 const GURL& source_url,
162 const Cart& cart,
163 const std::string& google_transaction_id,
164 base::WeakPtr<WalletClientObserver> observer) {
165 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
166 DCHECK(observer);
167 DCHECK(pending_request_body_.empty());
168 request_type_ = GET_FULL_WALLET;
169 observer_ = observer;
170
171 pending_request_body_.SetString(kApiKeyKey, google_apis::GetAPIKey());
172 pending_request_body_.SetString(kRiskParamsKey, GetRiskParams());
173 pending_request_body_.SetString(kSelectedInstrumentIdKey, instrument_id);
174 pending_request_body_.SetString(kSelectedAddressIdKey, address_id);
175 pending_request_body_.SetString(kMerchantDomainKey,
176 source_url.GetWithEmptyPath().spec());
177 pending_request_body_.SetString(kGoogleTransactionIdKey,
178 google_transaction_id);
179 pending_request_body_.Set(kCartKey, cart.ToDictionary().release());
180
181 crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
182 encryption_escrow_client_.EncryptOneTimePad(one_time_pad_,
183 weak_ptr_factory_.GetWeakPtr());
184 }
185
186 void WalletClient::GetWalletItems(
187 const GURL& source_url,
188 base::WeakPtr<WalletClientObserver> observer) {
189 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
190 request_type_ = GET_WALLET_ITEMS;
191
192 base::DictionaryValue request_dict;
193 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
194 request_dict.SetString(kRiskParamsKey, GetRiskParams());
195 request_dict.SetString(kMerchantDomainKey,
196 source_url.GetWithEmptyPath().spec());
197
198 std::string post_body;
199 base::JSONWriter::Write(&request_dict, &post_body);
200
201 MakeWalletRequest(GetGetWalletItemsUrl(), post_body, observer);
202 }
203
204 void WalletClient::SaveAddress(const Address& shipping_address,
205 const GURL& source_url,
206 base::WeakPtr<WalletClientObserver> observer) {
207 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
208 request_type_ = SAVE_ADDRESS;
209
210 base::DictionaryValue request_dict;
211 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
212 request_dict.SetString(kRiskParamsKey, GetRiskParams());
213 request_dict.SetString(kMerchantDomainKey,
214 source_url.GetWithEmptyPath().spec());
215
216 request_dict.Set(kShippingAddressKey,
217 shipping_address.ToDictionaryWithID().release());
218
219 std::string post_body;
220 base::JSONWriter::Write(&request_dict, &post_body);
221
222 MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer);
223 }
224
225 void WalletClient::SaveInstrument(
226 const Instrument& instrument,
227 const std::string& obfuscated_gaia_id,
228 const GURL& source_url,
229 base::WeakPtr<WalletClientObserver> observer) {
230 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
231 DCHECK(observer);
232 DCHECK(pending_request_body_.empty());
233 request_type_ = SAVE_INSTRUMENT;
234 observer_ = observer;
235
236 pending_request_body_.SetString(kApiKeyKey, google_apis::GetAPIKey());
237 pending_request_body_.SetString(kRiskParamsKey, GetRiskParams());
238 pending_request_body_.SetString(kMerchantDomainKey,
239 source_url.GetWithEmptyPath().spec());
240
241 pending_request_body_.Set(kInstrumentKey,
242 instrument.ToDictionary().release());
243 pending_request_body_.SetString(kInstrumentPhoneNumberKey,
244 instrument.address().phone_number());
245
246 encryption_escrow_client_.EscrowInstrumentInformation(
247 instrument,
248 obfuscated_gaia_id,
249 weak_ptr_factory_.GetWeakPtr());
250 }
251
252 void WalletClient::SaveInstrumentAndAddress(
253 const Instrument& instrument,
254 const Address& address,
255 const std::string& obfuscated_gaia_id,
256 const GURL& source_url,
257 base::WeakPtr<WalletClientObserver> observer) {
258 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
259 DCHECK(observer);
260 DCHECK(pending_request_body_.empty());
261 request_type_ = SAVE_INSTRUMENT_AND_ADDRESS;
262 observer_ = observer;
263
264 pending_request_body_.SetString(kApiKeyKey, google_apis::GetAPIKey());
265 pending_request_body_.SetString(kRiskParamsKey, GetRiskParams());
266 pending_request_body_.SetString(kMerchantDomainKey,
267 source_url.GetWithEmptyPath().spec());
268
269 pending_request_body_.Set(kInstrumentKey,
270 instrument.ToDictionary().release());
271 pending_request_body_.SetString(kInstrumentPhoneNumberKey,
272 instrument.address().phone_number());
273
274 pending_request_body_.Set(kShippingAddressKey,
275 address.ToDictionaryWithID().release());
276
277 encryption_escrow_client_.EscrowInstrumentInformation(
278 instrument,
279 obfuscated_gaia_id,
280 weak_ptr_factory_.GetWeakPtr());
281 }
282
283 void WalletClient::SendAutocheckoutStatus(
284 AutocheckoutStatus status,
285 const GURL& source_url,
286 const std::string& google_transaction_id,
287 base::WeakPtr<WalletClientObserver> observer) {
288 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
289 request_type_ = SEND_STATUS;
290
291 base::DictionaryValue request_dict;
292 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
293 bool success = status == SUCCESS;
294 request_dict.SetBoolean(kSuccessKey, success);
295 request_dict.SetString(kMerchantDomainKey,
296 source_url.GetWithEmptyPath().spec());
297 if (!success) {
298 request_dict.SetString(kReasonKey, AutocheckoutStatusToString(status));
299 }
300 request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
301
302 std::string post_body;
303 base::JSONWriter::Write(&request_dict, &post_body);
304
305 MakeWalletRequest(GetSendStatusUrl(), post_body, observer);
306 }
307
308 void WalletClient::UpdateInstrument(
309 const std::string& instrument_id,
310 const Address& billing_address,
311 const GURL& source_url,
312 base::WeakPtr<WalletClientObserver> observer) {
313 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
314 request_type_ = UPDATE_INSTRUMENT;
315
316 base::DictionaryValue request_dict;
317 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
318 request_dict.SetString(kRiskParamsKey, GetRiskParams());
319 request_dict.SetString(kMerchantDomainKey,
320 source_url.GetWithEmptyPath().spec());
321
322 request_dict.SetString(kUpgradedInstrumentIdKey, instrument_id);
323 request_dict.SetString(kInstrumentPhoneNumberKey,
324 billing_address.phone_number());
325 request_dict.Set(kUpgradedBillingAddressKey,
326 billing_address.ToDictionaryWithoutID().release());
327
328 std::string post_body;
329 base::JSONWriter::Write(&request_dict, &post_body);
330
331 MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer);
332 }
333
334 bool WalletClient::HasRequestInProgress() const {
335 return request_.get() != NULL;
336 }
337
338 void WalletClient::MakeWalletRequest(
339 const GURL& url,
340 const std::string& post_body,
341 base::WeakPtr<WalletClientObserver> observer) {
342 DCHECK(!HasRequestInProgress());
343 DCHECK(observer);
344
345 observer_ = observer;
346
347 request_.reset(net::URLFetcher::Create(
348 0, url, net::URLFetcher::POST, this));
349 request_->SetRequestContext(context_getter_);
350 DVLOG(1) << "url=" << url << ", post_body=" << post_body;
351 request_->SetUploadData(kJsonMimeType, post_body);
352 request_->Start();
353 }
354
355 // TODO(ahutter): Add manual retry logic if it's necessary.
356 void WalletClient::OnURLFetchComplete(
357 const net::URLFetcher* source) {
358 scoped_ptr<net::URLFetcher> old_request = request_.Pass();
359 DCHECK_EQ(source, old_request.get());
360 DVLOG(1) << "Got response from " << source->GetOriginalURL();
361
362 std::string data;
363 source->GetResponseAsString(&data);
364 DVLOG(1) << "Response body: " << data;
365
366 scoped_ptr<base::DictionaryValue> response_dict;
367
368 int response_code = source->GetResponseCode();
369 switch (response_code) {
370 // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
371 case net::HTTP_BAD_REQUEST: {
372 request_type_ = NO_PENDING_REQUEST;
373 observer_->OnWalletError();
374 return;
375 }
376 // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
377 // error code and message for the user.
378 case net::HTTP_OK:
379 case net::HTTP_INTERNAL_SERVER_ERROR: {
380 scoped_ptr<Value> message_value(base::JSONReader::Read(data));
381 if (message_value.get() &&
382 message_value->IsType(Value::TYPE_DICTIONARY)) {
383 response_dict.reset(
384 static_cast<base::DictionaryValue*>(message_value.release()));
385 }
386 if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
387 request_type_ = NO_PENDING_REQUEST;
388 // TODO(ahutter): Do something with the response. See
389 // http://crbug.com/164410.
390 observer_->OnWalletError();
391 return;
392 }
393 break;
394 }
395 // Anything else is an error.
396 default: {
397 request_type_ = NO_PENDING_REQUEST;
398 observer_->OnNetworkError(response_code);
399 return;
400 }
401 }
402
403 RequestType type = request_type_;
404 request_type_ = NO_PENDING_REQUEST;
405
406 if (!(type == ACCEPT_LEGAL_DOCUMENTS || type == SEND_STATUS) &&
407 !response_dict) {
408 HandleMalformedResponse(old_request.get());
409 return;
410 }
411
412 switch (type) {
413 case ACCEPT_LEGAL_DOCUMENTS:
414 if (observer_)
415 observer_->OnDidAcceptLegalDocuments();
416 break;
417
418 case AUTHENTICATE_INSTRUMENT: {
419 std::string auth_result;
420 if (response_dict->GetString(kAuthResultKey, &auth_result)) {
421 std::string trimmed;
422 TrimWhitespaceASCII(auth_result,
423 TRIM_ALL,
424 &trimmed);
425 if (observer_) {
426 observer_->OnDidAuthenticateInstrument(
427 LowerCaseEqualsASCII(trimmed, "success"));
428 }
429 } else {
430 HandleMalformedResponse(old_request.get());
431 }
432 break;
433 }
434
435 case SEND_STATUS:
436 if (observer_)
437 observer_->OnDidSendAutocheckoutStatus();
438 break;
439
440 case GET_FULL_WALLET: {
441 scoped_ptr<FullWallet> full_wallet(
442 FullWallet::CreateFullWallet(*response_dict));
443 if (full_wallet) {
444 full_wallet->set_one_time_pad(one_time_pad_);
445 if (observer_)
446 observer_->OnDidGetFullWallet(full_wallet.Pass());
447 } else {
448 HandleMalformedResponse(old_request.get());
449 }
450 break;
451 }
452
453 case GET_WALLET_ITEMS: {
454 scoped_ptr<WalletItems> wallet_items(
455 WalletItems::CreateWalletItems(*response_dict));
456 if (wallet_items) {
457 if (observer_)
458 observer_->OnDidGetWalletItems(wallet_items.Pass());
459 } else {
460 HandleMalformedResponse(old_request.get());
461 }
462 break;
463 }
464
465 case SAVE_ADDRESS: {
466 std::string shipping_address_id;
467 std::vector<RequiredAction> required_actions;
468 GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
469 if (response_dict->GetString(kShippingAddressIdKey,
470 &shipping_address_id) ||
471 !required_actions.empty()) {
472 if (observer_)
473 observer_->OnDidSaveAddress(shipping_address_id, required_actions);
474 } else {
475 HandleMalformedResponse(old_request.get());
476 }
477 break;
478 }
479
480 case SAVE_INSTRUMENT: {
481 std::string instrument_id;
482 std::vector<RequiredAction> required_actions;
483 GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
484 if (response_dict->GetString(kInstrumentIdKey, &instrument_id) ||
485 !required_actions.empty()) {
486 if (observer_)
487 observer_->OnDidSaveInstrument(instrument_id, required_actions);
488 } else {
489 HandleMalformedResponse(old_request.get());
490 }
491 break;
492 }
493
494 case SAVE_INSTRUMENT_AND_ADDRESS: {
495 std::string instrument_id;
496 response_dict->GetString(kInstrumentIdKey, &instrument_id);
497 std::string shipping_address_id;
498 response_dict->GetString(kShippingAddressIdKey,
499 &shipping_address_id);
500 std::vector<RequiredAction> required_actions;
501 GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
502 if ((!instrument_id.empty() && !shipping_address_id.empty()) ||
503 !required_actions.empty()) {
504 if (observer_) {
505 observer_->OnDidSaveInstrumentAndAddress(
506 instrument_id,
507 shipping_address_id,
508 required_actions);
509 }
510 } else {
511 HandleMalformedResponse(old_request.get());
512 }
513 break;
514 }
515
516 case UPDATE_INSTRUMENT: {
517 std::string instrument_id;
518 std::vector<RequiredAction> required_actions;
519 GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
520 if (response_dict->GetString(kInstrumentIdKey, &instrument_id) ||
521 !required_actions.empty()) {
522 if (observer_)
523 observer_->OnDidUpdateInstrument(instrument_id, required_actions);
524 } else {
525 HandleMalformedResponse(old_request.get());
526 }
527 break;
528 }
529
530 case NO_PENDING_REQUEST:
531 NOTREACHED();
532 }
533 }
534
535 void WalletClient::HandleMalformedResponse(net::URLFetcher* request) {
536 // Called to inform exponential backoff logic of the error.
537 request->ReceivedContentWasMalformed();
538 if (observer_)
539 observer_->OnMalformedResponse();
540 }
541
542 void WalletClient::OnDidEncryptOneTimePad(
543 const std::string& encrypted_one_time_pad,
544 const std::string& session_material) {
545 DCHECK_EQ(GET_FULL_WALLET, request_type_);
546 pending_request_body_.SetString(kEncryptedOtpKey, encrypted_one_time_pad);
547 pending_request_body_.SetString(kSessionMaterialKey, session_material);
548
549 std::string post_body;
550 base::JSONWriter::Write(&pending_request_body_, &post_body);
551 pending_request_body_.Clear();
552
553 MakeWalletRequest(GetGetFullWalletUrl(), post_body, observer_);
554 }
555
556 void WalletClient::OnDidEscrowInstrumentInformation(
557 const std::string& escrow_handle) {
558 DCHECK(request_type_ == SAVE_INSTRUMENT ||
559 request_type_ == SAVE_INSTRUMENT_AND_ADDRESS);
560
561 pending_request_body_.SetString(kInstrumentEscrowHandleKey, escrow_handle);
562
563 std::string post_body;
564 base::JSONWriter::Write(&pending_request_body_, &post_body);
565 pending_request_body_.Clear();
566
567 MakeWalletRequest(GetSaveToWalletUrl(), post_body, observer_);
568 }
569
570 void WalletClient::OnDidEscrowCardVerificationNumber(
571 const std::string& escrow_handle) {
572 DCHECK_EQ(AUTHENTICATE_INSTRUMENT, request_type_);
573 pending_request_body_.SetString(kInstrumentEscrowHandleKey, escrow_handle);
574
575 std::string post_body;
576 base::JSONWriter::Write(&pending_request_body_, &post_body);
577 pending_request_body_.Clear();
578
579 MakeWalletRequest(GetAuthenticateInstrumentUrl(), post_body, observer_);
580 }
581
582 void WalletClient::OnNetworkError(int response_code) {
583 if (observer_)
584 observer_->OnNetworkError(response_code);
585 }
586
587 void WalletClient::OnMalformedResponse() {
588 if (observer_)
589 observer_->OnMalformedResponse();
590 }
591
592 } // namespace wallet
593 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698