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