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/validation.h"
6
7 #include <stddef.h>
8
9 #include "base/check.h"
10 #include "base/notreached.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "components/autofill/core/browser/autofill_data_util.h"
17 #include "components/autofill/core/browser/autofill_regex_constants.h"
18 #include "components/autofill/core/browser/autofill_regexes.h"
19 #include "components/autofill/core/browser/data_model/credit_card.h"
20 #include "components/autofill/core/browser/geo/phone_number_i18n.h"
21 #include "components/autofill/core/browser/geo/state_names.h"
22 #include "components/autofill/core/common/autofill_clock.h"
23 #include "components/strings/grit/components_strings.h"
24 #include "ui/base/l10n/l10n_util.h"
25
26 namespace autofill {
27
IsValidCreditCardExpirationDate(int year,int month,const base::Time & now)28 bool IsValidCreditCardExpirationDate(int year,
29 int month,
30 const base::Time& now) {
31 if (month < 1 || month > 12)
32 return false;
33
34 base::Time::Exploded now_exploded;
35 now.LocalExplode(&now_exploded);
36
37 if (year < now_exploded.year)
38 return false;
39
40 if (year == now_exploded.year && month < now_exploded.month)
41 return false;
42
43 return true;
44 }
45
IsValidCreditCardExpirationYear(int year,const base::Time & now)46 bool IsValidCreditCardExpirationYear(int year, const base::Time& now) {
47 base::Time::Exploded now_exploded;
48 now.LocalExplode(&now_exploded);
49
50 return year >= now_exploded.year;
51 }
52
IsValidCreditCardNumber(const base::string16 & text)53 bool IsValidCreditCardNumber(const base::string16& text) {
54 const base::string16 number = CreditCard::StripSeparators(text);
55
56 if (!HasCorrectLength(number))
57 return false;
58
59 return PassesLuhnCheck(number);
60 }
61
HasCorrectLength(const base::string16 & number)62 bool HasCorrectLength(const base::string16& number) {
63 // Credit card numbers are at most 19 digits in length, 12 digits seems to
64 // be a fairly safe lower-bound [1]. Specific card issuers have more rigidly
65 // defined sizes.
66 // (Last updated: May 29, 2017)
67 // [1] https://en.wikipedia.org/wiki/Payment_card_number.
68 // CardEditor.isCardNumberLengthMaxium() needs to be kept in sync.
69 const char* const type = CreditCard::GetCardNetwork(number);
70 if (type == kAmericanExpressCard && number.size() != 15)
71 return false;
72 if (type == kDinersCard && number.size() != 14)
73 return false;
74 if (type == kDiscoverCard && number.size() != 16)
75 return false;
76 if (type == kEloCard && number.size() != 16)
77 return false;
78 if (type == kJCBCard && number.size() != 16)
79 return false;
80 if (type == kMasterCard && number.size() != 16)
81 return false;
82 if (type == kMirCard && number.size() != 16)
83 return false;
84 if (type == kTroyCard && number.size() != 16)
85 return false;
86 if (type == kUnionPay && (number.size() < 16 || number.size() > 19))
87 return false;
88 if (type == kVisaCard && number.size() != 13 && number.size() != 16 &&
89 number.size() != 19)
90 return false;
91 if (type == kGenericCard && (number.size() < 12 || number.size() > 19))
92 return false;
93
94 return true;
95 }
96
97 // TODO(crbug.com/927767): Add unit tests for this function.
PassesLuhnCheck(const base::string16 & number)98 bool PassesLuhnCheck(const base::string16& number) {
99 // Use the Luhn formula [3] to validate the number.
100 // [3] http://en.wikipedia.org/wiki/Luhn_algorithm
101 int sum = 0;
102 bool odd = false;
103 for (base::string16::const_reverse_iterator iter = number.rbegin();
104 iter != number.rend(); ++iter) {
105 if (!base::IsAsciiDigit(*iter))
106 return false;
107
108 int digit = *iter - '0';
109 if (odd) {
110 digit *= 2;
111 sum += digit / 10 + digit % 10;
112 } else {
113 sum += digit;
114 }
115 odd = !odd;
116 }
117
118 return (sum % 10) == 0;
119 }
120
IsValidCreditCardSecurityCode(const base::string16 & code,const base::StringPiece card_network)121 bool IsValidCreditCardSecurityCode(const base::string16& code,
122 const base::StringPiece card_network) {
123 return code.length() == GetCvcLengthForCardNetwork(card_network) &&
124 base::ContainsOnlyChars(code, base::ASCIIToUTF16("0123456789"));
125 }
126
IsValidCreditCardNumberForBasicCardNetworks(const base::string16 & text,const std::set<std::string> & supported_basic_card_networks,base::string16 * error_message)127 bool IsValidCreditCardNumberForBasicCardNetworks(
128 const base::string16& text,
129 const std::set<std::string>& supported_basic_card_networks,
130 base::string16* error_message) {
131 DCHECK(error_message);
132
133 // The type check is cheaper than the credit card number check.
134 const std::string basic_card_issuer_network =
135 autofill::data_util::GetPaymentRequestData(
136 CreditCard::GetCardNetwork(text))
137 .basic_card_issuer_network;
138 if (!supported_basic_card_networks.count(basic_card_issuer_network)) {
139 *error_message = l10n_util::GetStringUTF16(
140 IDS_PAYMENTS_VALIDATION_UNSUPPORTED_CREDIT_CARD_TYPE);
141 return false;
142 }
143
144 if (IsValidCreditCardNumber(text))
145 return true;
146
147 *error_message = l10n_util::GetStringUTF16(
148 IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE);
149 return false;
150 }
151
IsValidEmailAddress(const base::string16 & text)152 bool IsValidEmailAddress(const base::string16& text) {
153 // E-Mail pattern as defined by the WhatWG. (4.10.7.1.5 E-Mail state)
154 const base::string16 kEmailPattern = base::ASCIIToUTF16(
155 "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@"
156 "[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$");
157 return MatchesPattern(text, kEmailPattern);
158 }
159
IsValidState(const base::string16 & text)160 bool IsValidState(const base::string16& text) {
161 return !state_names::GetAbbreviationForName(text).empty() ||
162 !state_names::GetNameForAbbreviation(text).empty();
163 }
164
IsPossiblePhoneNumber(const base::string16 & text,const std::string & country_code)165 bool IsPossiblePhoneNumber(const base::string16& text,
166 const std::string& country_code) {
167 return i18n::IsPossiblePhoneNumber(base::UTF16ToUTF8(text), country_code);
168 }
169
IsValidZip(const base::string16 & text)170 bool IsValidZip(const base::string16& text) {
171 const base::string16 kZipPattern = base::ASCIIToUTF16("^\\d{5}(-\\d{4})?$");
172 return MatchesPattern(text, kZipPattern);
173 }
174
IsSSN(const base::string16 & text)175 bool IsSSN(const base::string16& text) {
176 base::string16 number_string;
177 base::RemoveChars(text, base::ASCIIToUTF16("- "), &number_string);
178
179 // A SSN is of the form AAA-GG-SSSS (A = area number, G = group number, S =
180 // serial number). The validation we do here is simply checking if the area,
181 // group, and serial numbers are valid.
182 //
183 // Historically, the area number was assigned per state, with the group number
184 // ascending in an alternating even/odd sequence. With that scheme it was
185 // possible to check for validity by referencing a table that had the highest
186 // group number assigned for a given area number. (This was something that
187 // Chromium never did though, because the "high group" values were constantly
188 // changing.)
189 //
190 // However, starting on 25 June 2011 the SSA began issuing SSNs randomly from
191 // all areas and groups. Group numbers and serial numbers of zero remain
192 // invalid, and areas 000, 666, and 900-999 remain invalid.
193 //
194 // References for current practices:
195 // http://www.socialsecurity.gov/employer/randomization.html
196 // http://www.socialsecurity.gov/employer/randomizationfaqs.html
197 //
198 // References for historic practices:
199 // http://www.socialsecurity.gov/history/ssn/geocard.html
200 // http://www.socialsecurity.gov/employer/stateweb.htm
201 // http://www.socialsecurity.gov/employer/ssnvhighgroup.htm
202
203 if (number_string.length() != 9 || !base::IsStringASCII(number_string))
204 return false;
205
206 int area;
207 if (!base::StringToInt(
208 base::StringPiece16(number_string.begin(), number_string.begin() + 3),
209 &area)) {
210 return false;
211 }
212 if (area < 1 || area == 666 || area >= 900) {
213 return false;
214 }
215
216 int group;
217 if (!base::StringToInt(base::StringPiece16(number_string.begin() + 3,
218 number_string.begin() + 5),
219 &group) ||
220 group == 0) {
221 return false;
222 }
223
224 int serial;
225 if (!base::StringToInt(base::StringPiece16(number_string.begin() + 5,
226 number_string.begin() + 9),
227 &serial) ||
228 serial == 0) {
229 return false;
230 }
231
232 return true;
233 }
234
IsValidForType(const base::string16 & value,ServerFieldType type,base::string16 * error_message)235 bool IsValidForType(const base::string16& value,
236 ServerFieldType type,
237 base::string16* error_message) {
238 switch (type) {
239 case CREDIT_CARD_NAME_FULL:
240 if (!value.empty())
241 return true;
242
243 if (error_message) {
244 *error_message =
245 l10n_util::GetStringUTF16(IDS_PAYMENTS_VALIDATION_INVALID_NAME);
246 }
247 break;
248
249 case CREDIT_CARD_EXP_MONTH: {
250 CreditCard temp;
251 // Expiration month was in an invalid format.
252 temp.SetExpirationMonthFromString(value, /* app_locale= */ std::string());
253 if (temp.expiration_month() == 0) {
254 if (error_message) {
255 *error_message = l10n_util::GetStringUTF16(
256 IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_MONTH);
257 }
258 break;
259 }
260 return true;
261 }
262
263 case CREDIT_CARD_EXP_2_DIGIT_YEAR:
264 case CREDIT_CARD_EXP_4_DIGIT_YEAR: {
265 CreditCard temp;
266 temp.SetExpirationYearFromString(value);
267 // Expiration year was in an invalid format.
268 if ((temp.expiration_year() == 0) ||
269 (type == CREDIT_CARD_EXP_2_DIGIT_YEAR && value.size() != 2u) ||
270 (type == CREDIT_CARD_EXP_4_DIGIT_YEAR && value.size() != 4u)) {
271 if (error_message) {
272 *error_message = l10n_util::GetStringUTF16(
273 IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_YEAR);
274 }
275 break;
276 }
277
278 base::Time::Exploded now_exploded;
279 AutofillClock::Now().LocalExplode(&now_exploded);
280 if (temp.expiration_year() >= now_exploded.year)
281 return true;
282
283 // If the year is before this year, it's expired.
284 if (error_message) {
285 *error_message = l10n_util::GetStringUTF16(
286 IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED);
287 }
288 break;
289 }
290
291 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
292 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
293 const base::string16 pattern =
294 type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
295 ? base::UTF8ToUTF16("^[0-9]{1,2}[-/|]?[0-9]{2}$")
296 : base::UTF8ToUTF16("^[0-9]{1,2}[-/|]?[0-9]{4}$");
297
298 CreditCard temp;
299 temp.SetExpirationDateFromString(value);
300
301 // Expiration date was in an invalid format.
302 if (temp.expiration_month() == 0 || temp.expiration_year() == 0 ||
303 !MatchesPattern(value, pattern)) {
304 if (error_message) {
305 *error_message = l10n_util::GetStringUTF16(
306 IDS_PAYMENTS_CARD_EXPIRATION_INVALID_VALIDATION_MESSAGE);
307 }
308 break;
309 }
310
311 // Checking for card expiration.
312 if (IsValidCreditCardExpirationDate(temp.expiration_year(),
313 temp.expiration_month(),
314 AutofillClock::Now())) {
315 return true;
316 }
317
318 if (error_message) {
319 *error_message = l10n_util::GetStringUTF16(
320 IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED);
321 }
322 break;
323 }
324
325 case CREDIT_CARD_NUMBER:
326 NOTREACHED() << "IsValidCreditCardNumberForBasicCardNetworks should be "
327 << "used to validate credit card numbers";
328 break;
329
330 default:
331 // Other types such as CREDIT_CARD_TYPE and CREDIT_CARD_VERIFICATION_CODE
332 // are not validated for now.
333 NOTREACHED() << "Attempting to validate unsupported type " << type;
334 break;
335 }
336 return false;
337 }
338
GetCvcLengthForCardNetwork(const base::StringPiece card_network)339 size_t GetCvcLengthForCardNetwork(const base::StringPiece card_network) {
340 if (card_network == kAmericanExpressCard)
341 return AMEX_CVC_LENGTH;
342
343 return GENERAL_CVC_LENGTH;
344 }
345
IsUPIVirtualPaymentAddress(const base::string16 & value)346 bool IsUPIVirtualPaymentAddress(const base::string16& value) {
347 return MatchesPattern(value, base::ASCIIToUTF16(kUPIVirtualPaymentAddressRe));
348 }
349
IsInternationalBankAccountNumber(const base::string16 & value)350 bool IsInternationalBankAccountNumber(const base::string16& value) {
351 base::string16 no_spaces;
352 base::RemoveChars(value, base::ASCIIToUTF16(" "), &no_spaces);
353 return MatchesPattern(no_spaces,
354 base::ASCIIToUTF16(kInternationalBankAccountNumberRe));
355 }
356
IsPlausibleCreditCardCVCNumber(const base::string16 & value)357 bool IsPlausibleCreditCardCVCNumber(const base::string16& value) {
358 return MatchesPattern(value, base::ASCIIToUTF16(kCreditCardCVCPattern));
359 }
360
IsPlausible4DigitExpirationYear(const base::string16 & value)361 bool IsPlausible4DigitExpirationYear(const base::string16& value) {
362 return MatchesPattern(value,
363 base::ASCIIToUTF16(kCreditCard4DigitExpYearPattern));
364 }
365 } // namespace autofill
366