blob: f3ac6b112ab976ea2ec39b67900a95d04e4d5e8b [file] [log] [blame]
Ben Murdocheb525c52013-07-10 11:40:50 +01001// 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"
Ben Murdocheb525c52013-07-10 11:40:50 +010024#include "components/autofill/core/browser/validation.h"
25#include "components/autofill/core/common/form_field_data.h"
26#include "grit/component_strings.h"
27#include "grit/webkit_resources.h"
Ben Murdochca12bfa2013-07-23 11:17:05 +010028#include "third_party/icu/source/common/unicode/uloc.h"
29#include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010030#include "ui/base/l10n/l10n_util.h"
31
32namespace autofill {
33
34namespace {
35
36const char16 kCreditCardObfuscationSymbol = '*';
37
38// This is the maximum obfuscated symbols displayed.
39// It is introduced to avoid rare cases where the credit card number is
40// too large and fills the screen.
41const size_t kMaxObfuscationSize = 20;
42
43bool ConvertYear(const base::string16& year, int* num) {
44 // If the |year| is empty, clear the stored value.
45 if (year.empty()) {
46 *num = 0;
47 return true;
48 }
49
50 // Try parsing the |year| as a number.
51 if (base::StringToInt(year, num))
52 return true;
53
54 *num = 0;
55 return false;
56}
57
58bool ConvertMonth(const base::string16& month,
59 const std::string& app_locale,
60 int* num) {
61 // If the |month| is empty, clear the stored value.
62 if (month.empty()) {
63 *num = 0;
64 return true;
65 }
66
67 // Try parsing the |month| as a number.
68 if (base::StringToInt(month, num))
69 return true;
70
71 // If the locale is unknown, give up.
72 if (app_locale.empty())
73 return false;
74
75 // Otherwise, try parsing the |month| as a named month, e.g. "January" or
76 // "Jan".
77 base::string16 lowercased_month = StringToLowerASCII(month);
78
79 UErrorCode status = U_ZERO_ERROR;
80 icu::Locale locale(app_locale.c_str());
81 icu::DateFormatSymbols date_format_symbols(locale, status);
82 DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
83 status == U_USING_DEFAULT_WARNING);
84
85 int32_t num_months;
86 const icu::UnicodeString* months = date_format_symbols.getMonths(num_months);
87 for (int32_t i = 0; i < num_months; ++i) {
88 const base::string16 icu_month = base::string16(months[i].getBuffer(),
89 months[i].length());
90 if (lowercased_month == StringToLowerASCII(icu_month)) {
91 *num = i + 1; // Adjust from 0-indexed to 1-indexed.
92 return true;
93 }
94 }
95
96 months = date_format_symbols.getShortMonths(num_months);
97 for (int32_t i = 0; i < num_months; ++i) {
98 const base::string16 icu_month = base::string16(months[i].getBuffer(),
99 months[i].length());
100 if (lowercased_month == StringToLowerASCII(icu_month)) {
101 *num = i + 1; // Adjust from 0-indexed to 1-indexed.
102 return true;
103 }
104 }
105
106 *num = 0;
107 return false;
108}
109
110} // namespace
111
112CreditCard::CreditCard(const std::string& guid, const std::string& origin)
113 : AutofillDataModel(guid, origin),
114 type_(kGenericCard),
115 expiration_month_(0),
116 expiration_year_(0) {
117}
118
119CreditCard::CreditCard()
120 : AutofillDataModel(base::GenerateGUID(), std::string()),
121 type_(kGenericCard),
122 expiration_month_(0),
123 expiration_year_(0) {
124}
125
126CreditCard::CreditCard(const CreditCard& credit_card)
127 : AutofillDataModel(std::string(), std::string()) {
128 operator=(credit_card);
129}
130
131CreditCard::~CreditCard() {}
132
133// static
134const base::string16 CreditCard::StripSeparators(const base::string16& number) {
135 const char16 kSeparators[] = {'-', ' ', '\0'};
136 base::string16 stripped;
137 RemoveChars(number, kSeparators, &stripped);
138 return stripped;
139}
140
141// static
142base::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);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100153 if (type == kUnionPay)
154 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_UNION_PAY);
Ben Murdocheb525c52013-07-10 11:40:50 +0100155 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
165int 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;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100176 if (type == kUnionPay)
177 return IDR_AUTOFILL_CC_GENERIC; // Needs resource: http://crbug.com/259211
Ben Murdocheb525c52013-07-10 11:40:50 +0100178 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
188std::string CreditCard::GetCreditCardType(const base::string16& number) {
189 // Credit card number specifications taken from:
190 // http://en.wikipedia.org/wiki/Credit_card_numbers,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100191 // http://en.wikipedia.org/wiki/List_of_Issuer_Identification_Numbers,
Ben Murdocheb525c52013-07-10 11:40:50 +0100192 // http://www.discovernetwork.com/merchants/images/Merchant_Marketing_PDF.pdf,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100193 // 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
Ben Murdocheb525c52013-07-10 11:40:50 +0100197 // 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
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100210 // UnionPay 62 16-19
Ben Murdocheb525c52013-07-10 11:40:50 +0100211
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
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100238 if (first_two_digits == 62)
239 return kUnionPay;
240
Ben Murdocheb525c52013-07-10 11:40:50 +0100241 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
Ben Murdoch32409262013-08-07 11:04:47 +0100278base::string16 CreditCard::GetRawInfo(ServerFieldType type) const {
Ben Murdocheb525c52013-07-10 11:40:50 +0100279 switch (type) {
280 case CREDIT_CARD_NAME:
281 return name_on_card_;
282
283 case CREDIT_CARD_EXP_MONTH:
284 return ExpirationMonthAsString();
285
286 case CREDIT_CARD_EXP_2_DIGIT_YEAR:
287 return Expiration2DigitYearAsString();
288
289 case CREDIT_CARD_EXP_4_DIGIT_YEAR:
290 return Expiration4DigitYearAsString();
291
292 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
293 base::string16 month = ExpirationMonthAsString();
294 base::string16 year = Expiration2DigitYearAsString();
295 if (!month.empty() && !year.empty())
296 return month + ASCIIToUTF16("/") + year;
297 return base::string16();
298 }
299
300 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
301 base::string16 month = ExpirationMonthAsString();
302 base::string16 year = Expiration4DigitYearAsString();
303 if (!month.empty() && !year.empty())
304 return month + ASCIIToUTF16("/") + year;
305 return base::string16();
306 }
307
308 case CREDIT_CARD_TYPE:
309 return TypeForDisplay();
310
311 case CREDIT_CARD_NUMBER:
312 return number_;
313
314 case CREDIT_CARD_VERIFICATION_CODE:
315 // Chrome doesn't store credit card verification codes.
316 return base::string16();
317
318 default:
319 // ComputeDataPresentForArray will hit this repeatedly.
320 return base::string16();
321 }
322}
323
Ben Murdoch32409262013-08-07 11:04:47 +0100324void CreditCard::SetRawInfo(ServerFieldType type,
Ben Murdocheb525c52013-07-10 11:40:50 +0100325 const base::string16& value) {
326 switch (type) {
327 case CREDIT_CARD_NAME:
328 name_on_card_ = value;
329 break;
330
331 case CREDIT_CARD_EXP_MONTH:
332 SetExpirationMonthFromString(value, std::string());
333 break;
334
335 case CREDIT_CARD_EXP_2_DIGIT_YEAR:
336 // This is a read-only attribute.
337 break;
338
339 case CREDIT_CARD_EXP_4_DIGIT_YEAR:
340 SetExpirationYearFromString(value);
341 break;
342
343 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
344 // This is a read-only attribute.
345 break;
346
347 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
348 // This is a read-only attribute.
349 break;
350
351 case CREDIT_CARD_TYPE:
352 // This is a read-only attribute, determined by the credit card number.
353 break;
354
355 case CREDIT_CARD_NUMBER: {
356 // Don't change the real value if the input is an obfuscated string.
357 if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol)
358 SetNumber(value);
359 break;
360 }
361
362 case CREDIT_CARD_VERIFICATION_CODE:
363 // Chrome doesn't store the credit card verification code.
364 break;
365
366 default:
367 NOTREACHED() << "Attempting to set unknown info-type " << type;
368 break;
369 }
370}
371
Ben Murdoch32409262013-08-07 11:04:47 +0100372base::string16 CreditCard::GetInfo(const AutofillType& type,
Ben Murdocheb525c52013-07-10 11:40:50 +0100373 const std::string& app_locale) const {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100374 ServerFieldType storable_type = type.GetStorableType();
375 if (storable_type == CREDIT_CARD_NUMBER)
Ben Murdocheb525c52013-07-10 11:40:50 +0100376 return StripSeparators(number_);
377
Ben Murdochbb1529c2013-08-08 10:24:53 +0100378 return GetRawInfo(storable_type);
Ben Murdocheb525c52013-07-10 11:40:50 +0100379}
380
Ben Murdoch32409262013-08-07 11:04:47 +0100381bool CreditCard::SetInfo(const AutofillType& type,
Ben Murdocheb525c52013-07-10 11:40:50 +0100382 const base::string16& value,
383 const std::string& app_locale) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100384 ServerFieldType storable_type = type.GetStorableType();
385 if (storable_type == CREDIT_CARD_NUMBER)
386 SetRawInfo(storable_type, StripSeparators(value));
387 else if (storable_type == CREDIT_CARD_EXP_MONTH)
Ben Murdocheb525c52013-07-10 11:40:50 +0100388 SetExpirationMonthFromString(value, app_locale);
389 else
Ben Murdochbb1529c2013-08-08 10:24:53 +0100390 SetRawInfo(storable_type, value);
Ben Murdocheb525c52013-07-10 11:40:50 +0100391
392 return true;
393}
394
395void CreditCard::GetMatchingTypes(const base::string16& text,
396 const std::string& app_locale,
Ben Murdoch32409262013-08-07 11:04:47 +0100397 ServerFieldTypeSet* matching_types) const {
Ben Murdocheb525c52013-07-10 11:40:50 +0100398 FormGroup::GetMatchingTypes(text, app_locale, matching_types);
399
Ben Murdoch32409262013-08-07 11:04:47 +0100400 base::string16 card_number =
401 GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale);
Ben Murdocheb525c52013-07-10 11:40:50 +0100402 if (!card_number.empty() && StripSeparators(text) == card_number)
403 matching_types->insert(CREDIT_CARD_NUMBER);
404
405 int month;
406 if (ConvertMonth(text, app_locale, &month) && month != 0 &&
407 month == expiration_month_) {
408 matching_types->insert(CREDIT_CARD_EXP_MONTH);
409 }
410}
411
412const base::string16 CreditCard::Label() const {
413 base::string16 label;
414 if (number().empty())
415 return name_on_card_; // No CC number, return name only.
416
417 base::string16 obfuscated_cc_number = ObfuscatedNumber();
418 if (!expiration_month_ || !expiration_year_)
419 return obfuscated_cc_number; // No expiration date set.
420
421 // TODO(georgey): Internationalize date.
422 base::string16 formatted_date(ExpirationMonthAsString());
423 formatted_date.append(ASCIIToUTF16("/"));
424 formatted_date.append(Expiration4DigitYearAsString());
425
426 label = l10n_util::GetStringFUTF16(IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT,
427 obfuscated_cc_number,
428 formatted_date);
429 return label;
430}
431
432void CreditCard::SetInfoForMonthInputType(const base::string16& value) {
433 // Check if |text| is "yyyy-mm" format first, and check normal month format.
434 if (!autofill::MatchesPattern(value, UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$")))
435 return;
436
437 std::vector<base::string16> year_month;
438 base::SplitString(value, L'-', &year_month);
439 DCHECK_EQ((int)year_month.size(), 2);
440 int num = 0;
441 bool converted = false;
442 converted = base::StringToInt(year_month[0], &num);
443 DCHECK(converted);
444 SetExpirationYear(num);
445 converted = base::StringToInt(year_month[1], &num);
446 DCHECK(converted);
447 SetExpirationMonth(num);
448}
449
450base::string16 CreditCard::ObfuscatedNumber() const {
451 // If the number is shorter than four digits, there's no need to obfuscate it.
452 if (number_.size() < 4)
453 return number_;
454
455 base::string16 number = StripSeparators(number_);
456
457 // Avoid making very long obfuscated numbers.
458 size_t obfuscated_digits = std::min(kMaxObfuscationSize, number.size() - 4);
459 base::string16 result(obfuscated_digits, kCreditCardObfuscationSymbol);
460 return result.append(LastFourDigits());
461}
462
463base::string16 CreditCard::LastFourDigits() const {
464 static const size_t kNumLastDigits = 4;
465
466 base::string16 number = StripSeparators(number_);
467 if (number.size() < kNumLastDigits)
468 return base::string16();
469
470 return number.substr(number.size() - kNumLastDigits, kNumLastDigits);
471}
472
473base::string16 CreditCard::TypeForDisplay() const {
474 return CreditCard::TypeForDisplay(type_);
475}
476
477base::string16 CreditCard::TypeAndLastFourDigits() const {
478 base::string16 type = TypeForDisplay();
479 // TODO(estade): type may be empty, we probably want to return
480 // "Card - 1234" or something in that case.
481
482 base::string16 digits = LastFourDigits();
483 if (digits.empty())
484 return type;
485
486 // TODO(estade): i18n.
487 return type + ASCIIToUTF16(" - ") + digits;
488}
489
490void CreditCard::operator=(const CreditCard& credit_card) {
491 if (this == &credit_card)
492 return;
493
494 number_ = credit_card.number_;
495 name_on_card_ = credit_card.name_on_card_;
496 type_ = credit_card.type_;
497 expiration_month_ = credit_card.expiration_month_;
498 expiration_year_ = credit_card.expiration_year_;
499
500 set_guid(credit_card.guid());
501 set_origin(credit_card.origin());
502}
503
504bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card,
505 const std::string& app_locale) {
Ben Murdoch32409262013-08-07 11:04:47 +0100506 if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale) !=
507 imported_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale)) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100508 return false;
509 }
510
511 // Heuristically aggregated data should never overwrite verified data.
512 // Instead, discard any heuristically aggregated credit cards that disagree
513 // with explicitly entered data, so that the UI is not cluttered with
514 // duplicate cards.
515 if (this->IsVerified() && !imported_card.IsVerified())
516 return true;
517
518 set_origin(imported_card.origin());
519
520 // Note that the card number is intentionally not updated, so as to preserve
521 // any formatting (i.e. separator characters). Since the card number is not
522 // updated, there is no reason to update the card type, either.
523 if (!imported_card.name_on_card_.empty())
524 name_on_card_ = imported_card.name_on_card_;
525
526 // The expiration date for |imported_card| should always be set.
527 DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_);
528 expiration_month_ = imported_card.expiration_month_;
529 expiration_year_ = imported_card.expiration_year_;
530
531 return true;
532}
533
534void CreditCard::FillFormField(const AutofillField& field,
535 size_t /*variant*/,
536 const std::string& app_locale,
537 FormFieldData* field_data) const {
Ben Murdoch32409262013-08-07 11:04:47 +0100538 DCHECK_EQ(CREDIT_CARD, field.Type().group());
Ben Murdocheb525c52013-07-10 11:40:50 +0100539 DCHECK(field_data);
540
541 if (field_data->form_control_type == "select-one") {
Ben Murdoch32409262013-08-07 11:04:47 +0100542 FillSelectControl(field.Type(), app_locale, field_data);
Ben Murdocheb525c52013-07-10 11:40:50 +0100543 } else if (field_data->form_control_type == "month") {
544 // HTML5 input="month" consists of year-month.
Ben Murdoch32409262013-08-07 11:04:47 +0100545 base::string16 year =
546 GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale);
547 base::string16 month =
548 GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale);
Ben Murdocheb525c52013-07-10 11:40:50 +0100549 if (!year.empty() && !month.empty()) {
550 // Fill the value only if |this| includes both year and month
551 // information.
552 field_data->value = year + ASCIIToUTF16("-") + month;
553 }
554 } else {
Ben Murdoch32409262013-08-07 11:04:47 +0100555 field_data->value = GetInfo(field.Type(), app_locale);
Ben Murdocheb525c52013-07-10 11:40:50 +0100556 }
557}
558
559int CreditCard::Compare(const CreditCard& credit_card) const {
560 // The following CreditCard field types are the only types we store in the
561 // WebDB so far, so we're only concerned with matching these types in the
562 // credit card.
Ben Murdoch32409262013-08-07 11:04:47 +0100563 const ServerFieldType types[] = { CREDIT_CARD_NAME,
564 CREDIT_CARD_NUMBER,
565 CREDIT_CARD_EXP_MONTH,
566 CREDIT_CARD_EXP_4_DIGIT_YEAR };
567 for (size_t i = 0; i < arraysize(types); ++i) {
568 int comparison =
569 GetRawInfo(types[i]).compare(credit_card.GetRawInfo(types[i]));
Ben Murdocheb525c52013-07-10 11:40:50 +0100570 if (comparison != 0)
571 return comparison;
572 }
573
574 return 0;
575}
576
577bool CreditCard::operator==(const CreditCard& credit_card) const {
578 return guid() == credit_card.guid() &&
579 origin() == credit_card.origin() &&
580 Compare(credit_card) == 0;
581}
582
583bool CreditCard::operator!=(const CreditCard& credit_card) const {
584 return !operator==(credit_card);
585}
586
587bool CreditCard::IsEmpty(const std::string& app_locale) const {
Ben Murdoch32409262013-08-07 11:04:47 +0100588 ServerFieldTypeSet types;
Ben Murdocheb525c52013-07-10 11:40:50 +0100589 GetNonEmptyTypes(app_locale, &types);
590 return types.empty();
591}
592
593bool CreditCard::IsComplete() const {
594 return
595 autofill::IsValidCreditCardNumber(number_) &&
596 expiration_month_ != 0 &&
597 expiration_year_ != 0;
598}
599
600bool CreditCard::IsValid() const {
601 return autofill::IsValidCreditCardNumber(number_) &&
602 autofill::IsValidCreditCardExpirationDate(
603 expiration_year_, expiration_month_, base::Time::Now());
604}
605
Ben Murdoch32409262013-08-07 11:04:47 +0100606void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
Ben Murdocheb525c52013-07-10 11:40:50 +0100607 supported_types->insert(CREDIT_CARD_NAME);
608 supported_types->insert(CREDIT_CARD_NUMBER);
609 supported_types->insert(CREDIT_CARD_TYPE);
610 supported_types->insert(CREDIT_CARD_EXP_MONTH);
611 supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR);
612 supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
613 supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
614 supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
615}
616
617base::string16 CreditCard::ExpirationMonthAsString() const {
618 if (expiration_month_ == 0)
619 return base::string16();
620
621 base::string16 month = base::IntToString16(expiration_month_);
622 if (expiration_month_ >= 10)
623 return month;
624
625 base::string16 zero = ASCIIToUTF16("0");
626 zero.append(month);
627 return zero;
628}
629
630base::string16 CreditCard::Expiration4DigitYearAsString() const {
631 if (expiration_year_ == 0)
632 return base::string16();
633
634 return base::IntToString16(Expiration4DigitYear());
635}
636
637base::string16 CreditCard::Expiration2DigitYearAsString() const {
638 if (expiration_year_ == 0)
639 return base::string16();
640
641 return base::IntToString16(Expiration2DigitYear());
642}
643
644void CreditCard::SetExpirationMonthFromString(const base::string16& text,
645 const std::string& app_locale) {
646 int month;
647 if (!ConvertMonth(text, app_locale, &month))
648 return;
649
650 SetExpirationMonth(month);
651}
652
653void CreditCard::SetExpirationYearFromString(const base::string16& text) {
654 int year;
655 if (!ConvertYear(text, &year))
656 return;
657
658 SetExpirationYear(year);
659}
660
661void CreditCard::SetNumber(const base::string16& number) {
662 number_ = number;
663 type_ = GetCreditCardType(StripSeparators(number_));
664}
665
666void CreditCard::SetExpirationMonth(int expiration_month) {
667 if (expiration_month < 0 || expiration_month > 12)
668 return;
669
670 expiration_month_ = expiration_month;
671}
672
673void CreditCard::SetExpirationYear(int expiration_year) {
674 if (expiration_year != 0 &&
675 (expiration_year < 2006 || expiration_year > 10000)) {
676 return;
677 }
678
679 expiration_year_ = expiration_year;
680}
681
682// So we can compare CreditCards with EXPECT_EQ().
683std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) {
684 return os
685 << UTF16ToUTF8(credit_card.Label())
686 << " "
687 << credit_card.guid()
688 << " "
689 << credit_card.origin()
690 << " "
691 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME))
692 << " "
693 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE))
694 << " "
695 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER))
696 << " "
697 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH))
698 << " "
699 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
700}
701
702// These values must match the values in WebKitPlatformSupportImpl in
703// webkit/glue. We send these strings to WebKit, which then asks
704// WebKitPlatformSupportImpl to load the image data.
705const char* const kAmericanExpressCard = "americanExpressCC";
706const char* const kDinersCard = "dinersCC";
707const char* const kDiscoverCard = "discoverCC";
708const char* const kGenericCard = "genericCC";
709const char* const kJCBCard = "jcbCC";
710const char* const kMasterCard = "masterCardCC";
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100711const char* const kUnionPay = "unionPayCC";
Ben Murdocheb525c52013-07-10 11:40:50 +0100712const char* const kVisaCard = "visaCC";
713
714} // namespace autofill