diff options
author | thestig <thestig@chromium.org> | 2015-04-03 16:59:54 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-04 00:00:24 +0000 |
commit | 49946212049e5744449e5222de7d1d114de97e9d (patch) | |
tree | 7f2aee3a41415864b03d3db94948bf6a3ff7245e | |
parent | 32fde13971e4af00a608bc0286331a5d9b2f1213 (diff) | |
download | chromium_src-49946212049e5744449e5222de7d1d114de97e9d.zip chromium_src-49946212049e5744449e5222de7d1d114de97e9d.tar.gz chromium_src-49946212049e5744449e5222de7d1d114de97e9d.tar.bz2 |
Autofill: Recognize more credit card date fields.
BUG=471831
Review URL: https://codereview.chromium.org/1048363002
Cr-Commit-Position: refs/heads/master@{#323853}
6 files changed, 182 insertions, 11 deletions
diff --git a/chrome/test/data/autofill/heuristics/input/bug_471831.html b/chrome/test/data/autofill/heuristics/input/bug_471831.html new file mode 100644 index 0000000..e9298e1 --- /dev/null +++ b/chrome/test/data/autofill/heuristics/input/bug_471831.html @@ -0,0 +1,95 @@ +<div class="layoutView paymentView" style="opacity: 1; height: 291px; transition: none; -webkit-transition: none; transform: translateX(0px); overflow: inherit;"> + <div class="layoutSubview" style="height: 55px; transform: translateY(0px); opacity: 1; transition: none; -webkit-transition: none;"> + <div class="emailInput input"> + <input class="control" id="email" type="email" x-autocompletetype="email" autocompletetype="email" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="Email"><span class="spinnerContainer" style="display: none;"> + <div class="svgSpinner" style="width: 14px; height: 15px;"> + </div></span> + <div class="svg icon" style="width: 30px; height: 30px;"> + </div> + </div> + </div> + <div class="layoutSubview" style="height: 43px; transform: translateY(55px); opacity: 1; transition: none; -webkit-transition: none;"> + <div class="segmentedControl paymentMethodsSegmentedControl small"> + <div class="content"><a class="segmentedControl paymentMethodsSegmentedControlItem0 card selected" data-index="0" style="width: 115px;"><span><span>Card</span></span></a><a class="segmentedControl paymentMethodsSegmentedControlItem1 bitcoin" data-index="1" style="width: 114px;"><span><span>Bitcoin</span></span></a> + </div> + </div> + </div> + <div class="layoutSubview" style="height: 158px; transform: translateY(98px); opacity: 1; transition: none; -webkit-transition: none;"> + <div class="contentSwitcher"> + <div class="inner"> + <div class="content"> + <div class="layoutView cardView" style="opacity: 1; transform: translateX(0px); display: block; transition: none; -webkit-transition: none; height: 158px;"> + <div class="layoutSubview" style="height: 91px; transform: translateY(0px); opacity: 1; transition: none; -webkit-transition: none;"> + <div class="cardPaymentView"> + <div class="cardNumberInput input top"> + <input class="control" id="card_number" type="tel" x-autocompletetype="cc-number" autocompletetype="cc-number" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="Card number"> + <div class="svg icon" style="width: 30px; height: 30px;"> + </div> + </div> + <div class="cardExpiresInput input left bottom"> + <input class="control" id="cc-exp" type="text" x-autocompletetype="off" autocompletetype="off" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="MM / YY"> + <div class="svg icon" style="width: 30px; height: 30px;"> + </div> + <select id="cc-exp-year" x-autocompletetype="cc-exp-year" autocompletetype="cc-exp-year" autocorrect="off" spellcheck="off" autocapitalize="off" tabindex="-1" style="position: absolute; left: -10000px;"><option>Year</option><option value="2014">2014</option><option value="2015">2015</option><option value="2016">2016</option><option value="2017">2017</option><option value="2018">2018</option><option value="2019">2019</option><option value="2020">2020</option><option value="2021">2021</option><option value="2022">2022</option><option value="2023">2023</option><option value="2024">2024</option></select> + <select id="cc-exp-month" x-autocompletetype="cc-exp-month" autocompletetype="cc-exp-month" autocorrect="off" spellcheck="off" autocapitalize="off" tabindex="-1" style="position: absolute; left: -10000px;"><option>Month</option><option value="01">January</option><option value="02">February</option><option value="03">March</option><option value="04">April</option><option value="05">May</option><option value="06">June</option><option value="07">July</option><option value="08">August</option><option value="09">September</option><option value="10">October</option><option value="11">November</option><option value="12">December</option></select> + </div> + <div class="cardCVCInput input right bottom"> + <input class="control" id="cc-csc" type="tel" autocomplete="off" autocorrect="off" spellcheck="off" autocapitalize="off" placeholder="CVC" maxlength="4"> + <div class="svg icon" style="width: 30px; height: 30px;"> + </div> + </div> + </div> + </div> + <div class="layoutSubview" style="height: 67px; transform: translateY(91px); opacity: 1; transition: none; -webkit-transition: none;"> + <div class="rememberMe"><a class="stripeLink"></a> + <div class="labelWithCheckbox"> + <div class="inner"><a class="checkbox checkbox-remember-me" href="#"><span class="tick"></span><span class="focusRing"></span></a><label>Remember me</label> + </div> + </div> + <div class="expandedContainer"> + <div class="expanded" style="opacity: 0; transform: rotateX(-60deg); display: none;"><p>For security, please enter your <strong>mobile phone number</strong>:</p> + <div class="telInput input"> + <input class="control" type="tel" x-autocompletetype="phone-full" autocompletetype="phone-full" autocorrect="off" spellcheck="off" autocapitalize="off" name="phone" placeholder="(555) 123-1234"><span class="flag"><img src="/v3/images/flags/US.png" style="opacity: 1; transform: scale(1); transition: none; -webkit-transition: none;"></span> + <div class="svg icon" style="width: 30px; height: 30px;"> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="layoutSubview" style="display: none; opacity: 0; height: 69px; transform: translateY(158px); transition: none; -webkit-transition: none;"> + <div class="labelWithCheckbox"> + <div class="inner"><a class="checkbox checked" href="#"><span class="tick"></span><span class="focusRing"></span></a><label>Keep me logged in</label> + </div> + </div> + </div> + </div> + <div class="layoutView bitcoinLayoutView" style="display: none; height: 8px;"> + <div class="layoutSubview" style="height: 8px; transform: translateY(0px); opacity: 1; transition: none; -webkit-transition: none;"> + <div class="carouselView"> + <div class="labelView">To complete your payment, please send bitcoins to the address below:</div> + </div> + </div> + <div class="layoutSubview" style="height: 0px; transform: translateY(8px); opacity: 1; transition: none; -webkit-transition: none;"> + <div class="bitcoinAddressView"> + <div class="amount"><span class="arrowContainer"><span class="arrow"></span></span> + <div class="svg icon" style="width: 30px; height: 30px;"></div> + <span class="btcPrice"></span><span class="originalPrice"></span> + <div class="tick bitcoinSuccessTick circle" style="display: none; transform: scale(0.01);"> + <div class="svg" style="width: 20px; height: 21px; transform: scale(1.8);"></div> + </div> + <div class="bitcoinLoadingView"><canvas class="loadingView" style="display: none;"></canvas></div> + </div> + <div class="addressContainer"> + <div class="address"><p class="stringAddress"><span></span></p> + <div class="buttons"><a class="openWalletButton"><span>Open Wallet</span></a><a class="scanButton"><span>Scan</span><span class="qrCode"></span></a></div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</div> diff --git a/chrome/test/data/autofill/heuristics/output/bug_471831.out b/chrome/test/data/autofill/heuristics/output/bug_471831.out new file mode 100644 index 0000000..2eabd5a --- /dev/null +++ b/chrome/test/data/autofill/heuristics/output/bug_471831.out @@ -0,0 +1,7 @@ +EMAIL_ADDRESS | email | Email | | email_1-default +CREDIT_CARD_NUMBER | card_number | Card number | | email_1-cc +CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR | cc-exp | MM / YY | | email_1-cc +UNKNOWN_TYPE | cc-exp-year | CardBitcoin | Year | email_1-default +UNKNOWN_TYPE | cc-exp-month | CardBitcoin | Month | email_1-default +UNKNOWN_TYPE | cc-csc | CVC | | email_1-default +PHONE_HOME_WHOLE_NUMBER | phone | (555) 123-1234 | | email_1-default diff --git a/components/autofill/core/browser/autofill_regex_constants.cc.utf8 b/components/autofill/core/browser/autofill_regex_constants.cc.utf8 index ac1d119..a4c4594 100644 --- a/components/autofill/core/browser/autofill_regex_constants.cc.utf8 +++ b/components/autofill/core/browser/autofill_regex_constants.cc.utf8 @@ -182,10 +182,11 @@ const char kExpirationYearRe[] = "|Срок действия карты" // ru "|年|有效期"; // zh-CN -// This regex is a little bit nasty, but it is simply requiring exactly two -// adjacent y's. +// The "yy" portion of the regex is just looking for two adjacent y's. const char kExpirationDate2DigitYearRe[] = - "exp.*date.*[^y]yy([^y]|$)"; + "(exp.*date.*|mm\\s*[-/]\\s*)[^y]yy([^y]|$)"; +const char kExpirationDate4DigitYearRe[] = + "^mm\\s*[-/]\\syyyy$"; const char kExpirationDateRe[] = "expir|exp.*date" "|gueltig|gültig" // de-DE diff --git a/components/autofill/core/browser/autofill_regex_constants.h b/components/autofill/core/browser/autofill_regex_constants.h index 8135a9d..7f5ce1a 100644 --- a/components/autofill/core/browser/autofill_regex_constants.h +++ b/components/autofill/core/browser/autofill_regex_constants.h @@ -30,6 +30,7 @@ extern const char kCardTypeRe[]; extern const char kExpirationMonthRe[]; extern const char kExpirationYearRe[]; extern const char kExpirationDate2DigitYearRe[]; +extern const char kExpirationDate4DigitYearRe[]; extern const char kExpirationDateRe[]; extern const char kCardIgnoredRe[]; extern const char kGiftCardRe[]; diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc index 3403b04..7d48bd5 100644 --- a/components/autofill/core/browser/credit_card_field.cc +++ b/components/autofill/core/browser/credit_card_field.cc @@ -50,6 +50,28 @@ bool FindConsecutiveStrings(const std::vector<base::string16>& regex_needles, return false; } +// Returns true if a field that has |max_length| can fit the data for a field of +// |type|. +bool FieldCanFitDataForFieldType(int max_length, ServerFieldType type) { + if (max_length == 0) + return true; + + switch (type) { + case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: { + static int kMinimum2YearCcExpLength = strlen("12/14"); + return max_length >= kMinimum2YearCcExpLength; + } + case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: { + static int kMinimum4YearCcExpLength = strlen("12/2014"); + return max_length >= kMinimum4YearCcExpLength; + } + default: + NOTREACHED(); + return false; + } +} + + } // namespace // static @@ -377,17 +399,17 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) { } // If that fails, try to parse a combined expiration field. - // Look for a 2-digit year first. // We allow <select> fields, because they're used e.g. on qvc.com. scanner->RewindTo(month_year_saved_cursor); - static int kMinimum2YearCcExpLength = strlen("12/14"); - int current_field_max_length = scanner->Cursor()->max_length; - if (current_field_max_length > 0 && - current_field_max_length < kMinimum2YearCcExpLength) { + // Bail out if the field cannot fit a 2-digit year expiration date. + const int current_field_max_length = scanner->Cursor()->max_length; + if (!FieldCanFitDataForFieldType(current_field_max_length, + CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR)) { return false; } + // Try to look for a 2-digit year expiration date. if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationDate2DigitYearRe), kMatchTelAndSelect, @@ -397,19 +419,33 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) { return true; } + // Try to look for a generic expiration date field. (2 or 4 digit year) if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationDateRe), kMatchTelAndSelect, &expiration_date_)) { - static int kMinimum4YearCcExpLength = strlen("12/2014"); - if (current_field_max_length > 0 && - current_field_max_length < kMinimum4YearCcExpLength) { + // If such a field exists, but it cannot fit a 4-digit year expiration + // date, then the likely possibility is that it is a 2-digit year expiration + // date. + if (!FieldCanFitDataForFieldType(current_field_max_length, + CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)) { exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; } expiration_month_ = nullptr; return true; } + // Try to look for a 4-digit year expiration date. + if (FieldCanFitDataForFieldType(current_field_max_length, + CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) && + ParseFieldSpecifics(scanner, + base::UTF8ToUTF16(kExpirationDate4DigitYearRe), + kMatchTelAndSelect, + &expiration_date_)) { + expiration_month_ = nullptr; + return true; + } + return false; } diff --git a/components/autofill/core/browser/credit_card_field_unittest.cc b/components/autofill/core/browser/credit_card_field_unittest.cc index ba54b56..1297175 100644 --- a/components/autofill/core/browser/credit_card_field_unittest.cc +++ b/components/autofill/core/browser/credit_card_field_unittest.cc @@ -339,6 +339,37 @@ TEST_F(CreditCardFieldTest, ParseExpField2DigitYearDueToMaxLength) { field_type_map_[ASCIIToUTF16("exp3")]); } +TEST_F(CreditCardFieldTest, ParseExpField4DigitYear) { + FormFieldData field; + field.form_control_type = "text"; + + field.label = ASCIIToUTF16("Name on Card"); + field.name = ASCIIToUTF16("name_on_card"); + list_.push_back(new AutofillField(field, ASCIIToUTF16("name1"))); + + field.label = ASCIIToUTF16("Card Number"); + field.name = ASCIIToUTF16("card_number"); + list_.push_back(new AutofillField(field, ASCIIToUTF16("number2"))); + + field.label = ASCIIToUTF16("MM / YYYY"); + field.name = ASCIIToUTF16("cc_exp"); + list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3"))); + + Parse(); + ASSERT_NE(nullptr, field_.get()); + EXPECT_TRUE(ClassifyField()); + ASSERT_TRUE( + field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end()); + EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]); + ASSERT_TRUE( + field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end()); + EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]); + ASSERT_TRUE( + field_type_map_.find(ASCIIToUTF16("exp3")) != field_type_map_.end()); + EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, + field_type_map_[ASCIIToUTF16("exp3")]); +} + TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) { FormFieldData field; field.form_control_type = "text"; |