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
ConvertYear(const base::string16 & year,int * num)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
ConvertMonth(const base::string16 & month,const std::string & app_locale,int * num)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
CreditCard(const std::string & guid,const std::string & origin)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
CreditCard()120 CreditCard::CreditCard()
121 : AutofillDataModel(base::GenerateGUID(), std::string()),
122 type_(kGenericCard),
123 expiration_month_(0),
124 expiration_year_(0) {
125 }
126
CreditCard(const CreditCard & credit_card)127 CreditCard::CreditCard(const CreditCard& credit_card)
128 : AutofillDataModel(std::string(), std::string()) {
129 operator=(credit_card);
130 }
131
~CreditCard()132 CreditCard::~CreditCard() {}
133
134 // static
StripSeparators(const base::string16 & number)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
TypeForDisplay(const std::string & type)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
IconResourceId(const std::string & type)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
GetCreditCardType(const base::string16 & number)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
GetRawInfo(ServerFieldType type) const278 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
SetRawInfo(ServerFieldType type,const base::string16 & value)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
GetInfo(const AutofillType & type,const std::string & app_locale) const374 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
SetInfo(const AutofillType & type,const base::string16 & value,const std::string & app_locale)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
GetMatchingTypes(const base::string16 & text,const std::string & app_locale,ServerFieldTypeSet * matching_types) const397 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
Label() const414 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
SetInfoForMonthInputType(const base::string16 & value)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
ObfuscatedNumber() const454 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
LastFourDigits() const467 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
TypeForDisplay() const477 base::string16 CreditCard::TypeForDisplay() const {
478 return CreditCard::TypeForDisplay(type_);
479 }
480
TypeAndLastFourDigits() const481 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
operator =(const CreditCard & credit_card)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
UpdateFromImportedCard(const CreditCard & imported_card,const std::string & app_locale)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
Compare(const CreditCard & credit_card) const538 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
operator ==(const CreditCard & credit_card) const556 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
operator !=(const CreditCard & credit_card) const562 bool CreditCard::operator!=(const CreditCard& credit_card) const {
563 return !operator==(credit_card);
564 }
565
IsEmpty(const std::string & app_locale) const566 bool CreditCard::IsEmpty(const std::string& app_locale) const {
567 ServerFieldTypeSet types;
568 GetNonEmptyTypes(app_locale, &types);
569 return types.empty();
570 }
571
IsComplete() const572 bool CreditCard::IsComplete() const {
573 return
574 autofill::IsValidCreditCardNumber(number_) &&
575 expiration_month_ != 0 &&
576 expiration_year_ != 0;
577 }
578
IsValid() const579 bool CreditCard::IsValid() const {
580 return autofill::IsValidCreditCardNumber(number_) &&
581 autofill::IsValidCreditCardExpirationDate(
582 expiration_year_, expiration_month_, base::Time::Now());
583 }
584
GetSupportedTypes(ServerFieldTypeSet * supported_types) const585 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
ExpirationMonthAsString() const596 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
Expiration4DigitYearAsString() const609 base::string16 CreditCard::Expiration4DigitYearAsString() const {
610 if (expiration_year_ == 0)
611 return base::string16();
612
613 return base::IntToString16(Expiration4DigitYear());
614 }
615
Expiration2DigitYearAsString() const616 base::string16 CreditCard::Expiration2DigitYearAsString() const {
617 if (expiration_year_ == 0)
618 return base::string16();
619
620 return base::IntToString16(Expiration2DigitYear());
621 }
622
SetExpirationMonthFromString(const base::string16 & text,const std::string & app_locale)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
SetExpirationYearFromString(const base::string16 & text)632 void CreditCard::SetExpirationYearFromString(const base::string16& text) {
633 int year;
634 if (!ConvertYear(text, &year))
635 return;
636
637 SetExpirationYear(year);
638 }
639
SetNumber(const base::string16 & number)640 void CreditCard::SetNumber(const base::string16& number) {
641 number_ = number;
642 type_ = GetCreditCardType(StripSeparators(number_));
643 }
644
SetExpirationMonth(int expiration_month)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
SetExpirationYear(int expiration_year)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().
operator <<(std::ostream & os,const CreditCard & credit_card)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