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