Home | History | Annotate | Download | only in autofill
      1 // Copyright (c) 2011 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/credit_card.h"
      6 
      7 #include <stddef.h>
      8 #include <string>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/logging.h"
     12 #include "base/string16.h"
     13 #include "base/string_number_conversions.h"
     14 #include "base/string_split.h"
     15 #include "base/string_util.h"
     16 #include "base/utf_string_conversions.h"
     17 #include "chrome/browser/autofill/autofill_type.h"
     18 #include "chrome/browser/autofill/field_types.h"
     19 #include "chrome/browser/autofill/form_field.h"
     20 #include "chrome/common/guid.h"
     21 #include "grit/generated_resources.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 
     24 namespace {
     25 
     26 const char16 kCreditCardObfuscationSymbol = '*';
     27 
     28 const AutofillFieldType kAutofillCreditCardTypes[] = {
     29   CREDIT_CARD_NAME,
     30   CREDIT_CARD_NUMBER,
     31   CREDIT_CARD_TYPE,
     32   CREDIT_CARD_EXP_MONTH,
     33   CREDIT_CARD_EXP_4_DIGIT_YEAR,
     34 };
     35 
     36 const int kAutofillCreditCardLength = arraysize(kAutofillCreditCardTypes);
     37 
     38 std::string GetCreditCardType(const string16& number) {
     39   // Don't check for a specific type if this is not a credit card number.
     40   if (!CreditCard::IsValidCreditCardNumber(number))
     41     return kGenericCard;
     42 
     43   // Credit card number specifications taken from:
     44   // http://en.wikipedia.org/wiki/Credit_card_numbers and
     45   // http://www.beachnet.com/~hstiles/cardtype.html
     46   // Card Type              Prefix(es)                      Length
     47   // ---------------------------------------------------------------
     48   // Visa                   4                               13,16
     49   // American Express       34,37                           15
     50   // Diners Club            300-305,2014,2149,36,           14,15
     51   // Discover Card          6011,65                         16
     52   // JCB                    3                               16
     53   // JCB                    2131,1800                       15
     54   // MasterCard             51-55                           16
     55   // Solo (debit card)      6334,6767                       16,18,19
     56 
     57   // We need at least 4 digits to work with.
     58   if (number.length() < 4)
     59     return kGenericCard;
     60 
     61   int first_four_digits = 0;
     62   if (!base::StringToInt(number.substr(0, 4), &first_four_digits))
     63     return kGenericCard;
     64 
     65   int first_three_digits = first_four_digits / 10;
     66   int first_two_digits = first_three_digits / 10;
     67   int first_digit = first_two_digits / 10;
     68 
     69   switch (number.length()) {
     70     case 13:
     71       if (first_digit == 4)
     72         return kVisaCard;
     73 
     74       break;
     75     case 14:
     76       if (first_three_digits >= 300 && first_three_digits <=305)
     77         return kDinersCard;
     78 
     79       if (first_digit == 36)
     80         return kDinersCard;
     81 
     82       break;
     83     case 15:
     84       if (first_two_digits == 34 || first_two_digits == 37)
     85         return kAmericanExpressCard;
     86 
     87       if (first_four_digits == 2131 || first_four_digits == 1800)
     88         return kJCBCard;
     89 
     90       if (first_four_digits == 2014 || first_four_digits == 2149)
     91         return kDinersCard;
     92 
     93       break;
     94     case 16:
     95       if (first_four_digits == 6011 || first_two_digits == 65)
     96         return kDiscoverCard;
     97 
     98       if (first_four_digits == 6334 || first_four_digits == 6767)
     99         return kSoloCard;
    100 
    101       if (first_two_digits >= 51 && first_two_digits <= 55)
    102         return kMasterCard;
    103 
    104       if (first_digit == 3)
    105         return kJCBCard;
    106 
    107       if (first_digit == 4)
    108         return kVisaCard;
    109 
    110       break;
    111     case 18:
    112     case 19:
    113       if (first_four_digits == 6334 || first_four_digits == 6767)
    114         return kSoloCard;
    115 
    116       break;
    117   }
    118 
    119   return kGenericCard;
    120 }
    121 
    122 bool ConvertDate(const string16& date, int* num) {
    123   if (!date.empty()) {
    124     bool converted = base::StringToInt(date, num);
    125     DCHECK(converted);
    126     if (!converted)
    127       return false;
    128   } else {
    129     // Clear the value.
    130     *num = 0;
    131   }
    132 
    133   return true;
    134 }
    135 
    136 }  // namespace
    137 
    138 CreditCard::CreditCard(const std::string& guid)
    139     : type_(kGenericCard),
    140       expiration_month_(0),
    141       expiration_year_(0),
    142       guid_(guid) {
    143 }
    144 
    145 CreditCard::CreditCard()
    146     : type_(kGenericCard),
    147       expiration_month_(0),
    148       expiration_year_(0),
    149       guid_(guid::GenerateGUID()) {
    150 }
    151 
    152 CreditCard::CreditCard(const CreditCard& credit_card) : FormGroup() {
    153   operator=(credit_card);
    154 }
    155 
    156 CreditCard::~CreditCard() {}
    157 
    158 void CreditCard::GetPossibleFieldTypes(const string16& text,
    159                                        FieldTypeSet* possible_types) const {
    160   if (IsNameOnCard(text))
    161     possible_types->insert(CREDIT_CARD_NAME);
    162 
    163   if (IsNumber(text))
    164     possible_types->insert(CREDIT_CARD_NUMBER);
    165 
    166   if (IsExpirationMonth(text))
    167     possible_types->insert(CREDIT_CARD_EXP_MONTH);
    168 
    169   if (Is2DigitExpirationYear(text))
    170     possible_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR);
    171 
    172   if (Is4DigitExpirationYear(text))
    173     possible_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
    174 }
    175 
    176 void CreditCard::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
    177   DCHECK(available_types);
    178 
    179   if (!name_on_card_.empty())
    180     available_types->insert(CREDIT_CARD_NAME);
    181 
    182   if (!number_.empty())
    183     available_types->insert(CREDIT_CARD_NUMBER);
    184 
    185   if (!ExpirationMonthAsString().empty())
    186     available_types->insert(CREDIT_CARD_EXP_MONTH);
    187 
    188   if (!Expiration2DigitYearAsString().empty())
    189     available_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR);
    190 
    191   if (!Expiration4DigitYearAsString().empty())
    192     available_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
    193 }
    194 
    195 string16 CreditCard::GetInfo(AutofillFieldType type) const {
    196   switch (type) {
    197     case CREDIT_CARD_NAME:
    198       return name_on_card_;
    199 
    200     case CREDIT_CARD_EXP_MONTH:
    201       return ExpirationMonthAsString();
    202 
    203     case CREDIT_CARD_EXP_2_DIGIT_YEAR:
    204       return Expiration2DigitYearAsString();
    205 
    206     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
    207       return Expiration4DigitYearAsString();
    208 
    209     case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
    210       string16 month = ExpirationMonthAsString();
    211       string16 year = Expiration2DigitYearAsString();
    212       if (!month.empty() && !year.empty())
    213         return month + ASCIIToUTF16("/") + year;
    214       return string16();
    215     }
    216 
    217     case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
    218       string16 month = ExpirationMonthAsString();
    219       string16 year = Expiration4DigitYearAsString();
    220       if (!month.empty() && !year.empty())
    221         return month + ASCIIToUTF16("/") + year;
    222       return string16();
    223     }
    224 
    225     case CREDIT_CARD_TYPE:
    226       // We don't handle this case.
    227       return string16();
    228 
    229     case CREDIT_CARD_NUMBER:
    230       return number();
    231 
    232     case CREDIT_CARD_VERIFICATION_CODE:
    233       NOTREACHED();
    234       return string16();
    235 
    236     default:
    237       // ComputeDataPresentForArray will hit this repeatedly.
    238       return string16();
    239   }
    240 }
    241 
    242 void CreditCard::SetInfo(AutofillFieldType type, const string16& value) {
    243   switch (type) {
    244     case CREDIT_CARD_NAME:
    245       name_on_card_ = value;
    246       break;
    247 
    248     case CREDIT_CARD_EXP_MONTH:
    249       SetExpirationMonthFromString(value);
    250       break;
    251 
    252     case CREDIT_CARD_EXP_2_DIGIT_YEAR:
    253       // This is a read-only attribute.
    254       break;
    255 
    256     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
    257       SetExpirationYearFromString(value);
    258       break;
    259 
    260     case CREDIT_CARD_TYPE:
    261       // We determine the type based on the number.
    262       break;
    263 
    264     case CREDIT_CARD_NUMBER: {
    265       // Don't change the real value if the input is an obfuscated string.
    266       if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol)
    267         SetNumber(value);
    268       break;
    269     }
    270 
    271     case CREDIT_CARD_VERIFICATION_CODE:
    272       NOTREACHED();
    273       break;
    274 
    275     default:
    276       NOTREACHED() << "Attempting to set unknown info-type " << type;
    277       break;
    278   }
    279 }
    280 
    281 const string16 CreditCard::Label() const {
    282   string16 label;
    283   if (number().empty())
    284     return name_on_card_;  // No CC number, return name only.
    285 
    286   string16 obfuscated_cc_number = ObfuscatedNumber();
    287   if (!expiration_month_ || !expiration_year_)
    288     return obfuscated_cc_number;  // No expiration date set.
    289 
    290   // TODO(georgey): Internationalize date.
    291   string16 formatted_date(ExpirationMonthAsString());
    292   formatted_date.append(ASCIIToUTF16("/"));
    293   formatted_date.append(Expiration4DigitYearAsString());
    294 
    295 #ifndef ANDROID
    296   label = l10n_util::GetStringFUTF16(IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT,
    297                                      obfuscated_cc_number,
    298                                      formatted_date);
    299 #endif
    300   return label;
    301 }
    302 
    303 void CreditCard::SetInfoForMonthInputType(const string16& value) {
    304   // Check if |text| is "yyyy-mm" format first, and check normal month format.
    305   if (!autofill::MatchString(value, UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$")))
    306     return;
    307 
    308   std::vector<string16> year_month;
    309   base::SplitString(value, L'-', &year_month);
    310   DCHECK_EQ((int)year_month.size(), 2);
    311   int num = 0;
    312   bool converted = false;
    313   converted = base::StringToInt(year_month[0], &num);
    314   DCHECK(converted);
    315   SetExpirationYear(num);
    316   converted = base::StringToInt(year_month[1], &num);
    317   DCHECK(converted);
    318   SetExpirationMonth(num);
    319 }
    320 
    321 string16 CreditCard::ObfuscatedNumber() const {
    322   // If the number is shorter than four digits, there's no need to obfuscate it.
    323   if (number_.size() < 4)
    324     return number_;
    325 
    326   string16 number = StripSeparators(number_);
    327   string16 result(number.size() - 4, kCreditCardObfuscationSymbol);
    328   result.append(LastFourDigits());
    329 
    330   return result;
    331 }
    332 
    333 string16 CreditCard::LastFourDigits() const {
    334   static const size_t kNumLastDigits = 4;
    335 
    336   string16 number = StripSeparators(number_);
    337   if (number.size() < kNumLastDigits)
    338     return string16();
    339 
    340   return number.substr(number.size() - kNumLastDigits, kNumLastDigits);
    341 }
    342 
    343 void CreditCard::operator=(const CreditCard& credit_card) {
    344   if (this == &credit_card)
    345     return;
    346 
    347   number_ = credit_card.number_;
    348   name_on_card_ = credit_card.name_on_card_;
    349   type_ = credit_card.type_;
    350   expiration_month_ = credit_card.expiration_month_;
    351   expiration_year_ = credit_card.expiration_year_;
    352   guid_ = credit_card.guid_;
    353 }
    354 
    355 int CreditCard::Compare(const CreditCard& credit_card) const {
    356   // The following CreditCard field types are the only types we store in the
    357   // WebDB so far, so we're only concerned with matching these types in the
    358   // credit card.
    359   const AutofillFieldType types[] = { CREDIT_CARD_NAME,
    360                                       CREDIT_CARD_NUMBER,
    361                                       CREDIT_CARD_EXP_MONTH,
    362                                       CREDIT_CARD_EXP_4_DIGIT_YEAR };
    363   for (size_t index = 0; index < arraysize(types); ++index) {
    364     int comparison = GetInfo(types[index]).compare(
    365         credit_card.GetInfo(types[index]));
    366     if (comparison != 0)
    367       return comparison;
    368   }
    369 
    370   return 0;
    371 }
    372 
    373 bool CreditCard::operator==(const CreditCard& credit_card) const {
    374   if (guid_ != credit_card.guid_)
    375     return false;
    376 
    377   return Compare(credit_card) == 0;
    378 }
    379 
    380 bool CreditCard::operator!=(const CreditCard& credit_card) const {
    381   return !operator==(credit_card);
    382 }
    383 
    384 // static
    385 const string16 CreditCard::StripSeparators(const string16& number) {
    386   const char16 kSeparators[] = {'-', ' ', '\0'};
    387   string16 stripped;
    388   RemoveChars(number, kSeparators, &stripped);
    389   return stripped;
    390 }
    391 
    392 // static
    393 bool CreditCard::IsValidCreditCardNumber(const string16& text) {
    394   string16 number = StripSeparators(text);
    395 
    396   // Credit card numbers are at most 19 digits in length [1]. 12 digits seems to
    397   // be a fairly safe lower-bound [2].
    398   // [1] http://www.merriampark.com/anatomycc.htm
    399   // [2] http://en.wikipedia.org/wiki/Bank_card_number
    400   const size_t kMinCreditCardDigits = 12;
    401   const size_t kMaxCreditCardDigits = 19;
    402   if (number.size() < kMinCreditCardDigits ||
    403       number.size() > kMaxCreditCardDigits)
    404     return false;
    405 
    406   // Use the Luhn formula [3] to validate the number.
    407   // [3] http://en.wikipedia.org/wiki/Luhn_algorithm
    408   int sum = 0;
    409   bool odd = false;
    410   string16::reverse_iterator iter;
    411   for (iter = number.rbegin(); iter != number.rend(); ++iter) {
    412     if (!IsAsciiDigit(*iter))
    413       return false;
    414 
    415     int digit = *iter - '0';
    416     if (odd) {
    417       digit *= 2;
    418       sum += digit / 10 + digit % 10;
    419     } else {
    420       sum += digit;
    421     }
    422     odd = !odd;
    423   }
    424 
    425   return (sum % 10) == 0;
    426 }
    427 
    428 bool CreditCard::IsEmpty() const {
    429   FieldTypeSet types;
    430   GetAvailableFieldTypes(&types);
    431   return types.empty();
    432 }
    433 
    434 string16 CreditCard::ExpirationMonthAsString() const {
    435   if (expiration_month_ == 0)
    436     return string16();
    437 
    438   string16 month = base::IntToString16(expiration_month_);
    439   if (expiration_month_ >= 10)
    440     return month;
    441 
    442   string16 zero = ASCIIToUTF16("0");
    443   zero.append(month);
    444   return zero;
    445 }
    446 
    447 string16 CreditCard::Expiration4DigitYearAsString() const {
    448   if (expiration_year_ == 0)
    449     return string16();
    450 
    451   return base::IntToString16(Expiration4DigitYear());
    452 }
    453 
    454 string16 CreditCard::Expiration2DigitYearAsString() const {
    455   if (expiration_year_ == 0)
    456     return string16();
    457 
    458   return base::IntToString16(Expiration2DigitYear());
    459 }
    460 
    461 void CreditCard::SetExpirationMonthFromString(const string16& text) {
    462   int month;
    463   if (!ConvertDate(text, &month))
    464     return;
    465 
    466   SetExpirationMonth(month);
    467 }
    468 
    469 void CreditCard::SetExpirationYearFromString(const string16& text) {
    470   int year;
    471   if (!ConvertDate(text, &year))
    472     return;
    473 
    474   SetExpirationYear(year);
    475 }
    476 
    477 void CreditCard::SetNumber(const string16& number) {
    478   number_ = number;
    479   type_ = GetCreditCardType(StripSeparators(number_));
    480 }
    481 
    482 void CreditCard::SetExpirationMonth(int expiration_month) {
    483   if (expiration_month < 0 || expiration_month > 12)
    484     return;
    485 
    486   expiration_month_ = expiration_month;
    487 }
    488 
    489 void CreditCard::SetExpirationYear(int expiration_year) {
    490   if (expiration_year != 0 &&
    491       (expiration_year < 2006 || expiration_year > 10000)) {
    492     return;
    493   }
    494 
    495   expiration_year_ = expiration_year;
    496 }
    497 
    498 bool CreditCard::IsNumber(const string16& text) const {
    499   return StripSeparators(text) == StripSeparators(number_);
    500 }
    501 
    502 bool CreditCard::IsNameOnCard(const string16& text) const {
    503   return StringToLowerASCII(text) == StringToLowerASCII(name_on_card_);
    504 }
    505 
    506 bool CreditCard::IsExpirationMonth(const string16& text) const {
    507   int month;
    508   if (!base::StringToInt(text, &month))
    509     return false;
    510 
    511   return expiration_month_ == month;
    512 }
    513 
    514 bool CreditCard::Is2DigitExpirationYear(const string16& text) const {
    515   int year;
    516   if (!base::StringToInt(text, &year))
    517     return false;
    518 
    519   return year < 100 && (expiration_year_ % 100) == year;
    520 }
    521 
    522 bool CreditCard::Is4DigitExpirationYear(const string16& text) const {
    523   int year;
    524   if (!base::StringToInt(text, &year))
    525     return false;
    526 
    527   return expiration_year_ == year;
    528 }
    529 
    530 // So we can compare CreditCards with EXPECT_EQ().
    531 std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) {
    532   return os
    533       << UTF16ToUTF8(credit_card.Label())
    534       << " "
    535       << credit_card.guid()
    536       << " "
    537       << UTF16ToUTF8(credit_card.GetInfo(CREDIT_CARD_NAME))
    538       << " "
    539       << UTF16ToUTF8(credit_card.GetInfo(CREDIT_CARD_TYPE))
    540       << " "
    541       << UTF16ToUTF8(credit_card.GetInfo(CREDIT_CARD_NUMBER))
    542       << " "
    543       << UTF16ToUTF8(credit_card.GetInfo(CREDIT_CARD_EXP_MONTH))
    544       << " "
    545       << UTF16ToUTF8(credit_card.GetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
    546 }
    547 
    548 // These values must match the values in WebKitClientImpl in webkit/glue. We
    549 // send these strings to WK, which then asks WebKitClientImpl to load the image
    550 // data.
    551 const char* const kAmericanExpressCard = "americanExpressCC";
    552 const char* const kDinersCard = "dinersCC";
    553 const char* const kDiscoverCard = "discoverCC";
    554 const char* const kGenericCard = "genericCC";
    555 const char* const kJCBCard = "jcbCC";
    556 const char* const kMasterCard = "masterCardCC";
    557 const char* const kSoloCard = "soloCC";
    558 const char* const kVisaCard = "visaCC";
    559