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 <algorithm>
     10 #include <ostream>
     11 #include <string>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/guid.h"
     15 #include "base/logging.h"
     16 #include "base/strings/string16.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "base/strings/string_split.h"
     19 #include "base/strings/string_util.h"
     20 #include "base/strings/utf_string_conversions.h"
     21 #include "base/time/time.h"
     22 #include "components/autofill/core/browser/autofill_field.h"
     23 #include "components/autofill/core/browser/autofill_regexes.h"
     24 #include "components/autofill/core/browser/autofill_type.h"
     25 #include "components/autofill/core/browser/validation.h"
     26 #include "components/autofill/core/common/form_field_data.h"
     27 #include "grit/components_scaled_resources.h"
     28 #include "grit/components_strings.h"
     29 #include "third_party/icu/source/common/unicode/uloc.h"
     30 #include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
     31 #include "ui/base/l10n/l10n_util.h"
     32 
     33 namespace autofill {
     34 
     35 namespace {
     36 
     37 const base::char16 kCreditCardObfuscationSymbol = '*';
     38 
     39 // This is the maximum obfuscated symbols displayed.
     40 // It is introduced to avoid rare cases where the credit card number is
     41 // too large and fills the screen.
     42 const size_t kMaxObfuscationSize = 20;
     43 
     44 bool ConvertYear(const base::string16& year, int* num) {
     45   // If the |year| is empty, clear the stored value.
     46   if (year.empty()) {
     47     *num = 0;
     48     return true;
     49   }
     50 
     51   // Try parsing the |year| as a number.
     52   if (base::StringToInt(year, num))
     53     return true;
     54 
     55   *num = 0;
     56   return false;
     57 }
     58 
     59 bool ConvertMonth(const base::string16& month,
     60                   const std::string& app_locale,
     61                   int* num) {
     62   // If the |month| is empty, clear the stored value.
     63   if (month.empty()) {
     64     *num = 0;
     65     return true;
     66   }
     67 
     68   // Try parsing the |month| as a number.
     69   if (base::StringToInt(month, num))
     70     return true;
     71 
     72   // If the locale is unknown, give up.
     73   if (app_locale.empty())
     74     return false;
     75 
     76   // Otherwise, try parsing the |month| as a named month, e.g. "January" or
     77   // "Jan".
     78   base::string16 lowercased_month = base::StringToLowerASCII(month);
     79 
     80   UErrorCode status = U_ZERO_ERROR;
     81   icu::Locale locale(app_locale.c_str());
     82   icu::DateFormatSymbols date_format_symbols(locale, status);
     83   DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
     84          status == U_USING_DEFAULT_WARNING);
     85 
     86   int32_t num_months;
     87   const icu::UnicodeString* months = date_format_symbols.getMonths(num_months);
     88   for (int32_t i = 0; i < num_months; ++i) {
     89     const base::string16 icu_month = base::string16(months[i].getBuffer(),
     90                                         months[i].length());
     91     if (lowercased_month == base::StringToLowerASCII(icu_month)) {
     92       *num = i + 1;  // Adjust from 0-indexed to 1-indexed.
     93       return true;
     94     }
     95   }
     96 
     97   months = date_format_symbols.getShortMonths(num_months);
     98   for (int32_t i = 0; i < num_months; ++i) {
     99     const base::string16 icu_month = base::string16(months[i].getBuffer(),
    100                                         months[i].length());
    101     if (lowercased_month == base::StringToLowerASCII(icu_month)) {
    102       *num = i + 1;  // Adjust from 0-indexed to 1-indexed.
    103       return true;
    104     }
    105   }
    106 
    107   *num = 0;
    108   return false;
    109 }
    110 
    111 }  // namespace
    112 
    113 CreditCard::CreditCard(const std::string& guid, const std::string& origin)
    114     : AutofillDataModel(guid, origin),
    115       type_(kGenericCard),
    116       expiration_month_(0),
    117       expiration_year_(0) {
    118 }
    119 
    120 CreditCard::CreditCard()
    121     : AutofillDataModel(base::GenerateGUID(), std::string()),
    122       type_(kGenericCard),
    123       expiration_month_(0),
    124       expiration_year_(0) {
    125 }
    126 
    127 CreditCard::CreditCard(const CreditCard& credit_card)
    128     : AutofillDataModel(std::string(), std::string()) {
    129   operator=(credit_card);
    130 }
    131 
    132 CreditCard::~CreditCard() {}
    133 
    134 // static
    135 const base::string16 CreditCard::StripSeparators(const base::string16& number) {
    136   base::string16 stripped;
    137   base::RemoveChars(number, base::ASCIIToUTF16("- "), &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 const char* 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   DCHECK_EQ(CREDIT_CARD, AutofillType(type).group());
    280   switch (type) {
    281     case CREDIT_CARD_NAME:
    282       return name_on_card_;
    283 
    284     case CREDIT_CARD_EXP_MONTH:
    285       return ExpirationMonthAsString();
    286 
    287     case CREDIT_CARD_EXP_2_DIGIT_YEAR:
    288       return Expiration2DigitYearAsString();
    289 
    290     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
    291       return Expiration4DigitYearAsString();
    292 
    293     case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
    294       base::string16 month = ExpirationMonthAsString();
    295       base::string16 year = Expiration2DigitYearAsString();
    296       if (!month.empty() && !year.empty())
    297         return month + base::ASCIIToUTF16("/") + year;
    298       return base::string16();
    299     }
    300 
    301     case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
    302       base::string16 month = ExpirationMonthAsString();
    303       base::string16 year = Expiration4DigitYearAsString();
    304       if (!month.empty() && !year.empty())
    305         return month + base::ASCIIToUTF16("/") + year;
    306       return base::string16();
    307     }
    308 
    309     case CREDIT_CARD_TYPE:
    310       return TypeForDisplay();
    311 
    312     case CREDIT_CARD_NUMBER:
    313       return number_;
    314 
    315     case CREDIT_CARD_VERIFICATION_CODE:
    316       // Chrome doesn't store credit card verification codes.
    317       return base::string16();
    318 
    319     default:
    320       // ComputeDataPresentForArray will hit this repeatedly.
    321       return base::string16();
    322   }
    323 }
    324 
    325 void CreditCard::SetRawInfo(ServerFieldType type,
    326                             const base::string16& value) {
    327   DCHECK_EQ(CREDIT_CARD, AutofillType(type).group());
    328   switch (type) {
    329     case CREDIT_CARD_NAME:
    330       name_on_card_ = value;
    331       break;
    332 
    333     case CREDIT_CARD_EXP_MONTH:
    334       SetExpirationMonthFromString(value, std::string());
    335       break;
    336 
    337     case CREDIT_CARD_EXP_2_DIGIT_YEAR:
    338       // This is a read-only attribute.
    339       break;
    340 
    341     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
    342       SetExpirationYearFromString(value);
    343       break;
    344 
    345     case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
    346       // This is a read-only attribute.
    347       break;
    348 
    349     case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
    350       // This is a read-only attribute.
    351       break;
    352 
    353     case CREDIT_CARD_TYPE:
    354       // This is a read-only attribute, determined by the credit card number.
    355       break;
    356 
    357     case CREDIT_CARD_NUMBER: {
    358       // Don't change the real value if the input is an obfuscated string.
    359       if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol)
    360         SetNumber(value);
    361       break;
    362     }
    363 
    364     case CREDIT_CARD_VERIFICATION_CODE:
    365       // Chrome doesn't store the credit card verification code.
    366       break;
    367 
    368     default:
    369       NOTREACHED() << "Attempting to set unknown info-type " << type;
    370       break;
    371   }
    372 }
    373 
    374 base::string16 CreditCard::GetInfo(const AutofillType& type,
    375                                    const std::string& app_locale) const {
    376   ServerFieldType storable_type = type.GetStorableType();
    377   if (storable_type == CREDIT_CARD_NUMBER)
    378     return StripSeparators(number_);
    379 
    380   return GetRawInfo(storable_type);
    381 }
    382 
    383 bool CreditCard::SetInfo(const AutofillType& type,
    384                          const base::string16& value,
    385                          const std::string& app_locale) {
    386   ServerFieldType storable_type = type.GetStorableType();
    387   if (storable_type == CREDIT_CARD_NUMBER)
    388     SetRawInfo(storable_type, StripSeparators(value));
    389   else if (storable_type == CREDIT_CARD_EXP_MONTH)
    390     SetExpirationMonthFromString(value, app_locale);
    391   else
    392     SetRawInfo(storable_type, value);
    393 
    394   return true;
    395 }
    396 
    397 void CreditCard::GetMatchingTypes(const base::string16& text,
    398                                   const std::string& app_locale,
    399                                   ServerFieldTypeSet* matching_types) const {
    400   FormGroup::GetMatchingTypes(text, app_locale, matching_types);
    401 
    402   base::string16 card_number =
    403       GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale);
    404   if (!card_number.empty() && StripSeparators(text) == card_number)
    405     matching_types->insert(CREDIT_CARD_NUMBER);
    406 
    407   int month;
    408   if (ConvertMonth(text, app_locale, &month) && month != 0 &&
    409       month == expiration_month_) {
    410     matching_types->insert(CREDIT_CARD_EXP_MONTH);
    411   }
    412 }
    413 
    414 const base::string16 CreditCard::Label() const {
    415   base::string16 label;
    416   if (number().empty())
    417     return name_on_card_;  // No CC number, return name only.
    418 
    419   base::string16 obfuscated_cc_number = ObfuscatedNumber();
    420   if (!expiration_month_ || !expiration_year_)
    421     return obfuscated_cc_number;  // No expiration date set.
    422 
    423   // TODO(georgey): Internationalize date.
    424   base::string16 formatted_date(ExpirationMonthAsString());
    425   formatted_date.append(base::ASCIIToUTF16("/"));
    426   formatted_date.append(Expiration4DigitYearAsString());
    427 
    428   label = l10n_util::GetStringFUTF16(IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT,
    429                                      obfuscated_cc_number,
    430                                      formatted_date);
    431   return label;
    432 }
    433 
    434 void CreditCard::SetInfoForMonthInputType(const base::string16& value) {
    435   // Check if |text| is "yyyy-mm" format first, and check normal month format.
    436   if (!autofill::MatchesPattern(value,
    437                                 base::UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$"))) {
    438     return;
    439   }
    440 
    441   std::vector<base::string16> year_month;
    442   base::SplitString(value, L'-', &year_month);
    443   DCHECK_EQ((int)year_month.size(), 2);
    444   int num = 0;
    445   bool converted = false;
    446   converted = base::StringToInt(year_month[0], &num);
    447   DCHECK(converted);
    448   SetExpirationYear(num);
    449   converted = base::StringToInt(year_month[1], &num);
    450   DCHECK(converted);
    451   SetExpirationMonth(num);
    452 }
    453 
    454 base::string16 CreditCard::ObfuscatedNumber() const {
    455   // If the number is shorter than four digits, there's no need to obfuscate it.
    456   if (number_.size() < 4)
    457     return number_;
    458 
    459   base::string16 number = StripSeparators(number_);
    460 
    461   // Avoid making very long obfuscated numbers.
    462   size_t obfuscated_digits = std::min(kMaxObfuscationSize, number.size() - 4);
    463   base::string16 result(obfuscated_digits, kCreditCardObfuscationSymbol);
    464   return result.append(LastFourDigits());
    465 }
    466 
    467 base::string16 CreditCard::LastFourDigits() const {
    468   static const size_t kNumLastDigits = 4;
    469 
    470   base::string16 number = StripSeparators(number_);
    471   if (number.size() < kNumLastDigits)
    472     return base::string16();
    473 
    474   return number.substr(number.size() - kNumLastDigits, kNumLastDigits);
    475 }
    476 
    477 base::string16 CreditCard::TypeForDisplay() const {
    478   return CreditCard::TypeForDisplay(type_);
    479 }
    480 
    481 base::string16 CreditCard::TypeAndLastFourDigits() const {
    482   base::string16 type = TypeForDisplay();
    483   // TODO(estade): type may be empty, we probably want to return
    484   // "Card - 1234" or something in that case.
    485 
    486   base::string16 digits = LastFourDigits();
    487   if (digits.empty())
    488     return type;
    489 
    490   // TODO(estade): i18n.
    491   return type + base::ASCIIToUTF16(" - ") + digits;
    492 }
    493 
    494 void CreditCard::operator=(const CreditCard& credit_card) {
    495   if (this == &credit_card)
    496     return;
    497 
    498   number_ = credit_card.number_;
    499   name_on_card_ = credit_card.name_on_card_;
    500   type_ = credit_card.type_;
    501   expiration_month_ = credit_card.expiration_month_;
    502   expiration_year_ = credit_card.expiration_year_;
    503 
    504   set_guid(credit_card.guid());
    505   set_origin(credit_card.origin());
    506 }
    507 
    508 bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card,
    509                                         const std::string& app_locale) {
    510   if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale) !=
    511           imported_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale)) {
    512     return false;
    513   }
    514 
    515   // Heuristically aggregated data should never overwrite verified data.
    516   // Instead, discard any heuristically aggregated credit cards that disagree
    517   // with explicitly entered data, so that the UI is not cluttered with
    518   // duplicate cards.
    519   if (this->IsVerified() && !imported_card.IsVerified())
    520     return true;
    521 
    522   set_origin(imported_card.origin());
    523 
    524   // Note that the card number is intentionally not updated, so as to preserve
    525   // any formatting (i.e. separator characters).  Since the card number is not
    526   // updated, there is no reason to update the card type, either.
    527   if (!imported_card.name_on_card_.empty())
    528     name_on_card_ = imported_card.name_on_card_;
    529 
    530   // The expiration date for |imported_card| should always be set.
    531   DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_);
    532   expiration_month_ = imported_card.expiration_month_;
    533   expiration_year_ = imported_card.expiration_year_;
    534 
    535   return true;
    536 }
    537 
    538 int CreditCard::Compare(const CreditCard& credit_card) const {
    539   // The following CreditCard field types are the only types we store in the
    540   // WebDB so far, so we're only concerned with matching these types in the
    541   // credit card.
    542   const ServerFieldType types[] = { CREDIT_CARD_NAME,
    543                                     CREDIT_CARD_NUMBER,
    544                                     CREDIT_CARD_EXP_MONTH,
    545                                     CREDIT_CARD_EXP_4_DIGIT_YEAR };
    546   for (size_t i = 0; i < arraysize(types); ++i) {
    547     int comparison =
    548         GetRawInfo(types[i]).compare(credit_card.GetRawInfo(types[i]));
    549     if (comparison != 0)
    550       return comparison;
    551   }
    552 
    553   return 0;
    554 }
    555 
    556 bool CreditCard::operator==(const CreditCard& credit_card) const {
    557   return guid() == credit_card.guid() &&
    558          origin() == credit_card.origin() &&
    559          Compare(credit_card) == 0;
    560 }
    561 
    562 bool CreditCard::operator!=(const CreditCard& credit_card) const {
    563   return !operator==(credit_card);
    564 }
    565 
    566 bool CreditCard::IsEmpty(const std::string& app_locale) const {
    567   ServerFieldTypeSet types;
    568   GetNonEmptyTypes(app_locale, &types);
    569   return types.empty();
    570 }
    571 
    572 bool CreditCard::IsComplete() const {
    573   return
    574       autofill::IsValidCreditCardNumber(number_) &&
    575       expiration_month_ != 0 &&
    576       expiration_year_ != 0;
    577 }
    578 
    579 bool CreditCard::IsValid() const {
    580   return autofill::IsValidCreditCardNumber(number_) &&
    581          autofill::IsValidCreditCardExpirationDate(
    582              expiration_year_, expiration_month_, base::Time::Now());
    583 }
    584 
    585 void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
    586   supported_types->insert(CREDIT_CARD_NAME);
    587   supported_types->insert(CREDIT_CARD_NUMBER);
    588   supported_types->insert(CREDIT_CARD_TYPE);
    589   supported_types->insert(CREDIT_CARD_EXP_MONTH);
    590   supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR);
    591   supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
    592   supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
    593   supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
    594 }
    595 
    596 base::string16 CreditCard::ExpirationMonthAsString() const {
    597   if (expiration_month_ == 0)
    598     return base::string16();
    599 
    600   base::string16 month = base::IntToString16(expiration_month_);
    601   if (expiration_month_ >= 10)
    602     return month;
    603 
    604   base::string16 zero = base::ASCIIToUTF16("0");
    605   zero.append(month);
    606   return zero;
    607 }
    608 
    609 base::string16 CreditCard::Expiration4DigitYearAsString() const {
    610   if (expiration_year_ == 0)
    611     return base::string16();
    612 
    613   return base::IntToString16(Expiration4DigitYear());
    614 }
    615 
    616 base::string16 CreditCard::Expiration2DigitYearAsString() const {
    617   if (expiration_year_ == 0)
    618     return base::string16();
    619 
    620   return base::IntToString16(Expiration2DigitYear());
    621 }
    622 
    623 void CreditCard::SetExpirationMonthFromString(const base::string16& text,
    624                                               const std::string& app_locale) {
    625   int month;
    626   if (!ConvertMonth(text, app_locale, &month))
    627     return;
    628 
    629   SetExpirationMonth(month);
    630 }
    631 
    632 void CreditCard::SetExpirationYearFromString(const base::string16& text) {
    633   int year;
    634   if (!ConvertYear(text, &year))
    635     return;
    636 
    637   SetExpirationYear(year);
    638 }
    639 
    640 void CreditCard::SetNumber(const base::string16& number) {
    641   number_ = number;
    642   type_ = GetCreditCardType(StripSeparators(number_));
    643 }
    644 
    645 void CreditCard::SetExpirationMonth(int expiration_month) {
    646   if (expiration_month < 0 || expiration_month > 12)
    647     return;
    648 
    649   expiration_month_ = expiration_month;
    650 }
    651 
    652 void CreditCard::SetExpirationYear(int expiration_year) {
    653   if (expiration_year != 0 &&
    654       (expiration_year < 2006 || expiration_year > 10000)) {
    655     return;
    656   }
    657 
    658   expiration_year_ = expiration_year;
    659 }
    660 
    661 // So we can compare CreditCards with EXPECT_EQ().
    662 std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) {
    663   return os
    664       << base::UTF16ToUTF8(credit_card.Label())
    665       << " "
    666       << credit_card.guid()
    667       << " "
    668       << credit_card.origin()
    669       << " "
    670       << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME))
    671       << " "
    672       << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE))
    673       << " "
    674       << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER))
    675       << " "
    676       << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH))
    677       << " "
    678       << base::UTF16ToUTF8(
    679              credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
    680 }
    681 
    682 // These values must match the values in WebKitPlatformSupportImpl in
    683 // webkit/glue. We send these strings to WebKit, which then asks
    684 // WebKitPlatformSupportImpl to load the image data.
    685 const char* const kAmericanExpressCard = "americanExpressCC";
    686 const char* const kDinersCard = "dinersCC";
    687 const char* const kDiscoverCard = "discoverCC";
    688 const char* const kGenericCard = "genericCC";
    689 const char* const kJCBCard = "jcbCC";
    690 const char* const kMasterCard = "masterCardCC";
    691 const char* const kUnionPay = "unionPayCC";
    692 const char* const kVisaCard = "visaCC";
    693 
    694 }  // namespace autofill
    695