• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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