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