Add diagnostics_writer.cc to the list of files allowed to printf.
[chromium-blink-merge.git] / components / autofill / content / browser / wallet / wallet_items.cc
blobd9a45d12c410e7c62ad63f89b840dba02d67ae5a
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.
5 #include "components/autofill/content/browser/wallet/wallet_items.h"
7 #include <limits>
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "components/autofill/content/browser/wallet/gaia_account.h"
14 #include "components/autofill/core/browser/autofill_type.h"
15 #include "components/autofill/core/browser/credit_card.h"
16 #include "grit/component_scaled_resources.h"
17 #include "grit/components_strings.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/image/image.h"
21 #include "url/gurl.h"
23 namespace autofill {
24 namespace wallet {
26 namespace {
28 const char kLegalDocumentUrl[] =
29 "https://wallet.google.com/legaldocument?docId=";
30 const char kPrivacyNoticeUrl[] = "https://wallet.google.com/files/privacy.html";
32 // TODO(estade): move to base/.
33 template<class T>
34 bool VectorsAreEqual(const std::vector<T*>& a, const std::vector<T*>& b) {
35 if (a.size() != b.size())
36 return false;
38 for (size_t i = 0; i < a.size(); ++i) {
39 if (*a[i] != *b[i])
40 return false;
43 return true;
46 WalletItems::MaskedInstrument::Type
47 TypeFromString(const std::string& type_string) {
48 if (type_string == "VISA")
49 return WalletItems::MaskedInstrument::VISA;
50 if (type_string == "MASTER_CARD")
51 return WalletItems::MaskedInstrument::MASTER_CARD;
52 if (type_string == "AMEX")
53 return WalletItems::MaskedInstrument::AMEX;
54 if (type_string == "DISCOVER")
55 return WalletItems::MaskedInstrument::DISCOVER;
56 if (type_string == "SOLO")
57 return WalletItems::MaskedInstrument::SOLO;
58 if (type_string == "MAESTRO")
59 return WalletItems::MaskedInstrument::MAESTRO;
60 if (type_string == "SWITCH")
61 return WalletItems::MaskedInstrument::SWITCH;
62 return WalletItems::MaskedInstrument::UNKNOWN;
65 WalletItems::MaskedInstrument::Status
66 StatusFromString(const std::string& status_string) {
67 if (status_string == "AMEX_NOT_SUPPORTED")
68 return WalletItems::MaskedInstrument::AMEX_NOT_SUPPORTED;
69 if (status_string == "PENDING")
70 return WalletItems::MaskedInstrument::PENDING;
71 if (status_string == "VALID")
72 return WalletItems::MaskedInstrument::VALID;
73 if (status_string == "DECLINED")
74 return WalletItems::MaskedInstrument::DECLINED;
75 if (status_string == "DISABLED_FOR_THIS_MERCHANT")
76 return WalletItems::MaskedInstrument::DISABLED_FOR_THIS_MERCHANT;
77 if (status_string == "UNSUPPORTED_COUNTRY")
78 return WalletItems::MaskedInstrument::UNSUPPORTED_COUNTRY;
79 if (status_string == "EXPIRED")
80 return WalletItems::MaskedInstrument::EXPIRED;
81 if (status_string == "BILLING_INCOMPLETE")
82 return WalletItems::MaskedInstrument::BILLING_INCOMPLETE;
83 return WalletItems::MaskedInstrument::INAPPLICABLE;
86 base::string16 DisplayStringFromType(WalletItems::MaskedInstrument::Type type) {
87 switch (type) {
88 case WalletItems::MaskedInstrument::AMEX:
89 return CreditCard::TypeForDisplay(kAmericanExpressCard);
90 case WalletItems::MaskedInstrument::DISCOVER:
91 return CreditCard::TypeForDisplay(kDiscoverCard);
92 case WalletItems::MaskedInstrument::MASTER_CARD:
93 return CreditCard::TypeForDisplay(kMasterCard);
94 case WalletItems::MaskedInstrument::VISA:
95 return CreditCard::TypeForDisplay(kVisaCard);
96 default:
97 return CreditCard::TypeForDisplay(kGenericCard);
101 } // anonymous namespace
103 WalletItems::MaskedInstrument::MaskedInstrument(
104 const base::string16& descriptive_name,
105 const WalletItems::MaskedInstrument::Type& type,
106 const base::string16& last_four_digits,
107 int expiration_month,
108 int expiration_year,
109 scoped_ptr<Address> address,
110 const WalletItems::MaskedInstrument::Status& status,
111 const std::string& object_id)
112 : descriptive_name_(descriptive_name),
113 type_(type),
114 last_four_digits_(last_four_digits),
115 expiration_month_(expiration_month),
116 expiration_year_(expiration_year),
117 address_(address.Pass()),
118 status_(status),
119 object_id_(object_id) {
120 DCHECK(address_);
123 WalletItems::MaskedInstrument::~MaskedInstrument() {}
125 scoped_ptr<WalletItems::MaskedInstrument>
126 WalletItems::MaskedInstrument::CreateMaskedInstrument(
127 const base::DictionaryValue& dictionary) {
128 std::string type_string;
129 Type type;
130 if (dictionary.GetString("type", &type_string)) {
131 type = TypeFromString(type_string);
132 } else {
133 DLOG(ERROR) << "Response from Google Wallet missing card type";
134 return scoped_ptr<MaskedInstrument>();
137 base::string16 last_four_digits;
138 if (!dictionary.GetString("last_four_digits", &last_four_digits)) {
139 DLOG(ERROR) << "Response from Google Wallet missing last four digits";
140 return scoped_ptr<MaskedInstrument>();
143 std::string status_string;
144 Status status;
145 if (dictionary.GetString("status", &status_string)) {
146 status = StatusFromString(status_string);
147 } else {
148 DLOG(ERROR) << "Response from Google Wallet missing status";
149 return scoped_ptr<MaskedInstrument>();
152 std::string object_id;
153 if (!dictionary.GetString("object_id", &object_id)) {
154 DLOG(ERROR) << "Response from Google Wallet missing object id";
155 return scoped_ptr<MaskedInstrument>();
158 const base::DictionaryValue* address_dict;
159 if (!dictionary.GetDictionary("billing_address", &address_dict)) {
160 DLOG(ERROR) << "Response from Google wallet missing address";
161 return scoped_ptr<MaskedInstrument>();
163 scoped_ptr<Address> address = Address::CreateDisplayAddress(*address_dict);
165 if (!address) {
166 DLOG(ERROR) << "Response from Google wallet contained malformed address";
167 return scoped_ptr<MaskedInstrument>();
170 int expiration_month;
171 if (!dictionary.GetInteger("expiration_month", &expiration_month))
172 DVLOG(1) << "Response from Google Wallet missing expiration month";
174 int expiration_year;
175 if (!dictionary.GetInteger("expiration_year", &expiration_year))
176 DVLOG(1) << "Response from Google Wallet missing expiration year";
178 base::string16 descriptive_name;
179 if (!dictionary.GetString("descriptive_name", &descriptive_name))
180 DVLOG(1) << "Response from Google Wallet missing descriptive name";
182 return scoped_ptr<MaskedInstrument>(new MaskedInstrument(descriptive_name,
183 type,
184 last_four_digits,
185 expiration_month,
186 expiration_year,
187 address.Pass(),
188 status,
189 object_id));
192 bool WalletItems::MaskedInstrument::operator==(
193 const WalletItems::MaskedInstrument& other) const {
194 if (descriptive_name_ != other.descriptive_name_)
195 return false;
196 if (type_ != other.type_)
197 return false;
198 if (last_four_digits_ != other.last_four_digits_)
199 return false;
200 if (expiration_month_ != other.expiration_month_)
201 return false;
202 if (expiration_year_ != other.expiration_year_)
203 return false;
204 if (address_) {
205 if (other.address_) {
206 if (*address_ != *other.address_)
207 return false;
208 } else {
209 return false;
211 } else if (other.address_) {
212 return false;
214 if (status_ != other.status_)
215 return false;
216 if (object_id_ != other.object_id_)
217 return false;
218 return true;
221 bool WalletItems::MaskedInstrument::operator!=(
222 const WalletItems::MaskedInstrument& other) const {
223 return !(*this == other);
226 const WalletItems::MaskedInstrument* WalletItems::GetInstrumentById(
227 const std::string& object_id) const {
228 if (object_id.empty())
229 return NULL;
231 for (size_t i = 0; i < instruments_.size(); ++i) {
232 if (instruments_[i]->object_id() == object_id)
233 return instruments_[i];
236 return NULL;
239 bool WalletItems::HasRequiredAction(RequiredAction action) const {
240 DCHECK(ActionAppliesToWalletItems(action));
241 return std::find(required_actions_.begin(),
242 required_actions_.end(),
243 action) != required_actions_.end();
246 bool WalletItems::SupportsCard(const base::string16& card_number,
247 base::string16* message) const {
248 const char* const card_type = CreditCard::GetCreditCardType(card_number);
250 if (card_type == kVisaCard ||
251 card_type == kMasterCard ||
252 card_type == kDiscoverCard) {
253 return true;
256 if (card_type == kAmericanExpressCard) {
257 if (amex_permission_ == AMEX_ALLOWED)
258 return true;
260 *message = l10n_util::GetStringUTF16(
261 IDS_AUTOFILL_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET_FOR_MERCHANT);
262 return false;
265 *message = l10n_util::GetStringUTF16(
266 IDS_AUTOFILL_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET);
267 return false;
270 std::string WalletItems::ObfuscatedGaiaId() const {
271 if (active_account_index_ >= gaia_accounts_.size())
272 return std::string();
274 return gaia_accounts_[active_account_index_]->obfuscated_id();
277 base::string16 WalletItems::MaskedInstrument::DisplayName() const {
278 #if defined(OS_ANDROID)
279 // TODO(aruslan): improve this stub implementation.
280 return descriptive_name();
281 #else
282 return descriptive_name();
283 #endif
286 base::string16 WalletItems::MaskedInstrument::DisplayNameDetail() const {
287 #if defined(OS_ANDROID)
288 // TODO(aruslan): improve this stub implementation.
289 return address().DisplayName();
290 #else
291 return base::string16();
292 #endif
295 base::string16 WalletItems::MaskedInstrument::TypeAndLastFourDigits() const {
296 // TODO(dbeam): i18n.
297 return DisplayStringFromType(type_) + base::ASCIIToUTF16(" - ") +
298 last_four_digits();
301 const gfx::Image& WalletItems::MaskedInstrument::CardIcon() const {
302 int idr = 0;
303 switch (type_) {
304 case AMEX:
305 idr = IDR_AUTOFILL_CC_AMEX;
306 break;
308 case DISCOVER:
309 idr = IDR_AUTOFILL_CC_DISCOVER;
310 break;
312 case MASTER_CARD:
313 idr = IDR_AUTOFILL_CC_MASTERCARD;
314 break;
316 case VISA:
317 idr = IDR_AUTOFILL_CC_VISA;
318 break;
320 case SOLO:
321 case MAESTRO:
322 case SWITCH:
323 case UNKNOWN:
324 idr = IDR_AUTOFILL_CC_GENERIC;
325 break;
328 return ResourceBundle::GetSharedInstance().GetImageNamed(idr);
331 base::string16 WalletItems::MaskedInstrument::GetInfo(
332 const AutofillType& type,
333 const std::string& app_locale) const {
334 if (type.group() != CREDIT_CARD)
335 return address().GetInfo(type, app_locale);
337 switch (type.GetStorableType()) {
338 case CREDIT_CARD_NAME:
339 return address().recipient_name();
341 case CREDIT_CARD_NUMBER:
342 return DisplayName();
344 case CREDIT_CARD_EXP_4_DIGIT_YEAR:
345 return base::IntToString16(expiration_year());
347 case CREDIT_CARD_VERIFICATION_CODE:
348 break;
350 case CREDIT_CARD_TYPE:
351 return DisplayStringFromType(type_);
353 default:
354 NOTREACHED();
357 return base::string16();
360 WalletItems::LegalDocument::~LegalDocument() {}
362 scoped_ptr<WalletItems::LegalDocument>
363 WalletItems::LegalDocument::CreateLegalDocument(
364 const base::DictionaryValue& dictionary) {
365 std::string id;
366 if (!dictionary.GetString("legal_document_id", &id)) {
367 DLOG(ERROR) << "Response from Google Wallet missing legal document id";
368 return scoped_ptr<LegalDocument>();
371 base::string16 display_name;
372 if (!dictionary.GetString("display_name", &display_name)) {
373 DLOG(ERROR) << "Response from Google Wallet missing display name";
374 return scoped_ptr<LegalDocument>();
377 return scoped_ptr<LegalDocument>(new LegalDocument(id, display_name));
380 scoped_ptr<WalletItems::LegalDocument>
381 WalletItems::LegalDocument::CreatePrivacyPolicyDocument() {
382 return scoped_ptr<LegalDocument>(new LegalDocument(
383 GURL(kPrivacyNoticeUrl),
384 l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PRIVACY_POLICY_LINK)));
387 bool WalletItems::LegalDocument::operator==(const LegalDocument& other) const {
388 return id_ == other.id_ &&
389 url_ == other.url_ &&
390 display_name_ == other.display_name_;
393 bool WalletItems::LegalDocument::operator!=(const LegalDocument& other) const {
394 return !(*this == other);
397 WalletItems::LegalDocument::LegalDocument(const std::string& id,
398 const base::string16& display_name)
399 : id_(id),
400 url_(kLegalDocumentUrl + id),
401 display_name_(display_name) {}
403 WalletItems::LegalDocument::LegalDocument(const GURL& url,
404 const base::string16& display_name)
405 : url_(url),
406 display_name_(display_name) {}
408 WalletItems::WalletItems(const std::vector<RequiredAction>& required_actions,
409 const std::string& google_transaction_id,
410 const std::string& default_instrument_id,
411 const std::string& default_address_id,
412 AmexPermission amex_permission)
413 : required_actions_(required_actions),
414 google_transaction_id_(google_transaction_id),
415 default_instrument_id_(default_instrument_id),
416 default_address_id_(default_address_id),
417 active_account_index_(std::numeric_limits<size_t>::max()),
418 amex_permission_(amex_permission) {}
420 WalletItems::~WalletItems() {}
422 scoped_ptr<WalletItems>
423 WalletItems::CreateWalletItems(const base::DictionaryValue& dictionary) {
424 std::vector<RequiredAction> required_action;
425 const base::ListValue* required_action_list;
426 if (dictionary.GetList("required_action", &required_action_list)) {
427 for (size_t i = 0; i < required_action_list->GetSize(); ++i) {
428 std::string action_string;
429 if (required_action_list->GetString(i, &action_string)) {
430 RequiredAction action = ParseRequiredActionFromString(action_string);
431 if (!ActionAppliesToWalletItems(action)) {
432 DLOG(ERROR) << "Response from Google wallet with bad required action:"
433 " \"" << action_string << "\"";
434 return scoped_ptr<WalletItems>();
436 required_action.push_back(action);
439 } else {
440 DVLOG(1) << "Response from Google wallet missing required actions";
443 std::string google_transaction_id;
444 if (!dictionary.GetString("google_transaction_id", &google_transaction_id) &&
445 required_action.empty()) {
446 DLOG(ERROR) << "Response from Google wallet missing google transaction id";
447 return scoped_ptr<WalletItems>();
450 std::string default_instrument_id;
451 if (!dictionary.GetString("default_instrument_id", &default_instrument_id))
452 DVLOG(1) << "Response from Google wallet missing default instrument id";
454 std::string default_address_id;
455 if (!dictionary.GetString("default_address_id", &default_address_id))
456 DVLOG(1) << "Response from Google wallet missing default_address_id";
458 // obfuscated_gaia_id is deprecated.
460 bool amex_disallowed = true;
461 if (!dictionary.GetBoolean("amex_disallowed", &amex_disallowed))
462 DVLOG(1) << "Response from Google wallet missing the amex_disallowed field";
463 AmexPermission amex_permission =
464 amex_disallowed ? AMEX_DISALLOWED : AMEX_ALLOWED;
466 scoped_ptr<WalletItems> wallet_items(new WalletItems(required_action,
467 google_transaction_id,
468 default_instrument_id,
469 default_address_id,
470 amex_permission));
471 std::vector<std::string> gaia_accounts;
472 const base::ListValue* gaia_profiles;
473 if (dictionary.GetList("gaia_profile", &gaia_profiles)) {
474 for (size_t i = 0; i < gaia_profiles->GetSize(); ++i) {
475 const base::DictionaryValue* account_dict;
476 std::string email;
477 if (!gaia_profiles->GetDictionary(i, &account_dict))
478 continue;
480 scoped_ptr<GaiaAccount> gaia_account(
481 GaiaAccount::Create(*account_dict));
482 if (gaia_account)
483 wallet_items->AddAccount(gaia_account.Pass());
485 } else {
486 DVLOG(1) << "Response from Google wallet missing GAIA accounts";
489 const base::ListValue* legal_docs;
490 if (dictionary.GetList("required_legal_document", &legal_docs)) {
491 for (size_t i = 0; i < legal_docs->GetSize(); ++i) {
492 const base::DictionaryValue* legal_doc_dict;
493 if (legal_docs->GetDictionary(i, &legal_doc_dict)) {
494 scoped_ptr<LegalDocument> legal_doc(
495 LegalDocument::CreateLegalDocument(*legal_doc_dict));
496 if (legal_doc)
497 wallet_items->AddLegalDocument(legal_doc.Pass());
498 else
499 return scoped_ptr<WalletItems>();
503 if (!legal_docs->empty()) {
504 // Always append the privacy policy link as well.
505 wallet_items->AddLegalDocument(
506 LegalDocument::CreatePrivacyPolicyDocument());
508 } else {
509 DVLOG(1) << "Response from Google wallet missing legal docs";
512 const base::ListValue* instruments;
513 if (dictionary.GetList("instrument", &instruments)) {
514 for (size_t i = 0; i < instruments->GetSize(); ++i) {
515 const base::DictionaryValue* instrument_dict;
516 if (instruments->GetDictionary(i, &instrument_dict)) {
517 scoped_ptr<MaskedInstrument> instrument(
518 MaskedInstrument::CreateMaskedInstrument(*instrument_dict));
519 if (instrument)
520 wallet_items->AddInstrument(instrument.Pass());
523 } else {
524 DVLOG(1) << "Response from Google wallet missing instruments";
527 const base::ListValue* addresses;
528 if (dictionary.GetList("address", &addresses)) {
529 for (size_t i = 0; i < addresses->GetSize(); ++i) {
530 const base::DictionaryValue* address_dict;
531 if (addresses->GetDictionary(i, &address_dict)) {
532 scoped_ptr<Address> address(
533 Address::CreateAddressWithID(*address_dict));
534 if (address)
535 wallet_items->AddAddress(address.Pass());
538 } else {
539 DVLOG(1) << "Response from Google wallet missing addresses";
542 const base::ListValue* allowed_shipping_countries;
543 if (dictionary.GetList("allowed_shipping_spec_by_country",
544 &allowed_shipping_countries)) {
545 for (size_t i = 0; i < allowed_shipping_countries->GetSize(); ++i) {
546 const base::DictionaryValue* country_spec;
547 std::string country_code;
548 if (allowed_shipping_countries->GetDictionary(i, &country_spec) &&
549 country_spec->GetString("country_code", &country_code)) {
550 wallet_items->AddAllowedShippingCountry(country_code);
553 } else {
554 DVLOG(1) << "Response from Google wallet missing allowed shipping"
555 " countries";
558 return wallet_items.Pass();
561 void WalletItems::AddAccount(scoped_ptr<GaiaAccount> account) {
562 if (account->index() != gaia_accounts_.size()) {
563 DVLOG(1) << "Tried to add account out of order";
564 return;
567 if (account->is_active())
568 active_account_index_ = account->index();
570 gaia_accounts_.push_back(account.release());
573 bool WalletItems::operator==(const WalletItems& other) const {
574 return google_transaction_id_ == other.google_transaction_id_ &&
575 default_instrument_id_ == other.default_instrument_id_ &&
576 default_address_id_ == other.default_address_id_ &&
577 required_actions_ == other.required_actions_ &&
578 // This check is technically redundant, but is useful for tests.
579 ObfuscatedGaiaId() == other.ObfuscatedGaiaId() &&
580 active_account_index() == other.active_account_index() &&
581 VectorsAreEqual<GaiaAccount>(gaia_accounts(),
582 other.gaia_accounts()) &&
583 VectorsAreEqual<MaskedInstrument>(instruments(),
584 other.instruments()) &&
585 VectorsAreEqual<Address>(addresses(), other.addresses()) &&
586 VectorsAreEqual<LegalDocument>(legal_documents(),
587 other.legal_documents()) &&
588 allowed_shipping_countries() == other.allowed_shipping_countries();
591 bool WalletItems::operator!=(const WalletItems& other) const {
592 return !(*this == other);
595 } // namespace wallet
596 } // namespace autofill