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 "base/strings/string_number_conversions.h" 8 #include "base/strings/string_piece.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "base/time/time.h" 12 #include "components/autofill/core/browser/autofill_regexes.h" 13 #include "components/autofill/core/browser/credit_card.h" 14 #include "components/autofill/core/browser/state_names.h" 15 16 17 namespace autofill { 18 19 bool IsValidCreditCardExpirationDate(const base::string16& year, 20 const base::string16& month, 21 const base::Time& now) { 22 base::string16 year_cleaned, month_cleaned; 23 base::TrimWhitespace(year, base::TRIM_ALL, &year_cleaned); 24 base::TrimWhitespace(month, base::TRIM_ALL, &month_cleaned); 25 if (year_cleaned.length() != 4) 26 return false; 27 28 int cc_year; 29 if (!base::StringToInt(year_cleaned, &cc_year)) 30 return false; 31 32 int cc_month; 33 if (!base::StringToInt(month_cleaned, &cc_month)) 34 return false; 35 36 return IsValidCreditCardExpirationDate(cc_year, cc_month, now); 37 } 38 39 bool IsValidCreditCardExpirationDate(int year, 40 int month, 41 const base::Time& now) { 42 base::Time::Exploded now_exploded; 43 now.LocalExplode(&now_exploded); 44 45 if (year < now_exploded.year) 46 return false; 47 48 if (year == now_exploded.year && month < now_exploded.month) 49 return false; 50 51 return true; 52 } 53 54 bool IsValidCreditCardNumber(const base::string16& text) { 55 base::string16 number = CreditCard::StripSeparators(text); 56 57 // Credit card numbers are at most 19 digits in length [1]. 12 digits seems to 58 // be a fairly safe lower-bound [2]. Specific card issuers have more rigidly 59 // defined sizes. 60 // [1] http://www.merriampark.com/anatomycc.htm 61 // [2] http://en.wikipedia.org/wiki/Bank_card_number 62 const char* const type = CreditCard::GetCreditCardType(text); 63 if (type == kAmericanExpressCard && number.size() != 15) 64 return false; 65 if (type == kDinersCard && number.size() != 14) 66 return false; 67 if (type == kDiscoverCard && number.size() != 16) 68 return false; 69 if (type == kJCBCard && number.size() != 16) 70 return false; 71 if (type == kMasterCard && number.size() != 16) 72 return false; 73 if (type == kUnionPay && (number.size() < 16 || number.size() > 19)) 74 return false; 75 if (type == kVisaCard && number.size() != 13 && number.size() != 16) 76 return false; 77 if (type == kGenericCard && (number.size() < 12 || number.size() > 19)) 78 return false; 79 80 // Unlike all the other supported types, UnionPay cards lack Luhn checksum 81 // validation. 82 if (type == kUnionPay) 83 return true; 84 85 // Use the Luhn formula [3] to validate the number. 86 // [3] http://en.wikipedia.org/wiki/Luhn_algorithm 87 int sum = 0; 88 bool odd = false; 89 for (base::string16::reverse_iterator iter = number.rbegin(); 90 iter != number.rend(); 91 ++iter) { 92 if (!IsAsciiDigit(*iter)) 93 return false; 94 95 int digit = *iter - '0'; 96 if (odd) { 97 digit *= 2; 98 sum += digit / 10 + digit % 10; 99 } else { 100 sum += digit; 101 } 102 odd = !odd; 103 } 104 105 return (sum % 10) == 0; 106 } 107 108 bool IsValidCreditCardSecurityCode(const base::string16& text) { 109 if (text.size() < 3U || text.size() > 4U) 110 return false; 111 112 for (base::string16::const_iterator iter = text.begin(); 113 iter != text.end(); 114 ++iter) { 115 if (!IsAsciiDigit(*iter)) 116 return false; 117 } 118 return true; 119 } 120 121 bool IsValidCreditCardSecurityCode(const base::string16& code, 122 const base::string16& number) { 123 const char* const type = CreditCard::GetCreditCardType(number); 124 size_t required_length = 3; 125 if (type == kAmericanExpressCard) 126 required_length = 4; 127 128 return code.length() == required_length; 129 } 130 131 bool IsValidEmailAddress(const base::string16& text) { 132 // E-Mail pattern as defined by the WhatWG. (4.10.7.1.5 E-Mail state) 133 const base::string16 kEmailPattern = base::ASCIIToUTF16( 134 "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@" 135 "[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$"); 136 return MatchesPattern(text, kEmailPattern); 137 } 138 139 bool IsValidState(const base::string16& text) { 140 return !state_names::GetAbbreviationForName(text).empty() || 141 !state_names::GetNameForAbbreviation(text).empty(); 142 } 143 144 bool IsValidZip(const base::string16& text) { 145 const base::string16 kZipPattern = base::ASCIIToUTF16("^\\d{5}(-\\d{4})?$"); 146 return MatchesPattern(text, kZipPattern); 147 } 148 149 bool IsSSN(const base::string16& text) { 150 base::string16 number_string; 151 base::RemoveChars(text, base::ASCIIToUTF16("- "), &number_string); 152 153 // A SSN is of the form AAA-GG-SSSS (A = area number, G = group number, S = 154 // serial number). The validation we do here is simply checking if the area, 155 // group, and serial numbers are valid. 156 // 157 // Historically, the area number was assigned per state, with the group number 158 // ascending in an alternating even/odd sequence. With that scheme it was 159 // possible to check for validity by referencing a table that had the highest 160 // group number assigned for a given area number. (This was something that 161 // Chromium never did though, because the "high group" values were constantly 162 // changing.) 163 // 164 // However, starting on 25 June 2011 the SSA began issuing SSNs randomly from 165 // all areas and groups. Group numbers and serial numbers of zero remain 166 // invalid, and areas 000, 666, and 900-999 remain invalid. 167 // 168 // References for current practices: 169 // http://www.socialsecurity.gov/employer/randomization.html 170 // http://www.socialsecurity.gov/employer/randomizationfaqs.html 171 // 172 // References for historic practices: 173 // http://www.socialsecurity.gov/history/ssn/geocard.html 174 // http://www.socialsecurity.gov/employer/stateweb.htm 175 // http://www.socialsecurity.gov/employer/ssnvhighgroup.htm 176 177 if (number_string.length() != 9 || !base::IsStringASCII(number_string)) 178 return false; 179 180 int area; 181 if (!base::StringToInt(base::StringPiece16(number_string.begin(), 182 number_string.begin() + 3), 183 &area)) { 184 return false; 185 } 186 if (area < 1 || 187 area == 666 || 188 area >= 900) { 189 return false; 190 } 191 192 int group; 193 if (!base::StringToInt(base::StringPiece16(number_string.begin() + 3, 194 number_string.begin() + 5), 195 &group) 196 || group == 0) { 197 return false; 198 } 199 200 int serial; 201 if (!base::StringToInt(base::StringPiece16(number_string.begin() + 5, 202 number_string.begin() + 9), 203 &serial) 204 || serial == 0) { 205 return false; 206 } 207 208 return true; 209 } 210 211 } // namespace autofill 212