Home | History | Annotate | Download | only in wallet
      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/content/browser/wallet/full_wallet.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/values.h"
     11 #include "components/autofill/core/browser/autofill_type.h"
     12 #include "components/autofill/core/browser/credit_card.h"
     13 
     14 namespace {
     15 
     16 const size_t kPanSize = 16;
     17 const size_t kBinSize = 6;
     18 const size_t kCvnSize = 3;
     19 const size_t kEncryptedRestSize = 12;
     20 
     21 }  // anonymous namespace
     22 
     23 namespace autofill {
     24 namespace wallet {
     25 
     26 FullWallet::FullWallet(int expiration_month,
     27                        int expiration_year,
     28                        const std::string& iin,
     29                        const std::string& encrypted_rest,
     30                        scoped_ptr<Address> billing_address,
     31                        scoped_ptr<Address> shipping_address,
     32                        const std::vector<RequiredAction>& required_actions)
     33     : expiration_month_(expiration_month),
     34       expiration_year_(expiration_year),
     35       iin_(iin),
     36       encrypted_rest_(encrypted_rest),
     37       billing_address_(billing_address.Pass()),
     38       shipping_address_(shipping_address.Pass()),
     39       required_actions_(required_actions) {
     40   DCHECK(required_actions_.size() > 0 || billing_address_.get());
     41 }
     42 
     43 FullWallet::~FullWallet() {}
     44 
     45 // static
     46 scoped_ptr<FullWallet>
     47     FullWallet::CreateFullWallet(const DictionaryValue& dictionary) {
     48   const ListValue* required_actions_list;
     49   std::vector<RequiredAction> required_actions;
     50   if (dictionary.GetList("required_action", &required_actions_list)) {
     51     for (size_t i = 0; i < required_actions_list->GetSize(); ++i) {
     52       std::string action_string;
     53       if (required_actions_list->GetString(i, &action_string)) {
     54         RequiredAction action = ParseRequiredActionFromString(action_string);
     55         if (!ActionAppliesToFullWallet(action)) {
     56           DLOG(ERROR) << "Response from Google wallet with bad required action:"
     57                          " \"" << action_string << "\"";
     58           return scoped_ptr<FullWallet>();
     59         }
     60         required_actions.push_back(action);
     61       }
     62     }
     63     if (required_actions.size() > 0) {
     64       return scoped_ptr<FullWallet>(new FullWallet(-1,
     65                                                    -1,
     66                                                    std::string(),
     67                                                    std::string(),
     68                                                    scoped_ptr<Address>(),
     69                                                    scoped_ptr<Address>(),
     70                                                    required_actions));
     71     }
     72   } else {
     73     DVLOG(1) << "Response from Google wallet missing required actions";
     74   }
     75 
     76   int expiration_month;
     77   if (!dictionary.GetInteger("expiration_month", &expiration_month)) {
     78     DLOG(ERROR) << "Response from Google wallet missing expiration month";
     79     return scoped_ptr<FullWallet>();
     80   }
     81 
     82   int expiration_year;
     83   if (!dictionary.GetInteger("expiration_year", &expiration_year)) {
     84     DLOG(ERROR) << "Response from Google wallet missing expiration year";
     85     return scoped_ptr<FullWallet>();
     86   }
     87 
     88   std::string iin;
     89   if (!dictionary.GetString("iin", &iin)) {
     90     DLOG(ERROR) << "Response from Google wallet missing iin";
     91     return scoped_ptr<FullWallet>();
     92   }
     93 
     94   std::string encrypted_rest;
     95   if (!dictionary.GetString("rest", &encrypted_rest)) {
     96     DLOG(ERROR) << "Response from Google wallet missing rest";
     97     return scoped_ptr<FullWallet>();
     98   }
     99 
    100   const DictionaryValue* billing_address_dict;
    101   if (!dictionary.GetDictionary("billing_address", &billing_address_dict)) {
    102     DLOG(ERROR) << "Response from Google wallet missing billing address";
    103     return scoped_ptr<FullWallet>();
    104   }
    105 
    106   scoped_ptr<Address> billing_address =
    107       Address::CreateAddress(*billing_address_dict);
    108   if (!billing_address.get()) {
    109     DLOG(ERROR) << "Response from Google wallet has malformed billing address";
    110     return scoped_ptr<FullWallet>();
    111   }
    112 
    113   const DictionaryValue* shipping_address_dict;
    114   scoped_ptr<Address> shipping_address;
    115   if (dictionary.GetDictionary("shipping_address", &shipping_address_dict)) {
    116     shipping_address =
    117         Address::CreateAddressWithID(*shipping_address_dict);
    118   } else {
    119     DVLOG(1) << "Response from Google wallet missing shipping address";
    120   }
    121 
    122   return scoped_ptr<FullWallet>(new FullWallet(expiration_month,
    123                                                expiration_year,
    124                                                iin,
    125                                                encrypted_rest,
    126                                                billing_address.Pass(),
    127                                                shipping_address.Pass(),
    128                                                required_actions));
    129 }
    130 
    131 // static
    132 scoped_ptr<FullWallet>
    133     FullWallet::CreateFullWalletFromClearText(
    134         int expiration_month,
    135         int expiration_year,
    136         const std::string& pan,
    137         const std::string& cvn,
    138         scoped_ptr<Address> billing_address,
    139         scoped_ptr<Address> shipping_address) {
    140   DCHECK(billing_address);
    141   DCHECK(!pan.empty());
    142   DCHECK(!cvn.empty());
    143 
    144   scoped_ptr<FullWallet> wallet(new FullWallet(
    145       expiration_month,
    146       expiration_year,
    147       std::string(),  // no iin -- clear text pan/cvn are set below.
    148       std::string(),  // no encrypted_rest -- clear text pan/cvn are set below.
    149       billing_address.Pass(),
    150       shipping_address.Pass(),
    151       std::vector<RequiredAction>()));  // no required actions in clear text.
    152   wallet->pan_ = pan;
    153   wallet->cvn_ = cvn;
    154   return wallet.Pass();
    155 }
    156 
    157 base::string16 FullWallet::GetInfo(const AutofillType& type) {
    158   switch (type.GetStorableType()) {
    159     case CREDIT_CARD_NUMBER:
    160       return UTF8ToUTF16(GetPan());
    161 
    162     case CREDIT_CARD_NAME:
    163       return billing_address()->recipient_name();
    164 
    165     case CREDIT_CARD_VERIFICATION_CODE:
    166       return UTF8ToUTF16(GetCvn());
    167 
    168     case CREDIT_CARD_EXP_MONTH:
    169       if (expiration_month() == 0)
    170         return base::string16();
    171       return base::IntToString16(expiration_month());
    172 
    173     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
    174       if (expiration_year() == 0)
    175         return base::string16();
    176       return base::IntToString16(expiration_year());
    177 
    178     case CREDIT_CARD_EXP_2_DIGIT_YEAR:
    179       if (expiration_year() == 0)
    180         return base::string16();
    181       return base::IntToString16(expiration_year() % 100);
    182 
    183     case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
    184       if (expiration_month() == 0 || expiration_year() == 0)
    185             return base::string16();
    186       return base::IntToString16(expiration_month()) + ASCIIToUTF16("/") +
    187              base::IntToString16(expiration_year() % 100);
    188 
    189     case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
    190       if (expiration_month() == 0 || expiration_year() == 0)
    191             return base::string16();
    192       return base::IntToString16(expiration_month()) + ASCIIToUTF16("/") +
    193              base::IntToString16(expiration_year());
    194 
    195     case CREDIT_CARD_TYPE: {
    196       std::string internal_type =
    197           CreditCard::GetCreditCardType(UTF8ToUTF16(GetPan()));
    198       if (internal_type == kGenericCard)
    199         return base::string16();
    200       return CreditCard::TypeForDisplay(internal_type);
    201     }
    202 
    203     default:
    204       NOTREACHED();
    205   }
    206 
    207   return base::string16();
    208 }
    209 
    210 bool FullWallet::HasRequiredAction(RequiredAction action) const {
    211   DCHECK(ActionAppliesToFullWallet(action));
    212   return std::find(required_actions_.begin(),
    213                    required_actions_.end(),
    214                    action) != required_actions_.end();
    215 }
    216 
    217 base::string16 FullWallet::TypeAndLastFourDigits() {
    218   CreditCard card;
    219   card.SetRawInfo(CREDIT_CARD_NUMBER,
    220                   GetInfo(AutofillType(CREDIT_CARD_NUMBER)));
    221   return card.TypeAndLastFourDigits();
    222 }
    223 
    224 bool FullWallet::operator==(const FullWallet& other) const {
    225   if (expiration_month_ != other.expiration_month_)
    226     return false;
    227 
    228   if (expiration_year_ != other.expiration_year_)
    229     return false;
    230 
    231   if (iin_ != other.iin_)
    232     return false;
    233 
    234   if (encrypted_rest_ != other.encrypted_rest_)
    235     return false;
    236 
    237   if (billing_address_.get() && other.billing_address_.get()) {
    238     if (*billing_address_.get() != *other.billing_address_.get())
    239       return false;
    240   } else if (billing_address_.get() || other.billing_address_.get()) {
    241     return false;
    242   }
    243 
    244   if (shipping_address_.get() && other.shipping_address_.get()) {
    245     if (*shipping_address_.get() != *other.shipping_address_.get())
    246       return false;
    247   } else if (shipping_address_.get() || other.shipping_address_.get()) {
    248     return false;
    249   }
    250 
    251   if (required_actions_ != other.required_actions_)
    252     return false;
    253 
    254   return true;
    255 }
    256 
    257 bool FullWallet::operator!=(const FullWallet& other) const {
    258   return !(*this == other);
    259 }
    260 
    261 void FullWallet::DecryptCardInfo() {
    262   // |encrypted_rest_| must be of length |kEncryptedRestSize| in order for
    263   // decryption to succeed and the server will not pad it with zeros.
    264   while (encrypted_rest_.size() < kEncryptedRestSize) {
    265     encrypted_rest_ = '0' + encrypted_rest_;
    266   }
    267 
    268   DCHECK_EQ(kEncryptedRestSize, encrypted_rest_.size());
    269 
    270   std::vector<uint8> operating_data;
    271   // Convert |encrypted_rest_| to bytes so we can decrypt it with |otp|.
    272   if (!base::HexStringToBytes(encrypted_rest_, &operating_data)) {
    273     DLOG(ERROR) << "Failed to parse encrypted rest";
    274     return;
    275   }
    276 
    277   // Ensure |one_time_pad_| and |encrypted_rest_| are of the same length
    278   // otherwise something has gone wrong and we can't decrypt the data.
    279   DCHECK_EQ(one_time_pad_.size(), operating_data.size());
    280 
    281   std::vector<uint8> results;
    282   // XOR |otp| with the encrypted data to decrypt.
    283   for (size_t i = 0; i < one_time_pad_.size(); ++i)
    284     results.push_back(one_time_pad_[i] ^ operating_data[i]);
    285 
    286   // There is no uint8* to int64 so convert the decrypted data to hex and then
    287   // parse the hex to an int64 before getting the int64 as a string.
    288   std::string hex_decrypted = base::HexEncode(&(results[0]), results.size());
    289 
    290   int64 decrypted;
    291   if (!base::HexStringToInt64(hex_decrypted, &decrypted)) {
    292     DLOG(ERROR) << "Failed to parse decrypted data in hex to int64";
    293     return;
    294   }
    295   std::string card_info = base::Int64ToString(decrypted);
    296 
    297   size_t padded_length = kPanSize - kBinSize + kCvnSize;
    298   // |card_info| is PAN without the IIN concatenated with the CVN, i.e.
    299   // PANPANPANPCVN. If what was decrypted is not of that size the front needs
    300   // to be padded with 0's until it is.
    301   if (card_info.size() != padded_length)
    302     card_info.insert(card_info.begin(), padded_length - card_info.size(), '0');
    303 
    304   // Separate out the PAN from the CVN.
    305   size_t split = kPanSize - kBinSize;
    306   cvn_ = card_info.substr(split);
    307   pan_ = iin_ + card_info.substr(0, split);
    308 }
    309 
    310 const std::string& FullWallet::GetPan() {
    311   if (pan_.empty())
    312     DecryptCardInfo();
    313   return pan_;
    314 }
    315 
    316 const std::string& FullWallet::GetCvn() {
    317   if (cvn_.empty())
    318     DecryptCardInfo();
    319   return cvn_;
    320 }
    321 
    322 }  // namespace wallet
    323 }  // namespace autofill
    324