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

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

Issue 1453193002: autofill: switch autofill_regexes to RE2 library (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address reviews Created 5 years 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_field.h" 5 #include "components/autofill/core/browser/credit_card_field.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
11 #include "base/strings/string16.h" 11 #include "base/strings/string16.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h" 14 #include "base/time/time.h"
16 #include "components/autofill/core/browser/autofill_field.h" 15 #include "components/autofill/core/browser/autofill_field.h"
17 #include "components/autofill/core/browser/autofill_regex_constants.h" 16 #include "components/autofill/core/browser/autofill_regex_constants.h"
18 #include "components/autofill/core/browser/autofill_scanner.h" 17 #include "components/autofill/core/browser/autofill_scanner.h"
19 #include "components/autofill/core/browser/field_types.h" 18 #include "components/autofill/core/browser/field_types.h"
20 #include "components/autofill/core/common/autofill_regexes.h" 19 #include "components/autofill/core/common/autofill_regexes.h"
21 #include "grit/components_strings.h" 20 #include "grit/components_strings.h"
22 #include "ui/base/l10n/l10n_util.h" 21 #include "ui/base/l10n/l10n_util.h"
23 22
24 namespace autofill { 23 namespace autofill {
25 24
26 namespace { 25 namespace {
27 26
28 // Credit card numbers are at most 19 digits in length. 27 // Credit card numbers are at most 19 digits in length.
29 // [Ref: http://en.wikipedia.org/wiki/Bank_card_number] 28 // [Ref: http://en.wikipedia.org/wiki/Bank_card_number]
30 const size_t kMaxValidCardNumberSize = 19; 29 const size_t kMaxValidCardNumberSize = 19;
31 30
32 // Look for the vector |regex_needles| in |haystack|. Returns true if a 31 // Look for the vector |regex_needles| in |haystack|. Returns true if a
33 // consecutive section of |haystack| matches |regex_needles|. 32 // consecutive section of |haystack| matches |regex_needles|.
34 bool FindConsecutiveStrings(const std::vector<base::string16>& regex_needles, 33 bool FindConsecutiveStrings(const std::vector<std::string>& regex_needles,
35 const std::vector<base::string16>& haystack) { 34 const std::vector<base::string16>& haystack) {
36 if (regex_needles.empty() || 35 if (regex_needles.empty() ||
37 haystack.empty() || 36 haystack.empty() ||
38 (haystack.size() < regex_needles.size())) 37 (haystack.size() < regex_needles.size()))
39 return false; 38 return false;
40 39
41 for (size_t i = 0; i < haystack.size() - regex_needles.size() + 1; ++i) { 40 for (size_t i = 0; i < haystack.size() - regex_needles.size() + 1; ++i) {
42 for (size_t j = 0; j < regex_needles.size(); ++j) { 41 for (size_t j = 0; j < regex_needles.size(); ++j) {
43 if (!MatchesPattern(haystack[i + j], regex_needles[j])) 42 if (!MatchesPattern(haystack[i + j], regex_needles[j]))
44 break; 43 break;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 83
85 // Credit card fields can appear in many different orders. 84 // Credit card fields can appear in many different orders.
86 // We loop until no more credit card related fields are found, see |break| at 85 // We loop until no more credit card related fields are found, see |break| at
87 // the bottom of the loop. 86 // the bottom of the loop.
88 for (int fields = 0; !scanner->IsEnd(); ++fields) { 87 for (int fields = 0; !scanner->IsEnd(); ++fields) {
89 // Ignore gift card fields. 88 // Ignore gift card fields.
90 if (IsGiftCardField(scanner)) 89 if (IsGiftCardField(scanner))
91 break; 90 break;
92 91
93 if (!credit_card_field->cardholder_) { 92 if (!credit_card_field->cardholder_) {
94 if (ParseField(scanner, 93 if (ParseField(scanner, kNameOnCardRe, &credit_card_field->cardholder_)) {
95 base::UTF8ToUTF16(kNameOnCardRe),
96 &credit_card_field->cardholder_)) {
97 continue; 94 continue;
98 } 95 }
99 96
100 // Sometimes the cardholder field is just labeled "name". Unfortunately 97 // Sometimes the cardholder field is just labeled "name". Unfortunately
101 // this is a dangerously generic word to search for, since it will often 98 // this is a dangerously generic word to search for, since it will often
102 // match a name (not cardholder name) field before or after credit card 99 // match a name (not cardholder name) field before or after credit card
103 // fields. So we search for "name" only when we've already parsed at 100 // fields. So we search for "name" only when we've already parsed at
104 // least one other credit card field and haven't yet parsed the 101 // least one other credit card field and haven't yet parsed the
105 // expiration date (which usually appears at the end). 102 // expiration date (which usually appears at the end).
106 if (fields > 0 && 103 if (fields > 0 && !credit_card_field->expiration_month_ &&
107 !credit_card_field->expiration_month_ && 104 ParseField(scanner, kNameOnCardContextualRe,
108 ParseField(scanner,
109 base::UTF8ToUTF16(kNameOnCardContextualRe),
110 &credit_card_field->cardholder_)) { 105 &credit_card_field->cardholder_)) {
111 continue; 106 continue;
112 } 107 }
113 } 108 }
114 109
115 // Check for a credit card type (Visa, MasterCard, etc.) field. 110 // Check for a credit card type (Visa, MasterCard, etc.) field.
116 // All CC type fields encountered so far have been of type select. 111 // All CC type fields encountered so far have been of type select.
117 if (!credit_card_field->type_ && LikelyCardTypeSelectField(scanner)) { 112 if (!credit_card_field->type_ && LikelyCardTypeSelectField(scanner)) {
118 credit_card_field->type_ = scanner->Cursor(); 113 credit_card_field->type_ = scanner->Cursor();
119 scanner->Advance(); 114 scanner->Advance();
120 continue; 115 continue;
121 } 116 }
122 117
123 // We look for a card security code before we look for a credit card number 118 // We look for a card security code before we look for a credit card number
124 // and match the general term "number". The security code has a plethora of 119 // and match the general term "number". The security code has a plethora of
125 // names; we've seen "verification #", "verification number", "card 120 // names; we've seen "verification #", "verification number", "card
126 // identification number", and others listed in the regex pattern used 121 // identification number", and others listed in the regex pattern used
127 // below. 122 // below.
128 // Note: Some sites use type="tel" or type="number" for numerical inputs. 123 // Note: Some sites use type="tel" or type="number" for numerical inputs.
129 const int kMatchNumAndTel = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE; 124 const int kMatchNumAndTel = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE;
130 if (!credit_card_field->verification_ && 125 if (!credit_card_field->verification_ &&
131 ParseFieldSpecifics(scanner, 126 ParseFieldSpecifics(scanner,
132 base::UTF8ToUTF16(kCardCvcRe), 127 kCardCvcRe,
133 kMatchNumAndTel | MATCH_PASSWORD, 128 kMatchNumAndTel | MATCH_PASSWORD,
134 &credit_card_field->verification_)) { 129 &credit_card_field->verification_)) {
135 continue; 130 continue;
136 } 131 }
137 132
138 AutofillField* current_number_field; 133 AutofillField* current_number_field;
139 if (ParseFieldSpecifics(scanner, 134 if (ParseFieldSpecifics(scanner,
140 base::UTF8ToUTF16(kCardNumberRe), 135 kCardNumberRe,
141 kMatchNumAndTel, 136 kMatchNumAndTel,
142 &current_number_field)) { 137 &current_number_field)) {
143 // Avoid autofilling any credit card number field having very low or high 138 // Avoid autofilling any credit card number field having very low or high
144 // |start_index| on the HTML form. 139 // |start_index| on the HTML form.
145 size_t start_index = 0; 140 size_t start_index = 0;
146 if (!credit_card_field->numbers_.empty()) { 141 if (!credit_card_field->numbers_.empty()) {
147 size_t last_number_field_size = 142 size_t last_number_field_size =
148 credit_card_field->numbers_.back()->credit_card_number_offset() + 143 credit_card_field->numbers_.back()->credit_card_number_offset() +
149 credit_card_field->numbers_.back()->max_length; 144 credit_card_field->numbers_.back()->max_length;
150 145
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 return false; 202 return false;
208 203
209 AutofillField* field = scanner->Cursor(); 204 AutofillField* field = scanner->Cursor();
210 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) 205 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
211 return false; 206 return false;
212 207
213 if (field->option_values.size() < 12 || field->option_values.size() > 13) 208 if (field->option_values.size() < 12 || field->option_values.size() > 13)
214 return false; 209 return false;
215 210
216 // Filter out years. 211 // Filter out years.
217 const base::string16 kNumericalYearRe = 212 const char kNumericalYearRe[] = "[1-9][0-9][0-9][0-9]";
218 base::ASCIIToUTF16("[1-9][0-9][0-9][0-9]");
219 for (const auto& value : field->option_values) { 213 for (const auto& value : field->option_values) {
220 if (MatchesPattern(value, kNumericalYearRe)) 214 if (MatchesPattern(value, kNumericalYearRe))
221 return false; 215 return false;
222 } 216 }
223 for (const auto& value : field->option_contents) { 217 for (const auto& value : field->option_contents) {
224 if (MatchesPattern(value, kNumericalYearRe)) 218 if (MatchesPattern(value, kNumericalYearRe))
225 return false; 219 return false;
226 } 220 }
227 221
228 // Look for numerical months. 222 // Look for numerical months.
229 const base::string16 kNumericalMonthRe = base::ASCIIToUTF16("12"); 223 const char kNumericalMonthRe[] = "12";
230 if (MatchesPattern(field->option_values.back(), kNumericalMonthRe) || 224 if (MatchesPattern(field->option_values.back(), kNumericalMonthRe) ||
231 MatchesPattern(field->option_contents.back(), kNumericalMonthRe)) { 225 MatchesPattern(field->option_contents.back(), kNumericalMonthRe)) {
232 return true; 226 return true;
233 } 227 }
234 228
235 // Maybe do more matches here. e.g. look for (translated) December. 229 // Maybe do more matches here. e.g. look for (translated) December.
236 230
237 // Unsure? Return false. 231 // Unsure? Return false.
238 return false; 232 return false;
239 } 233 }
240 234
241 // static 235 // static
242 bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) { 236 bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) {
243 if (scanner->IsEnd()) 237 if (scanner->IsEnd())
244 return false; 238 return false;
245 239
246 AutofillField* field = scanner->Cursor(); 240 AutofillField* field = scanner->Cursor();
247 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) 241 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
248 return false; 242 return false;
249 243
250 const base::Time time_now = base::Time::Now(); 244 const base::Time time_now = base::Time::Now();
251 base::Time::Exploded time_exploded; 245 base::Time::Exploded time_exploded;
252 time_now.UTCExplode(&time_exploded); 246 time_now.UTCExplode(&time_exploded);
253 247
254 const int kYearsToMatch = 3; 248 const int kYearsToMatch = 3;
255 std::vector<base::string16> years_to_check; 249 std::vector<std::string> years_to_check;
256 for (int year = time_exploded.year; 250 for (int year = time_exploded.year;
257 year < time_exploded.year + kYearsToMatch; 251 year < time_exploded.year + kYearsToMatch;
258 ++year) { 252 ++year) {
259 years_to_check.push_back(base::IntToString16(year)); 253 years_to_check.push_back(base::IntToString(year));
260 } 254 }
261 return (FindConsecutiveStrings(years_to_check, field->option_values) || 255 return (FindConsecutiveStrings(years_to_check, field->option_values) ||
262 FindConsecutiveStrings(years_to_check, field->option_contents)); 256 FindConsecutiveStrings(years_to_check, field->option_contents));
263 } 257 }
264 258
265 // static 259 // static
266 bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) { 260 bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) {
267 if (scanner->IsEnd()) 261 if (scanner->IsEnd())
268 return false; 262 return false;
269 263
270 AutofillField* field = scanner->Cursor(); 264 AutofillField* field = scanner->Cursor();
271 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) 265 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
272 return false; 266 return false;
273 267
274 return AutofillField::FindValueInSelectControl( 268 return AutofillField::FindValueInSelectControl(
275 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA), 269 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA),
276 nullptr) || 270 nullptr) ||
277 AutofillField::FindValueInSelectControl( 271 AutofillField::FindValueInSelectControl(
278 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD), 272 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD),
279 nullptr); 273 nullptr);
280 } 274 }
281 275
282 // static 276 // static
283 bool CreditCardField::IsGiftCardField(AutofillScanner* scanner) { 277 bool CreditCardField::IsGiftCardField(AutofillScanner* scanner) {
284 if (scanner->IsEnd()) 278 if (scanner->IsEnd())
285 return false; 279 return false;
286 280
287 size_t saved_cursor = scanner->SaveCursor(); 281 size_t saved_cursor = scanner->SaveCursor();
288 if (ParseField(scanner, base::UTF8ToUTF16(kDebitCardRe), nullptr)) { 282 if (ParseField(scanner, kDebitCardRe, nullptr)) {
289 scanner->RewindTo(saved_cursor); 283 scanner->RewindTo(saved_cursor);
290 return false; 284 return false;
291 } 285 }
292 if (ParseField(scanner, base::UTF8ToUTF16(kDebitGiftCardRe), nullptr)) { 286 if (ParseField(scanner, kDebitGiftCardRe, nullptr)) {
293 scanner->RewindTo(saved_cursor); 287 scanner->RewindTo(saved_cursor);
294 return false; 288 return false;
295 } 289 }
296 290
297 return ParseField(scanner, base::UTF8ToUTF16(kGiftCardRe), nullptr); 291 return ParseField(scanner, kGiftCardRe, nullptr);
298 } 292 }
299 293
300 CreditCardField::CreditCardField() 294 CreditCardField::CreditCardField()
301 : cardholder_(nullptr), 295 : cardholder_(nullptr),
302 cardholder_last_(nullptr), 296 cardholder_last_(nullptr),
303 type_(nullptr), 297 type_(nullptr),
304 verification_(nullptr), 298 verification_(nullptr),
305 expiration_month_(nullptr), 299 expiration_month_(nullptr),
306 expiration_year_(nullptr), 300 expiration_year_(nullptr),
307 expiration_date_(nullptr), 301 expiration_date_(nullptr),
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 return true; 363 return true;
370 } 364 }
371 expiration_month_ = nullptr; 365 expiration_month_ = nullptr;
372 expiration_year_ = nullptr; 366 expiration_year_ = nullptr;
373 } 367 }
374 368
375 // If that fails, do a general regex search. 369 // If that fails, do a general regex search.
376 scanner->RewindTo(month_year_saved_cursor); 370 scanner->RewindTo(month_year_saved_cursor);
377 const int kMatchTelAndSelect = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_SELECT; 371 const int kMatchTelAndSelect = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_SELECT;
378 if (ParseFieldSpecifics(scanner, 372 if (ParseFieldSpecifics(scanner,
379 base::UTF8ToUTF16(kExpirationMonthRe), 373 kExpirationMonthRe,
380 kMatchTelAndSelect, 374 kMatchTelAndSelect,
381 &expiration_month_) && 375 &expiration_month_) &&
382 ParseFieldSpecifics(scanner, 376 ParseFieldSpecifics(scanner,
383 base::UTF8ToUTF16(kExpirationYearRe), 377 kExpirationYearRe,
384 kMatchTelAndSelect, 378 kMatchTelAndSelect,
385 &expiration_year_)) { 379 &expiration_year_)) {
386 return true; 380 return true;
387 } 381 }
388 382
389 // If that fails, look for just MM/YY(YY). 383 // If that fails, look for just MM/YY(YY).
390 scanner->RewindTo(month_year_saved_cursor); 384 scanner->RewindTo(month_year_saved_cursor);
391 if (ParseFieldSpecifics(scanner, 385 if (ParseFieldSpecifics(scanner,
392 base::ASCIIToUTF16("^mm$"), 386 "^mm$",
393 kMatchTelAndSelect, 387 kMatchTelAndSelect,
394 &expiration_month_) && 388 &expiration_month_) &&
395 ParseFieldSpecifics(scanner, 389 ParseFieldSpecifics(scanner,
396 base::ASCIIToUTF16("^(yy|yyyy)$"), 390 "^(yy|yyyy)$",
397 kMatchTelAndSelect, 391 kMatchTelAndSelect,
398 &expiration_year_)) { 392 &expiration_year_)) {
399 return true; 393 return true;
400 } 394 }
401 395
402 // If that fails, try to parse a combined expiration field. 396 // If that fails, try to parse a combined expiration field.
403 // We allow <select> fields, because they're used e.g. on qvc.com. 397 // We allow <select> fields, because they're used e.g. on qvc.com.
404 scanner->RewindTo(month_year_saved_cursor); 398 scanner->RewindTo(month_year_saved_cursor);
405 399
406 // Bail out if the field cannot fit a 2-digit year expiration date. 400 // Bail out if the field cannot fit a 2-digit year expiration date.
407 const int current_field_max_length = scanner->Cursor()->max_length; 401 const int current_field_max_length = scanner->Cursor()->max_length;
408 if (!FieldCanFitDataForFieldType(current_field_max_length, 402 if (!FieldCanFitDataForFieldType(current_field_max_length,
409 CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR)) { 403 CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR)) {
410 return false; 404 return false;
411 } 405 }
412 406
413 // Try to look for a 2-digit year expiration date. 407 // Try to look for a 2-digit year expiration date.
414 if (ParseFieldSpecifics(scanner, 408 if (ParseFieldSpecifics(scanner,
415 base::UTF8ToUTF16(kExpirationDate2DigitYearRe), 409 kExpirationDate2DigitYearRe,
416 kMatchTelAndSelect, 410 kMatchTelAndSelect,
417 &expiration_date_)) { 411 &expiration_date_)) {
418 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; 412 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
419 expiration_month_ = nullptr; 413 expiration_month_ = nullptr;
420 return true; 414 return true;
421 } 415 }
422 416
423 // Try to look for a generic expiration date field. (2 or 4 digit year) 417 // Try to look for a generic expiration date field. (2 or 4 digit year)
424 if (ParseFieldSpecifics(scanner, 418 if (ParseFieldSpecifics(scanner,
425 base::UTF8ToUTF16(kExpirationDateRe), 419 kExpirationDateRe,
426 kMatchTelAndSelect, 420 kMatchTelAndSelect,
427 &expiration_date_)) { 421 &expiration_date_)) {
428 // If such a field exists, but it cannot fit a 4-digit year expiration 422 // If such a field exists, but it cannot fit a 4-digit year expiration
429 // date, then the likely possibility is that it is a 2-digit year expiration 423 // date, then the likely possibility is that it is a 2-digit year expiration
430 // date. 424 // date.
431 if (!FieldCanFitDataForFieldType(current_field_max_length, 425 if (!FieldCanFitDataForFieldType(current_field_max_length,
432 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)) { 426 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)) {
433 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; 427 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
434 } 428 }
435 expiration_month_ = nullptr; 429 expiration_month_ = nullptr;
436 return true; 430 return true;
437 } 431 }
438 432
439 // Try to look for a 4-digit year expiration date. 433 // Try to look for a 4-digit year expiration date.
440 if (FieldCanFitDataForFieldType(current_field_max_length, 434 if (FieldCanFitDataForFieldType(current_field_max_length,
441 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) && 435 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) &&
442 ParseFieldSpecifics(scanner, 436 ParseFieldSpecifics(scanner,
443 base::UTF8ToUTF16(kExpirationDate4DigitYearRe), 437 kExpirationDate4DigitYearRe,
444 kMatchTelAndSelect, 438 kMatchTelAndSelect,
445 &expiration_date_)) { 439 &expiration_date_)) {
446 expiration_month_ = nullptr; 440 expiration_month_ = nullptr;
447 return true; 441 return true;
448 } 442 }
449 443
450 return false; 444 return false;
451 } 445 }
452 446
453 ServerFieldType CreditCardField::GetExpirationYearType() const { 447 ServerFieldType CreditCardField::GetExpirationYearType() const {
454 return (expiration_date_ 448 return (expiration_date_
455 ? exp_year_type_ 449 ? exp_year_type_
456 : ((expiration_year_ && expiration_year_->max_length == 2) 450 : ((expiration_year_ && expiration_year_->max_length == 2)
457 ? CREDIT_CARD_EXP_2_DIGIT_YEAR 451 ? CREDIT_CARD_EXP_2_DIGIT_YEAR
458 : CREDIT_CARD_EXP_4_DIGIT_YEAR)); 452 : CREDIT_CARD_EXP_4_DIGIT_YEAR));
459 } 453 }
460 454
461 } // namespace autofill 455 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698