Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: components/autofill/core/browser/credit_card.cc

Issue 2136453003: [Autofill] Improve support for various credit card expiration dates. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final nits Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/core/browser/credit_card.h" 5 #include "components/autofill/core/browser/credit_card.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 17 matching lines...) Expand all
28 #include "components/autofill/core/browser/validation.h" 28 #include "components/autofill/core/browser/validation.h"
29 #include "components/autofill/core/common/autofill_l10n_util.h" 29 #include "components/autofill/core/common/autofill_l10n_util.h"
30 #include "components/autofill/core/common/autofill_regexes.h" 30 #include "components/autofill/core/common/autofill_regexes.h"
31 #include "components/autofill/core/common/form_field_data.h" 31 #include "components/autofill/core/common/form_field_data.h"
32 #include "grit/components_scaled_resources.h" 32 #include "grit/components_scaled_resources.h"
33 #include "grit/components_strings.h" 33 #include "grit/components_strings.h"
34 #include "third_party/icu/source/common/unicode/uloc.h" 34 #include "third_party/icu/source/common/unicode/uloc.h"
35 #include "third_party/icu/source/i18n/unicode/dtfmtsym.h" 35 #include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
36 #include "ui/base/l10n/l10n_util.h" 36 #include "ui/base/l10n/l10n_util.h"
37 37
38 using base::ASCIIToUTF16;
39
38 namespace autofill { 40 namespace autofill {
39 41
40 const base::char16 kMidlineEllipsis[] = { 0x22ef, 0 }; 42 const base::char16 kMidlineEllipsis[] = { 0x22ef, 0 };
41 43
42 namespace { 44 namespace {
43 45
44 const base::char16 kCreditCardObfuscationSymbol = '*'; 46 const base::char16 kCreditCardObfuscationSymbol = '*';
45 const base::char16 kNonBreakingSpace[] = { 0x00a0, 0 }; 47 const base::char16 kNonBreakingSpace[] = { 0x00a0, 0 };
46 48
47 bool ConvertYear(const base::string16& year, int* num) { 49 bool ConvertYear(const base::string16& year, int* num) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 113
112 CreditCard::CreditCard(const CreditCard& credit_card) : CreditCard() { 114 CreditCard::CreditCard(const CreditCard& credit_card) : CreditCard() {
113 operator=(credit_card); 115 operator=(credit_card);
114 } 116 }
115 117
116 CreditCard::~CreditCard() {} 118 CreditCard::~CreditCard() {}
117 119
118 // static 120 // static
119 const base::string16 CreditCard::StripSeparators(const base::string16& number) { 121 const base::string16 CreditCard::StripSeparators(const base::string16& number) {
120 base::string16 stripped; 122 base::string16 stripped;
121 base::RemoveChars(number, base::ASCIIToUTF16("- "), &stripped); 123 base::RemoveChars(number, ASCIIToUTF16("- "), &stripped);
122 return stripped; 124 return stripped;
123 } 125 }
124 126
125 // static 127 // static
126 base::string16 CreditCard::TypeForDisplay(const std::string& type) { 128 base::string16 CreditCard::TypeForDisplay(const std::string& type) {
127 if (kGenericCard == type) 129 if (kGenericCard == type)
128 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GENERIC); 130 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GENERIC);
129 if (kAmericanExpressCard == type) 131 if (kAmericanExpressCard == type)
130 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX_SHORT); 132 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX_SHORT);
131 133
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 case CREDIT_CARD_EXP_2_DIGIT_YEAR: 285 case CREDIT_CARD_EXP_2_DIGIT_YEAR:
284 return Expiration2DigitYearAsString(); 286 return Expiration2DigitYearAsString();
285 287
286 case CREDIT_CARD_EXP_4_DIGIT_YEAR: 288 case CREDIT_CARD_EXP_4_DIGIT_YEAR:
287 return Expiration4DigitYearAsString(); 289 return Expiration4DigitYearAsString();
288 290
289 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: { 291 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
290 base::string16 month = ExpirationMonthAsString(); 292 base::string16 month = ExpirationMonthAsString();
291 base::string16 year = Expiration2DigitYearAsString(); 293 base::string16 year = Expiration2DigitYearAsString();
292 if (!month.empty() && !year.empty()) 294 if (!month.empty() && !year.empty())
293 return month + base::ASCIIToUTF16("/") + year; 295 return month + ASCIIToUTF16("/") + year;
294 return base::string16(); 296 return base::string16();
295 } 297 }
296 298
297 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: { 299 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
298 base::string16 month = ExpirationMonthAsString(); 300 base::string16 month = ExpirationMonthAsString();
299 base::string16 year = Expiration4DigitYearAsString(); 301 base::string16 year = Expiration4DigitYearAsString();
300 if (!month.empty() && !year.empty()) 302 if (!month.empty() && !year.empty())
301 return month + base::ASCIIToUTF16("/") + year; 303 return month + ASCIIToUTF16("/") + year;
302 return base::string16(); 304 return base::string16();
303 } 305 }
304 306
305 case CREDIT_CARD_TYPE: 307 case CREDIT_CARD_TYPE:
306 return TypeForFill(); 308 return TypeForFill();
307 309
308 case CREDIT_CARD_NUMBER: 310 case CREDIT_CARD_NUMBER:
309 return number_; 311 return number_;
310 312
311 case CREDIT_CARD_VERIFICATION_CODE: 313 case CREDIT_CARD_VERIFICATION_CODE:
(...skipping 12 matching lines...) Expand all
324 switch (type) { 326 switch (type) {
325 case CREDIT_CARD_NAME_FULL: 327 case CREDIT_CARD_NAME_FULL:
326 name_on_card_ = value; 328 name_on_card_ = value;
327 break; 329 break;
328 330
329 case CREDIT_CARD_EXP_MONTH: 331 case CREDIT_CARD_EXP_MONTH:
330 SetExpirationMonthFromString(value, std::string()); 332 SetExpirationMonthFromString(value, std::string());
331 break; 333 break;
332 334
333 case CREDIT_CARD_EXP_2_DIGIT_YEAR: 335 case CREDIT_CARD_EXP_2_DIGIT_YEAR:
334 // This is a read-only attribute. 336 SetExpirationYearFromString(value);
335 break; 337 break;
336 338
337 case CREDIT_CARD_EXP_4_DIGIT_YEAR: 339 case CREDIT_CARD_EXP_4_DIGIT_YEAR:
338 SetExpirationYearFromString(value); 340 SetExpirationYearFromString(value);
339 break; 341 break;
340 342
341 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: 343 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
342 // This is a read-only attribute. 344 SetExpirationDateFromString(value);
343 break; 345 break;
344 346
345 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: 347 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
346 // This is a read-only attribute. 348 SetExpirationDateFromString(value);
347 break; 349 break;
348 350
349 case CREDIT_CARD_TYPE: 351 case CREDIT_CARD_TYPE:
350 // This is a read-only attribute, determined by the credit card number. 352 // This is a read-only attribute, determined by the credit card number.
351 break; 353 break;
352 354
353 case CREDIT_CARD_NUMBER: { 355 case CREDIT_CARD_NUMBER: {
354 // Don't change the real value if the input is an obfuscated string. 356 // Don't change the real value if the input is an obfuscated string.
355 if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol) 357 if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol)
356 SetNumber(value); 358 SetNumber(value);
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 // No CC number, return name only. 426 // No CC number, return name only.
425 if (number().empty()) 427 if (number().empty())
426 return std::make_pair(name_on_card_, base::string16()); 428 return std::make_pair(name_on_card_, base::string16());
427 429
428 base::string16 obfuscated_cc_number = TypeAndLastFourDigits(); 430 base::string16 obfuscated_cc_number = TypeAndLastFourDigits();
429 // No expiration date set. 431 // No expiration date set.
430 if (!expiration_month_ || !expiration_year_) 432 if (!expiration_month_ || !expiration_year_)
431 return std::make_pair(obfuscated_cc_number, base::string16()); 433 return std::make_pair(obfuscated_cc_number, base::string16());
432 434
433 base::string16 formatted_date(ExpirationMonthAsString()); 435 base::string16 formatted_date(ExpirationMonthAsString());
434 formatted_date.append(base::ASCIIToUTF16("/")); 436 formatted_date.append(ASCIIToUTF16("/"));
435 formatted_date.append(Expiration4DigitYearAsString()); 437 formatted_date.append(Expiration4DigitYearAsString());
436 438
437 base::string16 separator = 439 base::string16 separator =
438 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR); 440 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
439 return std::make_pair(obfuscated_cc_number, separator + formatted_date); 441 return std::make_pair(obfuscated_cc_number, separator + formatted_date);
440 } 442 }
441 443
442 void CreditCard::SetInfoForMonthInputType(const base::string16& value) { 444 void CreditCard::SetInfoForMonthInputType(const base::string16& value) {
443 // Check if |text| is "yyyy-mm" format first, and check normal month format. 445 // Check if |text| is "yyyy-mm" format first, and check normal month format.
444 if (!MatchesPattern(value, base::UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$"))) 446 if (!MatchesPattern(value, base::UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$")))
445 return; 447 return;
446 448
447 std::vector<base::StringPiece16> year_month = base::SplitStringPiece( 449 std::vector<base::StringPiece16> year_month = base::SplitStringPiece(
448 value, base::ASCIIToUTF16("-"), 450 value, ASCIIToUTF16("-"), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
449 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
450 DCHECK_EQ(2u, year_month.size()); 451 DCHECK_EQ(2u, year_month.size());
451 int num = 0; 452 int num = 0;
452 bool converted = false; 453 bool converted = false;
453 converted = base::StringToInt(year_month[0], &num); 454 converted = base::StringToInt(year_month[0], &num);
454 DCHECK(converted); 455 DCHECK(converted);
455 SetExpirationYear(num); 456 SetExpirationYear(num);
456 converted = base::StringToInt(year_month[1], &num); 457 converted = base::StringToInt(year_month[1], &num);
457 DCHECK(converted); 458 DCHECK(converted);
458 SetExpirationMonth(num); 459 SetExpirationMonth(num);
459 } 460 }
460 461
461 void CreditCard::SetExpirationMonth(int expiration_month) { 462 void CreditCard::SetExpirationMonth(int expiration_month) {
462 if (expiration_month < 0 || expiration_month > 12) 463 if (expiration_month < 0 || expiration_month > 12)
463 return; 464 return;
464 expiration_month_ = expiration_month; 465 expiration_month_ = expiration_month;
465 } 466 }
466 467
467 void CreditCard::SetExpirationYear(int expiration_year) { 468 void CreditCard::SetExpirationYear(int expiration_year) {
468 if (expiration_year != 0 && 469 // If |expiration_year| is beyond this millenium, or more than 2 digits but
469 (expiration_year < 2006 || expiration_year > 10000)) 470 // before the current millenium (e.g. "545", "1995"), return. What is left are
471 // values like "45" or "2018".
472 if (expiration_year > 2999 ||
473 (expiration_year > 99 && expiration_year < 2000))
470 return; 474 return;
475
476 // Will normalize 2-digit years to the 4-digit version.
477 if (expiration_year > 0 && expiration_year < 100) {
478 base::Time::Exploded now_exploded;
479 base::Time::Now().LocalExplode(&now_exploded);
480 expiration_year += (now_exploded.year / 100) * 100;
481 }
482
471 expiration_year_ = expiration_year; 483 expiration_year_ = expiration_year;
472 } 484 }
473 485
474 base::string16 CreditCard::LastFourDigits() const { 486 base::string16 CreditCard::LastFourDigits() const {
475 static const size_t kNumLastDigits = 4; 487 static const size_t kNumLastDigits = 4;
476 488
477 base::string16 number = StripSeparators(number_); 489 base::string16 number = StripSeparators(number_);
478 if (number.size() <= kNumLastDigits) 490 if (number.size() <= kNumLastDigits)
479 return number; 491 return number;
480 492
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 } 682 }
671 683
672 base::string16 CreditCard::ExpirationMonthAsString() const { 684 base::string16 CreditCard::ExpirationMonthAsString() const {
673 if (expiration_month_ == 0) 685 if (expiration_month_ == 0)
674 return base::string16(); 686 return base::string16();
675 687
676 base::string16 month = base::IntToString16(expiration_month_); 688 base::string16 month = base::IntToString16(expiration_month_);
677 if (expiration_month_ >= 10) 689 if (expiration_month_ >= 10)
678 return month; 690 return month;
679 691
680 base::string16 zero = base::ASCIIToUTF16("0"); 692 base::string16 zero = ASCIIToUTF16("0");
681 zero.append(month); 693 zero.append(month);
682 return zero; 694 return zero;
683 } 695 }
684 696
685 base::string16 CreditCard::TypeForFill() const { 697 base::string16 CreditCard::TypeForFill() const {
686 return ::autofill::TypeForFill(type_); 698 return ::autofill::TypeForFill(type_);
687 } 699 }
688 700
689 base::string16 CreditCard::Expiration4DigitYearAsString() const { 701 base::string16 CreditCard::Expiration4DigitYearAsString() const {
690 if (expiration_year_ == 0) 702 if (expiration_year_ == 0)
(...skipping 23 matching lines...) Expand all
714 } 726 }
715 727
716 void CreditCard::SetExpirationYearFromString(const base::string16& text) { 728 void CreditCard::SetExpirationYearFromString(const base::string16& text) {
717 int year; 729 int year;
718 if (!ConvertYear(text, &year)) 730 if (!ConvertYear(text, &year))
719 return; 731 return;
720 732
721 SetExpirationYear(year); 733 SetExpirationYear(year);
722 } 734 }
723 735
736 void CreditCard::SetExpirationDateFromString(const base::string16& text) {
737 // Check that |text| fits the supported patterns: mmyy, mmyyyy, m-yy,
738 // mm-yy, m-yyyy and mm-yyyy. Note that myy and myyyy matched by this pattern
739 // but are not supported (ambiguous). Separators: -, / and |.
740 if (!MatchesPattern(text, base::UTF8ToUTF16("^[0-9]{1,2}[-/|]?[0-9]{2,4}$")))
741 return;
742
743 base::string16 month;
744 base::string16 year;
745
746 // Check for a separator.
747 base::string16 found_separator;
748 const std::vector<base::string16> kSeparators{
749 ASCIIToUTF16("-"), ASCIIToUTF16("/"), ASCIIToUTF16("|")};
750 for (const base::string16& separator : kSeparators) {
751 if (text.find(separator) != base::string16::npos) {
752 found_separator = separator;
753 break;
754 }
755 }
756
757 if (!found_separator.empty()) {
758 std::vector<base::string16> month_year = base::SplitString(
759 text, found_separator, base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
760 DCHECK_EQ(2u, month_year.size());
761 month = month_year[0];
762 year = month_year[1];
763 } else if (text.size() % 2 == 0) {
764 // If there are no separators, the supported formats are mmyy and mmyyyy.
765 month = text.substr(0, 2);
766 year = text.substr(2);
767 } else {
768 // Odd number of digits with no separator is too ambiguous.
769 return;
770 }
771
772 int num = 0;
773 bool converted = false;
774 converted = base::StringToInt(month, &num);
775 DCHECK(converted);
776 SetExpirationMonth(num);
777 converted = base::StringToInt(year, &num);
778 DCHECK(converted);
779 SetExpirationYear(num);
780 }
781
724 void CreditCard::SetNumber(const base::string16& number) { 782 void CreditCard::SetNumber(const base::string16& number) {
725 number_ = number; 783 number_ = number;
726 784
727 // Set the type based on the card number, but only for full numbers, not 785 // Set the type based on the card number, but only for full numbers, not
728 // when we have masked cards from the server (last 4 digits). 786 // when we have masked cards from the server (last 4 digits).
729 if (record_type_ != MASKED_SERVER_CARD) 787 if (record_type_ != MASKED_SERVER_CARD)
730 type_ = GetCreditCardType(StripSeparators(number_)); 788 type_ = GetCreditCardType(StripSeparators(number_));
731 } 789 }
732 790
733 void CreditCard::RecordAndLogUse() { 791 void CreditCard::RecordAndLogUse() {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
766 if (compare.StringsEqual(icu_month, month)) { 824 if (compare.StringsEqual(icu_month, month)) {
767 *num = i + 1; // Adjust from 0-indexed to 1-indexed. 825 *num = i + 1; // Adjust from 0-indexed to 1-indexed.
768 return true; 826 return true;
769 } 827 }
770 } 828 }
771 829
772 months = date_format_symbols.getShortMonths(num_months); 830 months = date_format_symbols.getShortMonths(num_months);
773 // Some abbreviations have . at the end (e.g., "janv." in French). We don't 831 // Some abbreviations have . at the end (e.g., "janv." in French). We don't
774 // care about matching that. 832 // care about matching that.
775 base::string16 trimmed_month; 833 base::string16 trimmed_month;
776 base::TrimString(month, base::ASCIIToUTF16("."), &trimmed_month); 834 base::TrimString(month, ASCIIToUTF16("."), &trimmed_month);
777 for (int32_t i = 0; i < num_months; ++i) { 835 for (int32_t i = 0; i < num_months; ++i) {
778 base::string16 icu_month(months[i].getBuffer(), months[i].length()); 836 base::string16 icu_month(months[i].getBuffer(), months[i].length());
779 base::TrimString(icu_month, base::ASCIIToUTF16("."), &icu_month); 837 base::TrimString(icu_month, ASCIIToUTF16("."), &icu_month);
780 if (compare.StringsEqual(icu_month, trimmed_month)) { 838 if (compare.StringsEqual(icu_month, trimmed_month)) {
781 *num = i + 1; // Adjust from 0-indexed to 1-indexed. 839 *num = i + 1; // Adjust from 0-indexed to 1-indexed.
782 return true; 840 return true;
783 } 841 }
784 } 842 }
785 843
786 return false; 844 return false;
787 } 845 }
788 846
789 bool CreditCard::IsExpired(const base::Time& current_time) const { 847 bool CreditCard::IsExpired(const base::Time& current_time) const {
(...skipping 28 matching lines...) Expand all
818 const char kAmericanExpressCard[] = "americanExpressCC"; 876 const char kAmericanExpressCard[] = "americanExpressCC";
819 const char kDinersCard[] = "dinersCC"; 877 const char kDinersCard[] = "dinersCC";
820 const char kDiscoverCard[] = "discoverCC"; 878 const char kDiscoverCard[] = "discoverCC";
821 const char kGenericCard[] = "genericCC"; 879 const char kGenericCard[] = "genericCC";
822 const char kJCBCard[] = "jcbCC"; 880 const char kJCBCard[] = "jcbCC";
823 const char kMasterCard[] = "masterCardCC"; 881 const char kMasterCard[] = "masterCardCC";
824 const char kUnionPay[] = "unionPayCC"; 882 const char kUnionPay[] = "unionPayCC";
825 const char kVisaCard[] = "visaCC"; 883 const char kVisaCard[] = "visaCC";
826 884
827 } // namespace autofill 885 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/core/browser/credit_card.h ('k') | components/autofill/core/browser/credit_card_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698