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