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
14namespace {
15
16const size_t kPanSize = 16;
17const size_t kBinSize = 6;
18const size_t kCvnSize = 3;
19const size_t kEncryptedRestSize = 12;
20
21}  // anonymous namespace
22
23namespace autofill {
24namespace wallet {
25
26FullWallet::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
43FullWallet::~FullWallet() {}
44
45// static
46scoped_ptr<FullWallet>
47    FullWallet::CreateFullWallet(const base::DictionaryValue& dictionary) {
48  const base::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 base::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 base::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
132scoped_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
157base::string16 FullWallet::GetInfo(const std::string& app_locale,
158                                   const AutofillType& type) {
159  switch (type.GetStorableType()) {
160    case CREDIT_CARD_NUMBER:
161      return base::ASCIIToUTF16(GetPan());
162
163    case CREDIT_CARD_NAME:
164      return billing_address()->recipient_name();
165
166    case CREDIT_CARD_VERIFICATION_CODE:
167      return base::ASCIIToUTF16(GetCvn());
168
169    case CREDIT_CARD_EXP_MONTH:
170      if (expiration_month() == 0)
171        return base::string16();
172      return base::IntToString16(expiration_month());
173
174    case CREDIT_CARD_EXP_4_DIGIT_YEAR:
175      if (expiration_year() == 0)
176        return base::string16();
177      return base::IntToString16(expiration_year());
178
179    case CREDIT_CARD_EXP_2_DIGIT_YEAR:
180      if (expiration_year() == 0)
181        return base::string16();
182      return base::IntToString16(expiration_year() % 100);
183
184    case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
185      if (expiration_month() == 0 || expiration_year() == 0)
186        return base::string16();
187      return base::IntToString16(expiration_month()) + base::ASCIIToUTF16("/") +
188             base::IntToString16(expiration_year() % 100);
189
190    case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
191      if (expiration_month() == 0 || expiration_year() == 0)
192            return base::string16();
193      return base::IntToString16(expiration_month()) + base::ASCIIToUTF16("/") +
194             base::IntToString16(expiration_year());
195
196    case CREDIT_CARD_TYPE: {
197      const char* const internal_type =
198          CreditCard::GetCreditCardType(base::ASCIIToUTF16(GetPan()));
199      if (internal_type == kGenericCard)
200        return base::string16();
201      return CreditCard::TypeForDisplay(internal_type);
202    }
203
204    default: {
205      switch (type.group()) {
206        case NAME_BILLING:
207        case PHONE_BILLING:
208        case ADDRESS_BILLING:
209          return billing_address_->GetInfo(type, app_locale);
210
211        case CREDIT_CARD:
212          NOTREACHED();
213
214        default:
215          return shipping_address_->GetInfo(type, app_locale);
216      }
217    }
218  }
219}
220
221bool FullWallet::HasRequiredAction(RequiredAction action) const {
222  DCHECK(ActionAppliesToFullWallet(action));
223  return std::find(required_actions_.begin(),
224                   required_actions_.end(),
225                   action) != required_actions_.end();
226}
227
228base::string16 FullWallet::TypeAndLastFourDigits() {
229  CreditCard card;
230  card.SetRawInfo(CREDIT_CARD_NUMBER, base::ASCIIToUTF16(GetPan()));
231  return card.TypeAndLastFourDigits();
232}
233
234const std::string& FullWallet::GetPan() {
235  if (pan_.empty())
236    DecryptCardInfo();
237  return pan_;
238}
239
240bool FullWallet::operator==(const FullWallet& other) const {
241  if (expiration_month_ != other.expiration_month_)
242    return false;
243
244  if (expiration_year_ != other.expiration_year_)
245    return false;
246
247  if (iin_ != other.iin_)
248    return false;
249
250  if (encrypted_rest_ != other.encrypted_rest_)
251    return false;
252
253  if (billing_address_.get() && other.billing_address_.get()) {
254    if (*billing_address_.get() != *other.billing_address_.get())
255      return false;
256  } else if (billing_address_.get() || other.billing_address_.get()) {
257    return false;
258  }
259
260  if (shipping_address_.get() && other.shipping_address_.get()) {
261    if (*shipping_address_.get() != *other.shipping_address_.get())
262      return false;
263  } else if (shipping_address_.get() || other.shipping_address_.get()) {
264    return false;
265  }
266
267  if (required_actions_ != other.required_actions_)
268    return false;
269
270  return true;
271}
272
273bool FullWallet::operator!=(const FullWallet& other) const {
274  return !(*this == other);
275}
276
277void FullWallet::DecryptCardInfo() {
278  // |encrypted_rest_| must be of length |kEncryptedRestSize| in order for
279  // decryption to succeed and the server will not pad it with zeros.
280  while (encrypted_rest_.size() < kEncryptedRestSize) {
281    encrypted_rest_ = '0' + encrypted_rest_;
282  }
283
284  DCHECK_EQ(kEncryptedRestSize, encrypted_rest_.size());
285
286  std::vector<uint8> operating_data;
287  // Convert |encrypted_rest_| to bytes so we can decrypt it with |otp|.
288  if (!base::HexStringToBytes(encrypted_rest_, &operating_data)) {
289    DLOG(ERROR) << "Failed to parse encrypted rest";
290    return;
291  }
292
293  // Ensure |one_time_pad_| and |encrypted_rest_| are of the same length
294  // otherwise something has gone wrong and we can't decrypt the data.
295  DCHECK_EQ(one_time_pad_.size(), operating_data.size());
296
297  std::vector<uint8> results;
298  // XOR |otp| with the encrypted data to decrypt.
299  for (size_t i = 0; i < one_time_pad_.size(); ++i)
300    results.push_back(one_time_pad_[i] ^ operating_data[i]);
301
302  // There is no uint8* to int64 so convert the decrypted data to hex and then
303  // parse the hex to an int64 before getting the int64 as a string.
304  std::string hex_decrypted = base::HexEncode(&(results[0]), results.size());
305
306  int64 decrypted;
307  if (!base::HexStringToInt64(hex_decrypted, &decrypted)) {
308    DLOG(ERROR) << "Failed to parse decrypted data in hex to int64";
309    return;
310  }
311  std::string card_info = base::Int64ToString(decrypted);
312
313  size_t padded_length = kPanSize - kBinSize + kCvnSize;
314  // |card_info| is PAN without the IIN concatenated with the CVN, i.e.
315  // PANPANPANPCVN. If what was decrypted is not of that size the front needs
316  // to be padded with 0's until it is.
317  if (card_info.size() != padded_length)
318    card_info.insert(card_info.begin(), padded_length - card_info.size(), '0');
319
320  // Separate out the PAN from the CVN.
321  size_t split = kPanSize - kBinSize;
322  cvn_ = card_info.substr(split);
323  pan_ = iin_ + card_info.substr(0, split);
324}
325
326const std::string& FullWallet::GetCvn() {
327  if (cvn_.empty())
328    DecryptCardInfo();
329  return cvn_;
330}
331
332}  // namespace wallet
333}  // namespace autofill
334