Commit 401f3492 authored by pritam.nikam's avatar pritam.nikam Committed by Commit bot

[Autofill] Autofill incorrectly fills credit card expiration year in 2-digit fields.

With current implementation the on parsing the credit card field heuristics
matches to the autofill::kExpirationYearRe and apparently it's assumes that a
4-digit credit card field (i.e. ServerFieldType CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR).

This patch considers *maxlength* attribute in addition to see whether the feild
is 2-digit input field or not.

BUG=406247

Review URL: https://codereview.chromium.org/493393003

Cr-Commit-Position: refs/heads/master@{#291734}
parent 9b2d620f
......@@ -60,7 +60,8 @@ FormField* CreditCardField::Parse(AutofillScanner* scanner) {
scanner->SaveCursor();
const AutofillField* first;
if (ParseField(scanner, base::ASCIIToUTF16("^cfnm"), &first) &&
ParseField(scanner, base::ASCIIToUTF16("^clnm"),
ParseField(scanner,
base::ASCIIToUTF16("^clnm"),
&credit_card_field->cardholder_last_)) {
credit_card_field->cardholder_ = first;
continue;
......@@ -71,7 +72,8 @@ FormField* CreditCardField::Parse(AutofillScanner* scanner) {
// Check for a credit card type (Visa, MasterCard, etc.) field.
base::string16 type_pattern = base::UTF8ToUTF16(autofill::kCardTypeRe);
if (!credit_card_field->type_ &&
ParseFieldSpecifics(scanner, type_pattern,
ParseFieldSpecifics(scanner,
type_pattern,
MATCH_DEFAULT | MATCH_SELECT,
&credit_card_field->type_)) {
continue;
......@@ -102,11 +104,15 @@ FormField* CreditCardField::Parse(AutofillScanner* scanner) {
scanner->SaveCursor();
pattern = base::UTF8ToUTF16(autofill::kExpirationMonthRe);
if (!credit_card_field->expiration_month_ &&
ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_SELECT,
ParseFieldSpecifics(scanner,
pattern,
MATCH_DEFAULT | MATCH_SELECT,
&credit_card_field->expiration_month_)) {
pattern = base::UTF8ToUTF16(autofill::kExpirationYearRe);
if (ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_SELECT,
&credit_card_field->expiration_year_)) {
if (ParseFieldSpecifics(scanner,
pattern,
MATCH_DEFAULT | MATCH_SELECT,
&credit_card_field->expiration_year_)) {
continue;
}
}
......@@ -117,19 +123,21 @@ FormField* CreditCardField::Parse(AutofillScanner* scanner) {
scanner->Rewind();
pattern = base::UTF8ToUTF16(autofill::kExpirationDate2DigitYearRe);
// We allow <select> fields, because they're used e.g. on qvc.com.
if (ParseFieldSpecifics(scanner, pattern,
MATCH_LABEL | MATCH_VALUE | MATCH_TEXT |
MATCH_SELECT,
&credit_card_field->expiration_date_)) {
credit_card_field->is_two_digit_year_ = true;
if (ParseFieldSpecifics(
scanner,
pattern,
MATCH_LABEL | MATCH_VALUE | MATCH_TEXT | MATCH_SELECT,
&credit_card_field->expiration_date_)) {
credit_card_field->exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
continue;
}
pattern = base::UTF8ToUTF16(autofill::kExpirationDateRe);
if (ParseFieldSpecifics(scanner, pattern,
MATCH_LABEL | MATCH_VALUE | MATCH_TEXT |
MATCH_SELECT,
&credit_card_field->expiration_date_)) {
if (ParseFieldSpecifics(
scanner,
pattern,
MATCH_LABEL | MATCH_VALUE | MATCH_TEXT | MATCH_SELECT,
&credit_card_field->expiration_date_)) {
continue;
}
}
......@@ -187,14 +195,14 @@ CreditCardField::CreditCardField()
expiration_month_(NULL),
expiration_year_(NULL),
expiration_date_(NULL),
is_two_digit_year_(false) {
exp_year_type_(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) {
}
bool CreditCardField::ClassifyField(ServerFieldTypeMap* map) const {
bool ok = AddClassification(number_, CREDIT_CARD_NUMBER, map);
ok = ok && AddClassification(type_, CREDIT_CARD_TYPE, map);
ok = ok && AddClassification(verification_, CREDIT_CARD_VERIFICATION_CODE,
map);
ok = ok &&
AddClassification(verification_, CREDIT_CARD_VERIFICATION_CODE, map);
// If the heuristics detected first and last name in separate fields,
// then ignore both fields. Putting them into separate fields is probably
......@@ -204,27 +212,23 @@ bool CreditCardField::ClassifyField(ServerFieldTypeMap* map) const {
ok = ok && AddClassification(cardholder_, CREDIT_CARD_NAME, map);
if (expiration_date_) {
if (is_two_digit_year_) {
ok = ok && AddClassification(expiration_date_,
CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, map);
} else {
ok = ok && AddClassification(expiration_date_,
CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, map);
}
ok =
ok && AddClassification(expiration_date_, GetExpirationYearType(), map);
} else {
ok = ok && AddClassification(expiration_month_, CREDIT_CARD_EXP_MONTH, map);
if (is_two_digit_year_) {
ok = ok && AddClassification(expiration_year_,
CREDIT_CARD_EXP_2_DIGIT_YEAR,
map);
} else {
ok = ok && AddClassification(expiration_year_,
CREDIT_CARD_EXP_4_DIGIT_YEAR,
map);
}
ok =
ok && AddClassification(expiration_year_, GetExpirationYearType(), map);
}
return ok;
}
ServerFieldType CreditCardField::GetExpirationYearType() const {
return (expiration_date_
? exp_year_type_
: ((expiration_year_ && expiration_year_->max_length == 2)
? CREDIT_CARD_EXP_2_DIGIT_YEAR
: CREDIT_CARD_EXP_4_DIGIT_YEAR));
}
} // namespace autofill
......@@ -31,12 +31,17 @@ class CreditCardField : public FormField {
CreditCardField();
// For the combined expiration field we return |exp_year_type_|; otherwise if
// |expiration_year_| is having year with |max_length| of 2-digits we return
// |CREDIT_CARD_EXP_2_DIGIT_YEAR|; otherwise |CREDIT_CARD_EXP_4_DIGIT_YEAR|.
ServerFieldType GetExpirationYearType() const;
const AutofillField* cardholder_; // Optional.
// Occasionally pages have separate fields for the cardholder's first and
// last names; for such pages cardholder_ holds the first name field and
// last names; for such pages |cardholder_| holds the first name field and
// we store the last name field here.
// (We could store an embedded NameField object here, but we don't do so
// (We could store an embedded |NameField| object here, but we don't do so
// because the text patterns for matching a cardholder name are different
// than for ordinary names, and because cardholder names never have titles,
// middle names or suffixes.)
......@@ -55,9 +60,10 @@ class CreditCardField : public FormField {
const AutofillField* expiration_year_;
const AutofillField* expiration_date_;
// True if the year is detected to be a 2-digit year; otherwise, we assume
// a 4-digit year.
bool is_two_digit_year_;
// For combined expiration field having year as 2-digits we store here
// |CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR|; otherwise we store
// |CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR|.
ServerFieldType exp_year_type_;
DISALLOW_COPY_AND_ASSIGN(CreditCardField);
};
......
......@@ -347,4 +347,37 @@ TEST_F(CreditCardFieldTest, ParseMonthControl) {
field_type_map_[ASCIIToUTF16("date2")]);
}
// Verify that heuristics <input name="ccyear" maxlength="2"/> considers
// *maxlength* attribute while parsing 2 Digit expiration year.
TEST_F(CreditCardFieldTest, ParseCreditCardExpYear_2DigitMaxLength) {
FormFieldData field;
field.form_control_type = "text";
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
list_.push_back(new AutofillField(field, ASCIIToUTF16("number")));
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("ccmonth");
list_.push_back(new AutofillField(field, ASCIIToUTF16("month")));
field.name = ASCIIToUTF16("ccyear");
field.max_length = 2;
list_.push_back(new AutofillField(field, ASCIIToUTF16("year")));
Parse();
ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
EXPECT_TRUE(ClassifyField());
ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number")) !=
field_type_map_.end());
EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number")]);
ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("month")) !=
field_type_map_.end());
EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month")]);
ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("year")) !=
field_type_map_.end());
EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR,
field_type_map_[ASCIIToUTF16("year")]);
}
} // namespace autofill
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment