Home | History | Annotate | Download | only in browser
      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/core/browser/credit_card.h"
      6 
      7 #include <stddef.h>
      8 
      9 #include <ostream>
     10 #include <string>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/guid.h"
     14 #include "base/logging.h"
     15 #include "base/strings/string16.h"
     16 #include "base/strings/string_number_conversions.h"
     17 #include "base/strings/string_split.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/strings/utf_string_conversions.h"
     20 #include "base/time/time.h"
     21 #include "components/autofill/core/browser/autofill_field.h"
     22 #include "components/autofill/core/browser/autofill_regexes.h"
     23 #include "components/autofill/core/browser/autofill_type.h"
     24 #include "components/autofill/core/browser/validation.h"
     25 #include "components/autofill/core/common/form_field_data.h"
     26 #include "grit/component_strings.h"
     27 #include "grit/webkit_resources.h"
     28 #include "third_party/icu/source/common/unicode/uloc.h"
     29 #include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
     30 #include "ui/base/l10n/l10n_util.h"
     31 
     32 namespace autofill {
     33 
     34 namespace {
     35 
     36 const char16 kCreditCardObfuscationSymbol = '*';
     37 
     38 // This is the maximum obfuscated symbols displayed.
     39 // It is introduced to avoid rare cases where the credit card number is
     40 // too large and fills the screen.
     41 const size_t kMaxObfuscationSize = 20;
     42 
     43 bool ConvertYear(const base::string16& year, int* num) {
     44   // If the |year| is empty, clear the stored value.
     45   if (year.empty()) {
     46     *num = 0;
     47     return true;
     48   }
     49 
     50   // Try parsing the |year| as a number.
     51   if (base::StringToInt(year, num))
     52     return true;
     53 
     54   *num = 0;
     55   return false;
     56 }
     57 
     58 bool ConvertMonth(const base::string16& month,
     59                   const std::string& app_locale,
     60                   int* num) {
     61   // If the |month| is empty, clear the stored value.
     62   if (month.empty()) {
     63     *num = 0;
     64     return true;
     65   }
     66 
     67   // Try parsing the |month| as a number.
     68   if (base::StringToInt(month, num))
     69     return true;
     70 
     71   // If the locale is unknown, give up.
     72   if (app_locale.empty())
     73     return false;
     74 
     75   // Otherwise, try parsing the |month| as a named month, e.g. "January" or
     76   // "Jan".
     77   base::string16 lowercased_month = StringToLowerASCII(month);
     78 
     79   UErrorCode status = U_ZERO_ERROR;
     80   icu::Locale locale(app_locale.c_str());
     81   icu::DateFormatSymbols date_format_symbols(locale, status);
     82   DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
     83          status == U_USING_DEFAULT_WARNING);
     84 
     85   int32_t num_months;
     86   const icu::UnicodeString* months = date_format_symbols.getMonths(num_months);
     87   for (int32_t i = 0; i < num_months; ++i) {
     88     const base::string16 icu_month = base::string16(months[i].getBuffer(),
     89                                         months[i].length());
     90     if (lowercased_month == StringToLowerASCII(icu_month)) {
     91       *num = i + 1;  // Adjust from 0-indexed to 1-indexed.
     92       return true;
     93     }
     94   }
     95 
     96   months = date_format_symbols.getShortMonths(num_months);
     97   for (int32_t i = 0; i < num_months; ++i) {
     98     const base::string16 icu_month = base::string16(months[i].getBuffer(),
     99                                         months[i].length());
    100     if (lowercased_month == StringToLowerASCII(icu_month)) {
    101       *num = i + 1;  // Adjust from 0-indexed to 1-indexed.
    102       return true;
    103     }
    104   }
    105 
    106   *num = 0;
    107   return false;
    108 }
    109 
    110 }  // namespace
    111 
    112 CreditCard::CreditCard(const std::string& guid, const std::string& origin)
    113     : AutofillDataModel(guid, origin),
    114       type_(kGenericCard),
    115       expiration_month_(0),
    116       expiration_year_(0) {
    117 }
    118 
    119 CreditCard::CreditCard()
    120     : AutofillDataModel(base::GenerateGUID(), std::string()),
    121       type_(kGenericCard),
    122       expiration_month_(0),
    123       expiration_year_(0) {
    124 }
    125 
    126 CreditCard::CreditCard(const CreditCard& credit_card)
    127     : AutofillDataModel(std::string(), std::string()) {
    128   operator=(credit_card);
    129 }
    130 
    131 CreditCard::~CreditCard() {}
    132 
    133 // static
    134 const base::string16 CreditCard::StripSeparators(const base::string16& number) {
    135   const char16 kSeparators[] = {'-', ' ', '\0'};
    136   base::string16 stripped;
    137   RemoveChars(number, kSeparators, &stripped);
    138   return stripped;
    139 }
    140 
    141 // static
    142 base::string16 CreditCard::TypeForDisplay(const std::string& type) {
    143   if (type == kAmericanExpressCard)
    144     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX);
    145   if (type == kDinersCard)
    146     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS);
    147   if (type == kDiscoverCard)
    148     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER);
    149   if (type == kJCBCard)
    150     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB);
    151   if (type == kMasterCard)
    152     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD);
    153   if (type == kUnionPay)
    154     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_UNION_PAY);
    155   if (type == kVisaCard)
    156     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA);
    157 
    158   // If you hit this DCHECK, the above list of cases needs to be updated to
    159   // include a new card.
    160   DCHECK_EQ(kGenericCard, type);
    161   return base::string16();
    162 }
    163 
    164 // static
    165 int CreditCard::IconResourceId(const std::string& type) {
    166   if (type == kAmericanExpressCard)
    167     return IDR_AUTOFILL_CC_AMEX;
    168   if (type == kDinersCard)
    169     return IDR_AUTOFILL_CC_DINERS;
    170   if (type == kDiscoverCard)
    171     return IDR_AUTOFILL_CC_DISCOVER;
    172   if (type == kJCBCard)
    173     return IDR_AUTOFILL_CC_JCB;
    174   if (type == kMasterCard)
    175     return IDR_AUTOFILL_CC_MASTERCARD;
    176   if (type == kUnionPay)
    177     return IDR_AUTOFILL_CC_GENERIC;  // Needs resource: http://crbug.com/259211
    178   if (type == kVisaCard)
    179     return IDR_AUTOFILL_CC_VISA;
    180 
    181   // If you hit this DCHECK, the above list of cases needs to be updated to
    182   // include a new card.
    183   DCHECK_EQ(kGenericCard, type);
    184   return IDR_AUTOFILL_CC_GENERIC;
    185 }
    186 
    187 // static
    188 std::string CreditCard::GetCreditCardType(const base::string16& number) {
    189   // Credit card number specifications taken from:
    190   // http://en.wikipedia.org/wiki/Credit_card_numbers,
    191   // http://en.wikipedia.org/wiki/List_of_Issuer_Identification_Numbers,
    192   // http://www.discovernetwork.com/merchants/images/Merchant_Marketing_PDF.pdf,
    193   // http://www.regular-expressions.info/creditcard.html,
    194   // http://developer.ean.com/general_info/Valid_Credit_Card_Types,
    195   // http://www.bincodes.com/,
    196   // http://www.fraudpractice.com/FL-binCC.html, and
    197   // http://www.beachnet.com/~hstiles/cardtype.html
    198   //
    199   // The last site is currently unavailable, but a cached version remains at
    200   // http://web.archive.org/web/20120923111349/http://www.beachnet.com/~hstiles/cardtype.html
    201   //
    202   // Card Type              Prefix(es)                      Length
    203   // ---------------------------------------------------------------
    204   // Visa                   4                               13,16
    205   // American Express       34,37                           15
    206   // Diners Club            300-305,3095,36,38-39           14
    207   // Discover Card          6011,644-649,65                 16
    208   // JCB                    3528-3589                       16
    209   // MasterCard             51-55                           16
    210   // UnionPay               62                              16-19
    211 
    212   // Check for prefixes of length 1.
    213   if (number.empty())
    214     return kGenericCard;
    215 
    216   if (number[0] == '4')
    217     return kVisaCard;
    218 
    219   // Check for prefixes of length 2.
    220   if (number.size() < 2)
    221     return kGenericCard;
    222 
    223   int first_two_digits = 0;
    224   if (!base::StringToInt(number.substr(0, 2), &first_two_digits))
    225     return kGenericCard;
    226 
    227   if (first_two_digits == 34 || first_two_digits == 37)
    228     return kAmericanExpressCard;
    229 
    230   if (first_two_digits == 36 ||
    231       first_two_digits == 38 ||
    232       first_two_digits == 39)
    233     return kDinersCard;
    234 
    235   if (first_two_digits >= 51 && first_two_digits <= 55)
    236     return kMasterCard;
    237 
    238   if (first_two_digits == 62)
    239     return kUnionPay;
    240 
    241   if (first_two_digits == 65)
    242     return kDiscoverCard;
    243 
    244   // Check for prefixes of length 3.
    245   if (number.size() < 3)
    246     return kGenericCard;
    247 
    248   int first_three_digits = 0;
    249   if (!base::StringToInt(number.substr(0, 3), &first_three_digits))
    250     return kGenericCard;
    251 
    252   if (first_three_digits >= 300 && first_three_digits <= 305)
    253     return kDinersCard;
    254 
    255   if (first_three_digits >= 644 && first_three_digits <= 649)
    256     return kDiscoverCard;
    257 
    258   // Check for prefixes of length 4.
    259   if (number.size() < 4)
    260     return kGenericCard;
    261 
    262   int first_four_digits = 0;
    263   if (!base::StringToInt(number.substr(0, 4), &first_four_digits))
    264     return kGenericCard;
    265 
    266   if (first_four_digits == 3095)
    267     return kDinersCard;
    268 
    269   if (first_four_digits >= 3528 && first_four_digits <= 3589)
    270     return kJCBCard;
    271 
    272   if (first_four_digits == 6011)
    273     return kDiscoverCard;
    274 
    275   return kGenericCard;
    276 }
    277 
    278 base::string16 CreditCard::GetRawInfo(ServerFieldType type) const {
    279   switch (type) {
    280     case CREDIT_CARD_NAME:
    281       return name_on_card_;
    282 
    283     case CREDIT_CARD_EXP_MONTH:
    284       return ExpirationMonthAsString();
    285 
    286     case CREDIT_CARD_EXP_2_DIGIT_YEAR:
    287       return Expiration2DigitYearAsString();
    288 
    289     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
    290       return Expiration4DigitYearAsString();
    291 
    292     case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
    293       base::string16 month = ExpirationMonthAsString();
    294       base::string16 year = Expiration2DigitYearAsString();
    295       if (!month.empty() && !year.empty())
    296         return month + ASCIIToUTF16("/") + year;
    297       return base::string16();
    298     }
    299 
    300     case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
    301       base::string16 month = ExpirationMonthAsString();
    302       base::string16 year = Expiration4DigitYearAsString();
    303       if (!month.empty() && !year.empty())
    304         return month + ASCIIToUTF16("/") + year;
    305       return base::string16();
    306     }
    307 
    308     case CREDIT_CARD_TYPE:
    309       return TypeForDisplay();
    310 
    311     case CREDIT_CARD_NUMBER:
    312       return number_;
    313 
    314     case CREDIT_CARD_VERIFICATION_CODE:
    315       // Chrome doesn't store credit card verification codes.
    316       return base::string16();
    317 
    318     default:
    319       // ComputeDataPresentForArray will hit this repeatedly.
    320       return base::string16();
    321   }
    322 }
    323 
    324 void CreditCard::SetRawInfo(ServerFieldType type,
    325                             const base::string16& value) {
    326   switch (type) {
    327     case CREDIT_CARD_NAME:
    328       name_on_card_ = value;
    329       break;
    330 
    331     case CREDIT_CARD_EXP_MONTH:
    332       SetExpirationMonthFromString(value, std::string());
    333       break;
    334 
    335     case CREDIT_CARD_EXP_2_DIGIT_YEAR:
    336       // This is a read-only attribute.
    337       break;
    338 
    339     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
    340       SetExpirationYearFromString(value);
    341       break;
    342 
    343     case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
    344       // This is a read-only attribute.
    345       break;
    346 
    347     case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
    348       // This is a read-only attribute.
    349       break;
    350 
    351     case CREDIT_CARD_TYPE:
    352       // This is a read-only attribute, determined by the credit card number.
    353       break;
    354 
    355     case CREDIT_CARD_NUMBER: {
    356       // Don't change the real value if the input is an obfuscated string.
    357       if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol)
    358         SetNumber(value);
    359       break;
    360     }
    361 
    362     case CREDIT_CARD_VERIFICATION_CODE:
    363       // Chrome doesn't store the credit card verification code.
    364       break;
    365 
    366     default:
    367       NOTREACHED() << "Attempting to set unknown info-type " << type;
    368       break;
    369   }
    370 }
    371 
    372 base::string16 CreditCard::GetInfo(const AutofillType& type,
    373                                    const std::string& app_locale) const {
    374   ServerFieldType storable_type = type.GetStorableType();
    375   if (storable_type == CREDIT_CARD_NUMBER)
    376     return StripSeparators(number_);
    377 
    378   return GetRawInfo(storable_type);
    379 }
    380 
    381 bool CreditCard::SetInfo(const AutofillType& type,
    382                          const base::string16& value,
    383                          const std::string& app_locale) {
    384   ServerFieldType storable_type = type.GetStorableType();
    385   if (storable_type == CREDIT_CARD_NUMBER)
    386     SetRawInfo(storable_type, StripSeparators(value));
    387   else if (storable_type == CREDIT_CARD_EXP_MONTH)
    388     SetExpirationMonthFromString(value, app_locale);
    389   else
    390     SetRawInfo(storable_type, value);
    391 
    392   return true;
    393 }
    394 
    395 void CreditCard::GetMatchingTypes(const base::string16& text,
    396                                   const std::string& app_locale,
    397                                   ServerFieldTypeSet* matching_types) const {
    398   FormGroup::GetMatchingTypes(text, app_locale, matching_types);
    399 
    400   base::string16 card_number =
    401       GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale);
    402   if (!card_number.empty() && StripSeparators(text) == card_number)
    403     matching_types->insert(CREDIT_CARD_NUMBER);
    404 
    405   int month;
    406   if (ConvertMonth(text, app_locale, &month) && month != 0 &&
    407       month == expiration_month_) {
    408     matching_types->insert(CREDIT_CARD_EXP_MONTH);
    409   }
    410 }
    411 
    412 const base::string16 CreditCard::Label() const {
    413   base::string16 label;
    414   if (number().empty())
    415     return name_on_card_;  // No CC number, return name only.
    416 
    417   base::string16 obfuscated_cc_number = ObfuscatedNumber();
    418   if (!expiration_month_ || !expiration_year_)
    419     return obfuscated_cc_number;  // No expiration date set.
    420 
    421   // TODO(georgey): Internationalize date.
    422   base::string16 formatted_date(ExpirationMonthAsString());
    423   formatted_date.append(ASCIIToUTF16("/"));
    424   formatted_date.append(Expiration4DigitYearAsString());
    425 
    426   label = l10n_util::GetStringFUTF16(IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT,
    427                                      obfuscated_cc_number,
    428                                      formatted_date);
    429   return label;
    430 }
    431 
    432 void CreditCard::SetInfoForMonthInputType(const base::string16& value) {
    433   // Check if |text| is "yyyy-mm" format first, and check normal month format.
    434   if (!autofill::MatchesPattern(value, UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$")))
    435     return;
    436 
    437   std::vector<base::string16> year_month;
    438   base::SplitString(value, L'-', &year_month);
    439   DCHECK_EQ((int)year_month.size(), 2);
    440   int num = 0;
    441   bool converted = false;
    442   converted = base::StringToInt(year_month[0], &num);
    443   DCHECK(converted);
    444   SetExpirationYear(num);
    445   converted = base::StringToInt(year_month[1], &num);
    446   DCHECK(converted);
    447   SetExpirationMonth(num);
    448 }
    449 
    450 base::string16 CreditCard::ObfuscatedNumber() const {
    451   // If the number is shorter than four digits, there's no need to obfuscate it.
    452   if (number_.size() < 4)
    453     return number_;
    454 
    455   base::string16 number = StripSeparators(number_);
    456 
    457   // Avoid making very long obfuscated numbers.
    458   size_t obfuscated_digits = std::min(kMaxObfuscationSize, number.size() - 4);
    459   base::string16 result(obfuscated_digits, kCreditCardObfuscationSymbol);
    460   return result.append(LastFourDigits());
    461 }
    462 
    463 base::string16 CreditCard::LastFourDigits() const {
    464   static const size_t kNumLastDigits = 4;
    465 
    466   base::string16 number = StripSeparators(number_);
    467   if (number.size() < kNumLastDigits)
    468     return base::string16();
    469 
    470   return number.substr(number.size() - kNumLastDigits, kNumLastDigits);
    471 }
    472 
    473 base::string16 CreditCard::TypeForDisplay() const {
    474   return CreditCard::TypeForDisplay(type_);
    475 }
    476 
    477 base::string16 CreditCard::TypeAndLastFourDigits() const {
    478   base::string16 type = TypeForDisplay();
    479   // TODO(estade): type may be empty, we probably want to return
    480   // "Card - 1234" or something in that case.
    481 
    482   base::string16 digits = LastFourDigits();
    483   if (digits.empty())
    484     return type;
    485 
    486   // TODO(estade): i18n.
    487   return type + ASCIIToUTF16(" - ") + digits;
    488 }
    489 
    490 void CreditCard::operator=(const CreditCard& credit_card) {
    491   if (this == &credit_card)
    492     return;
    493 
    494   number_ = credit_card.number_;
    495   name_on_card_ = credit_card.name_on_card_;
    496   type_ = credit_card.type_;
    497   expiration_month_ = credit_card.expiration_month_;
    498   expiration_year_ = credit_card.expiration_year_;
    499 
    500   set_guid(credit_card.guid());
    501   set_origin(credit_card.origin());
    502 }
    503 
    504 bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card,
    505                                         const std::string& app_locale) {
    506   if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale) !=
    507           imported_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale)) {
    508     return false;
    509   }
    510 
    511   // Heuristically aggregated data should never overwrite verified data.
    512   // Instead, discard any heuristically aggregated credit cards that disagree
    513   // with explicitly entered data, so that the UI is not cluttered with
    514   // duplicate cards.
    515   if (this->IsVerified() && !imported_card.IsVerified())
    516     return true;
    517 
    518   set_origin(imported_card.origin());
    519 
    520   // Note that the card number is intentionally not updated, so as to preserve
    521   // any formatting (i.e. separator characters).  Since the card number is not
    522   // updated, there is no reason to update the card type, either.
    523   if (!imported_card.name_on_card_.empty())
    524     name_on_card_ = imported_card.name_on_card_;
    525 
    526   // The expiration date for |imported_card| should always be set.
    527   DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_);
    528   expiration_month_ = imported_card.expiration_month_;
    529   expiration_year_ = imported_card.expiration_year_;
    530 
    531   return true;
    532 }
    533 
    534 void CreditCard::FillFormField(const AutofillField& field,
    535                                size_t /*variant*/,
    536                                const std::string& app_locale,
    537                                FormFieldData* field_data) const {
    538   DCHECK_EQ(CREDIT_CARD, field.Type().group());
    539   DCHECK(field_data);
    540 
    541   if (field_data->form_control_type == "select-one") {
    542     FillSelectControl(field.Type(), app_locale, field_data);
    543   } else if (field_data->form_control_type == "month") {
    544     // HTML5 input="month" consists of year-month.
    545     base::string16 year =
    546         GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale);
    547     base::string16 month =
    548         GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale);
    549     if (!year.empty() && !month.empty()) {
    550       // Fill the value only if |this| includes both year and month
    551       // information.
    552       field_data->value = year + ASCIIToUTF16("-") + month;
    553     }
    554   } else {
    555     field_data->value = GetInfo(field.Type(), app_locale);
    556   }
    557 }
    558 
    559 int CreditCard::Compare(const CreditCard& credit_card) const {
    560   // The following CreditCard field types are the only types we store in the
    561   // WebDB so far, so we're only concerned with matching these types in the
    562   // credit card.
    563   const ServerFieldType types[] = { CREDIT_CARD_NAME,
    564                                     CREDIT_CARD_NUMBER,
    565                                     CREDIT_CARD_EXP_MONTH,
    566                                     CREDIT_CARD_EXP_4_DIGIT_YEAR };
    567   for (size_t i = 0; i < arraysize(types); ++i) {
    568     int comparison =
    569         GetRawInfo(types[i]).compare(credit_card.GetRawInfo(types[i]));
    570     if (comparison != 0)
    571       return comparison;
    572   }
    573 
    574   return 0;
    575 }
    576 
    577 bool CreditCard::operator==(const CreditCard& credit_card) const {
    578   return guid() == credit_card.guid() &&
    579          origin() == credit_card.origin() &&
    580          Compare(credit_card) == 0;
    581 }
    582 
    583 bool CreditCard::operator!=(const CreditCard& credit_card) const {
    584   return !operator==(credit_card);
    585 }
    586 
    587 bool CreditCard::IsEmpty(const std::string& app_locale) const {
    588   ServerFieldTypeSet types;
    589   GetNonEmptyTypes(app_locale, &types);
    590   return types.empty();
    591 }
    592 
    593 bool CreditCard::IsComplete() const {
    594   return
    595       autofill::IsValidCreditCardNumber(number_) &&
    596       expiration_month_ != 0 &&
    597       expiration_year_ != 0;
    598 }
    599 
    600 bool CreditCard::IsValid() const {
    601   return autofill::IsValidCreditCardNumber(number_) &&
    602          autofill::IsValidCreditCardExpirationDate(
    603              expiration_year_, expiration_month_, base::Time::Now());
    604 }
    605 
    606 void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
    607   supported_types->insert(CREDIT_CARD_NAME);
    608   supported_types->insert(CREDIT_CARD_NUMBER);
    609   supported_types->insert(CREDIT_CARD_TYPE);
    610   supported_types->insert(CREDIT_CARD_EXP_MONTH);
    611   supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR);
    612   supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
    613   supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
    614   supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
    615 }
    616 
    617 base::string16 CreditCard::ExpirationMonthAsString() const {
    618   if (expiration_month_ == 0)
    619     return base::string16();
    620 
    621   base::string16 month = base::IntToString16(expiration_month_);
    622   if (expiration_month_ >= 10)
    623     return month;
    624 
    625   base::string16 zero = ASCIIToUTF16("0");
    626   zero.append(month);
    627   return zero;
    628 }
    629 
    630 base::string16 CreditCard::Expiration4DigitYearAsString() const {
    631   if (expiration_year_ == 0)
    632     return base::string16();
    633 
    634   return base::IntToString16(Expiration4DigitYear());
    635 }
    636 
    637 base::string16 CreditCard::Expiration2DigitYearAsString() const {
    638   if (expiration_year_ == 0)
    639     return base::string16();
    640 
    641   return base::IntToString16(Expiration2DigitYear());
    642 }
    643 
    644 void CreditCard::SetExpirationMonthFromString(const base::string16& text,
    645                                               const std::string& app_locale) {
    646   int month;
    647   if (!ConvertMonth(text, app_locale, &month))
    648     return;
    649 
    650   SetExpirationMonth(month);
    651 }
    652 
    653 void CreditCard::SetExpirationYearFromString(const base::string16& text) {
    654   int year;
    655   if (!ConvertYear(text, &year))
    656     return;
    657 
    658   SetExpirationYear(year);
    659 }
    660 
    661 void CreditCard::SetNumber(const base::string16& number) {
    662   number_ = number;
    663   type_ = GetCreditCardType(StripSeparators(number_));
    664 }
    665 
    666 void CreditCard::SetExpirationMonth(int expiration_month) {
    667   if (expiration_month < 0 || expiration_month > 12)
    668     return;
    669 
    670   expiration_month_ = expiration_month;
    671 }
    672 
    673 void CreditCard::SetExpirationYear(int expiration_year) {
    674   if (expiration_year != 0 &&
    675       (expiration_year < 2006 || expiration_year > 10000)) {
    676     return;
    677   }
    678 
    679   expiration_year_ = expiration_year;
    680 }
    681 
    682 // So we can compare CreditCards with EXPECT_EQ().
    683 std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) {
    684   return os
    685       << UTF16ToUTF8(credit_card.Label())
    686       << " "
    687       << credit_card.guid()
    688       << " "
    689       << credit_card.origin()
    690       << " "
    691       << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME))
    692       << " "
    693       << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE))
    694       << " "
    695       << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER))
    696       << " "
    697       << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH))
    698       << " "
    699       << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
    700 }
    701 
    702 // These values must match the values in WebKitPlatformSupportImpl in
    703 // webkit/glue. We send these strings to WebKit, which then asks
    704 // WebKitPlatformSupportImpl to load the image data.
    705 const char* const kAmericanExpressCard = "americanExpressCC";
    706 const char* const kDinersCard = "dinersCC";
    707 const char* const kDiscoverCard = "discoverCC";
    708 const char* const kGenericCard = "genericCC";
    709 const char* const kJCBCard = "jcbCC";
    710 const char* const kMasterCard = "masterCardCC";
    711 const char* const kUnionPay = "unionPayCC";
    712 const char* const kVisaCard = "visaCC";
    713 
    714 }  // namespace autofill
    715