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_field.h"
6
7#include <stddef.h>
8
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/strings/string16.h"
12#include "base/strings/string_util.h"
13#include "base/strings/utf_string_conversions.h"
14#include "components/autofill/core/browser/autofill_field.h"
15#include "components/autofill/core/browser/autofill_regex_constants.h"
16#include "components/autofill/core/browser/autofill_scanner.h"
17#include "components/autofill/core/browser/field_types.h"
18#include "ui/base/l10n/l10n_util.h"
19
20namespace autofill {
21
22// Credit card numbers are at most 19 digits in length.
23// [Ref: http://en.wikipedia.org/wiki/Bank_card_number]
24static const size_t kMaxValidCardNumberSize = 19;
25
26// static
27FormField* CreditCardField::Parse(AutofillScanner* scanner) {
28  if (scanner->IsEnd())
29    return NULL;
30
31  scoped_ptr<CreditCardField> credit_card_field(new CreditCardField);
32  size_t saved_cursor = scanner->SaveCursor();
33  bool form_has_valid_card_number_fields = true;
34
35  // Credit card fields can appear in many different orders.
36  // We loop until no more credit card related fields are found, see |break| at
37  // bottom of the loop.
38  for (int fields = 0; !scanner->IsEnd(); ++fields) {
39    // Ignore gift card fields.
40    if (ParseField(scanner, base::UTF8ToUTF16(autofill::kGiftCardRe), NULL))
41      break;
42
43    // Sometimes the cardholder field is just labeled "name". Unfortunately this
44    // is a dangerously generic word to search for, since it will often match a
45    // name (not cardholder name) field before or after credit card fields. So
46    // we search for "name" only when we've already parsed at least one other
47    // credit card field and haven't yet parsed the expiration date (which
48    // usually appears at the end).
49    if (credit_card_field->cardholder_ == NULL) {
50      base::string16 name_pattern;
51      if (fields == 0 || credit_card_field->expiration_month_) {
52        // at beginning or end
53        name_pattern = base::UTF8ToUTF16(autofill::kNameOnCardRe);
54      } else {
55        name_pattern = base::UTF8ToUTF16(autofill::kNameOnCardContextualRe);
56      }
57
58      if (ParseField(scanner, name_pattern, &credit_card_field->cardholder_))
59        continue;
60
61      // As a hard-coded hack for Expedia's billing pages (expedia_checkout.html
62      // and ExpediaBilling.html in our test suite), recognize separate fields
63      // for the cardholder's first and last name if they have the labels "cfnm"
64      // and "clnm".
65      scanner->SaveCursor();
66      AutofillField* first;
67      if (ParseField(scanner, base::ASCIIToUTF16("^cfnm"), &first) &&
68          ParseField(scanner,
69                     base::ASCIIToUTF16("^clnm"),
70                     &credit_card_field->cardholder_last_)) {
71        credit_card_field->cardholder_ = first;
72        continue;
73      }
74      scanner->Rewind();
75    }
76
77    // Check for a credit card type (Visa, MasterCard, etc.) field.
78    base::string16 type_pattern = base::UTF8ToUTF16(autofill::kCardTypeRe);
79    if (!credit_card_field->type_ &&
80        ParseFieldSpecifics(scanner,
81                            type_pattern,
82                            MATCH_DEFAULT | MATCH_SELECT,
83                            &credit_card_field->type_)) {
84      continue;
85    }
86
87    // We look for a card security code before we look for a credit
88    // card number and match the general term "number".  The security code
89    // has a plethora of names; we've seen "verification #",
90    // "verification number", "card identification number" and others listed
91    // in the |pattern| below.
92    base::string16 pattern = base::UTF8ToUTF16(autofill::kCardCvcRe);
93    if (!credit_card_field->verification_ &&
94        ParseField(scanner, pattern, &credit_card_field->verification_)) {
95      continue;
96    }
97
98    pattern = base::UTF8ToUTF16(autofill::kCardNumberRe);
99    AutofillField* current_number_field;
100    if (ParseField(scanner, pattern, &current_number_field)) {
101      // Avoid autofilling any credit card number field having very low or high
102      // |start_index| on the HTML form.
103      size_t start_index = 0;
104      if (!credit_card_field->numbers_.empty()) {
105        size_t last_number_field_size =
106            credit_card_field->numbers_.back()->credit_card_number_offset() +
107            credit_card_field->numbers_.back()->max_length;
108
109        // In some cases, HTML form may have credit card number split across
110        // multiple input fields and either one or cumulatively having
111        // |max_length| more than |kMaxValidCardNumberSize|, mark these input
112        // form fields as invalid and skip autofilling them.
113        if (last_number_field_size == 0U ||
114            last_number_field_size >= kMaxValidCardNumberSize) {
115          // Mark that the credit card number splits are invalid. But keep
116          // scanning HTML form so that cursor moves beyond related fields.
117          form_has_valid_card_number_fields = false;
118        }
119
120        start_index = last_number_field_size;
121      }
122
123      current_number_field->set_credit_card_number_offset(start_index);
124      credit_card_field->numbers_.push_back(current_number_field);
125      continue;
126    }
127
128    if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) {
129      credit_card_field->expiration_date_ = scanner->Cursor();
130      scanner->Advance();
131    } else {
132      // First try to parse split month/year expiration fields.
133      scanner->SaveCursor();
134      pattern = base::UTF8ToUTF16(autofill::kExpirationMonthRe);
135      if (!credit_card_field->expiration_month_ &&
136          ParseFieldSpecifics(scanner,
137                              pattern,
138                              MATCH_DEFAULT | MATCH_SELECT,
139                              &credit_card_field->expiration_month_)) {
140        pattern = base::UTF8ToUTF16(autofill::kExpirationYearRe);
141        if (ParseFieldSpecifics(scanner,
142                                pattern,
143                                MATCH_DEFAULT | MATCH_SELECT,
144                                &credit_card_field->expiration_year_)) {
145          continue;
146        }
147      }
148
149      // If that fails, try to parse a combined expiration field.
150      if (!credit_card_field->expiration_date_) {
151        // Look for a 2-digit year first.
152        scanner->Rewind();
153        pattern = base::UTF8ToUTF16(autofill::kExpirationDate2DigitYearRe);
154        // We allow <select> fields, because they're used e.g. on qvc.com.
155        if (ParseFieldSpecifics(
156                scanner,
157                pattern,
158                MATCH_LABEL | MATCH_VALUE | MATCH_TEXT | MATCH_SELECT,
159                &credit_card_field->expiration_date_)) {
160          credit_card_field->exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
161          continue;
162        }
163
164        pattern = base::UTF8ToUTF16(autofill::kExpirationDateRe);
165        if (ParseFieldSpecifics(
166                scanner,
167                pattern,
168                MATCH_LABEL | MATCH_VALUE | MATCH_TEXT | MATCH_SELECT,
169                &credit_card_field->expiration_date_)) {
170          continue;
171        }
172      }
173
174      if (credit_card_field->expiration_month_ &&
175          !credit_card_field->expiration_year_ &&
176          !credit_card_field->expiration_date_) {
177        // Parsed a month but couldn't parse a year; give up.
178        scanner->RewindTo(saved_cursor);
179        return NULL;
180      }
181    }
182
183    // Some pages (e.g. ExpediaBilling.html) have a "card description"
184    // field; we parse this field but ignore it.
185    // We also ignore any other fields within a credit card block that
186    // start with "card", under the assumption that they are related to
187    // the credit card section being processed but are uninteresting to us.
188    if (ParseField(scanner, base::UTF8ToUTF16(autofill::kCardIgnoredRe), NULL))
189      continue;
190
191    break;
192  }
193
194  // Cases where heuristic misinterprets input field as credit card number
195  // field, refuse to autofill credit card number fields.
196  if (!form_has_valid_card_number_fields)
197    credit_card_field->numbers_.clear();
198
199  // Some pages have a billing address field after the cardholder name field.
200  // For that case, allow only just the cardholder name field.  The remaining
201  // CC fields will be picked up in a following CreditCardField.
202  if (credit_card_field->cardholder_)
203    return credit_card_field.release();
204
205  // On some pages, the user selects a card type using radio buttons
206  // (e.g. test page Apple Store Billing.html).  We can't handle that yet,
207  // so we treat the card type as optional for now.
208  // The existence of a number or cvc in combination with expiration date is
209  // a strong enough signal that this is a credit card.  It is possible that
210  // the number and name were parsed in a separate part of the form.  So if
211  // the cvc and date were found independently they are returned.
212  if ((!credit_card_field->numbers_.empty() ||
213       credit_card_field->verification_ ||
214       !form_has_valid_card_number_fields) &&
215      (credit_card_field->expiration_date_ ||
216       (credit_card_field->expiration_month_ &&
217        credit_card_field->expiration_year_))) {
218    return credit_card_field.release();
219  }
220
221  scanner->RewindTo(saved_cursor);
222  return NULL;
223}
224
225CreditCardField::CreditCardField()
226    : cardholder_(NULL),
227      cardholder_last_(NULL),
228      type_(NULL),
229      verification_(NULL),
230      expiration_month_(NULL),
231      expiration_year_(NULL),
232      expiration_date_(NULL),
233      exp_year_type_(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) {
234}
235
236CreditCardField::~CreditCardField() {
237}
238
239bool CreditCardField::ClassifyField(ServerFieldTypeMap* map) const {
240  bool ok = true;
241  for (size_t index = 0; index < numbers_.size(); ++index) {
242    ok = ok && AddClassification(numbers_[index], CREDIT_CARD_NUMBER, map);
243  }
244
245  ok = ok && AddClassification(type_, CREDIT_CARD_TYPE, map);
246  ok = ok &&
247       AddClassification(verification_, CREDIT_CARD_VERIFICATION_CODE, map);
248
249  // If the heuristics detected first and last name in separate fields,
250  // then ignore both fields. Putting them into separate fields is probably
251  // wrong, because the credit card can also contain a middle name or middle
252  // initial.
253  if (cardholder_last_ == NULL)
254    ok = ok && AddClassification(cardholder_, CREDIT_CARD_NAME, map);
255
256  if (expiration_date_) {
257    ok =
258        ok && AddClassification(expiration_date_, GetExpirationYearType(), map);
259  } else {
260    ok = ok && AddClassification(expiration_month_, CREDIT_CARD_EXP_MONTH, map);
261    ok =
262        ok && AddClassification(expiration_year_, GetExpirationYearType(), map);
263  }
264
265  return ok;
266}
267
268ServerFieldType CreditCardField::GetExpirationYearType() const {
269  return (expiration_date_
270              ? exp_year_type_
271              : ((expiration_year_ && expiration_year_->max_length == 2)
272                     ? CREDIT_CARD_EXP_2_DIGIT_YEAR
273                     : CREDIT_CARD_EXP_4_DIGIT_YEAR));
274}
275
276}  // namespace autofill
277