| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "chrome/browser/autofill/autofill_ie_toolbar_import_win.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <map> | |
| 9 #include <string> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/basictypes.h" | |
| 13 #include "base/compiler_specific.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/string16.h" | |
| 16 #include "base/win/registry.h" | |
| 17 #include "chrome/browser/autofill/autofill_country.h" | |
| 18 #include "chrome/browser/autofill/autofill_profile.h" | |
| 19 #include "chrome/browser/autofill/credit_card.h" | |
| 20 #include "chrome/browser/autofill/crypto/rc4_decryptor.h" | |
| 21 #include "chrome/browser/autofill/field_types.h" | |
| 22 #include "chrome/browser/autofill/form_group.h" | |
| 23 #include "chrome/browser/autofill/personal_data_manager.h" | |
| 24 #include "chrome/browser/autofill/personal_data_manager_observer.h" | |
| 25 #include "chrome/browser/autofill/phone_number.h" | |
| 26 #include "chrome/browser/autofill/phone_number_i18n.h" | |
| 27 #include "sync/util/data_encryption_win.h" | |
| 28 | |
| 29 using base::win::RegKey; | |
| 30 | |
| 31 // Forward declaration. This function is not in unnamed namespace as it | |
| 32 // is referenced in the unittest. | |
| 33 bool ImportCurrentUserProfiles(std::vector<AutofillProfile>* profiles, | |
| 34 std::vector<CreditCard>* credit_cards); | |
| 35 namespace { | |
| 36 | |
| 37 const wchar_t* const kProfileKey = | |
| 38 L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles"; | |
| 39 const wchar_t* const kCreditCardKey = | |
| 40 L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards"; | |
| 41 const wchar_t* const kPasswordHashValue = L"password_hash"; | |
| 42 const wchar_t* const kSaltValue = L"salt"; | |
| 43 | |
| 44 // This is RC4 decryption for Toolbar credit card data. This is necessary | |
| 45 // because it is not standard, so Crypto API cannot be used. | |
| 46 std::wstring DecryptCCNumber(const std::wstring& data) { | |
| 47 const wchar_t* kEmptyKey = | |
| 48 L"\x3605\xCEE5\xCE49\x44F7\xCF4E\xF6CC\x604B\xFCBE\xC70A\x08FD"; | |
| 49 const size_t kMacLen = 10; | |
| 50 | |
| 51 if (data.length() <= kMacLen) | |
| 52 return std::wstring(); | |
| 53 | |
| 54 RC4Decryptor rc4_algorithm(kEmptyKey); | |
| 55 return rc4_algorithm.Run(data.substr(kMacLen)); | |
| 56 } | |
| 57 | |
| 58 bool IsEmptySalt(std::wstring const& salt) { | |
| 59 // Empty salt in IE Toolbar is \x1\x2...\x14 | |
| 60 if (salt.length() != 20) | |
| 61 return false; | |
| 62 for (size_t i = 0; i < salt.length(); ++i) { | |
| 63 if (salt[i] != i + 1) | |
| 64 return false; | |
| 65 } | |
| 66 return true; | |
| 67 } | |
| 68 | |
| 69 string16 ReadAndDecryptValue(const RegKey& key, const wchar_t* value_name) { | |
| 70 DWORD data_type = REG_BINARY; | |
| 71 DWORD data_size = 0; | |
| 72 LONG result = key.ReadValue(value_name, NULL, &data_size, &data_type); | |
| 73 if ((result != ERROR_SUCCESS) || !data_size || data_type != REG_BINARY) | |
| 74 return string16(); | |
| 75 std::vector<uint8> data; | |
| 76 data.resize(data_size); | |
| 77 result = key.ReadValue(value_name, &(data[0]), &data_size, &data_type); | |
| 78 if (result == ERROR_SUCCESS) { | |
| 79 std::string out_data; | |
| 80 if (syncer::DecryptData(data, &out_data)) { | |
| 81 // The actual data is in UTF16 already. | |
| 82 if (!(out_data.size() & 1) && (out_data.size() > 2) && | |
| 83 !out_data[out_data.size() - 1] && !out_data[out_data.size() - 2]) { | |
| 84 return string16( | |
| 85 reinterpret_cast<const wchar_t *>(out_data.c_str())); | |
| 86 } | |
| 87 } | |
| 88 } | |
| 89 return string16(); | |
| 90 } | |
| 91 | |
| 92 struct { | |
| 93 AutofillFieldType field_type; | |
| 94 const wchar_t *reg_value_name; | |
| 95 } profile_reg_values[] = { | |
| 96 { NAME_FIRST, L"name_first" }, | |
| 97 { NAME_MIDDLE, L"name_middle" }, | |
| 98 { NAME_LAST, L"name_last" }, | |
| 99 { NAME_SUFFIX, L"name_suffix" }, | |
| 100 { EMAIL_ADDRESS, L"email" }, | |
| 101 { COMPANY_NAME, L"company_name" }, | |
| 102 { PHONE_HOME_NUMBER, L"phone_home_number" }, | |
| 103 { PHONE_HOME_CITY_CODE, L"phone_home_city_code" }, | |
| 104 { PHONE_HOME_COUNTRY_CODE, L"phone_home_country_code" }, | |
| 105 { ADDRESS_HOME_LINE1, L"address_home_line1" }, | |
| 106 { ADDRESS_HOME_LINE2, L"address_home_line2" }, | |
| 107 { ADDRESS_HOME_CITY, L"address_home_city" }, | |
| 108 { ADDRESS_HOME_STATE, L"address_home_state" }, | |
| 109 { ADDRESS_HOME_ZIP, L"address_home_zip" }, | |
| 110 { ADDRESS_HOME_COUNTRY, L"address_home_country" }, | |
| 111 { ADDRESS_BILLING_LINE1, L"address_billing_line1" }, | |
| 112 { ADDRESS_BILLING_LINE2, L"address_billing_line2" }, | |
| 113 { ADDRESS_BILLING_CITY, L"address_billing_city" }, | |
| 114 { ADDRESS_BILLING_STATE, L"address_billing_state" }, | |
| 115 { ADDRESS_BILLING_ZIP, L"address_billing_zip" }, | |
| 116 { ADDRESS_BILLING_COUNTRY, L"address_billing_country" }, | |
| 117 { CREDIT_CARD_NAME, L"credit_card_name" }, | |
| 118 { CREDIT_CARD_NUMBER, L"credit_card_number" }, | |
| 119 { CREDIT_CARD_EXP_MONTH, L"credit_card_exp_month" }, | |
| 120 { CREDIT_CARD_EXP_4_DIGIT_YEAR, L"credit_card_exp_4_digit_year" }, | |
| 121 { CREDIT_CARD_TYPE, L"credit_card_type" }, | |
| 122 // We do not import verification code. | |
| 123 }; | |
| 124 | |
| 125 typedef std::map<std::wstring, AutofillFieldType> RegToFieldMap; | |
| 126 | |
| 127 // Imports address or credit card data from the given registry |key| into the | |
| 128 // given |form_group|, with the help of |reg_to_field|. When importing address | |
| 129 // data, writes the phone data into |phone|; otherwise, |phone| should be null. | |
| 130 // Returns true if any fields were set, false otherwise. | |
| 131 bool ImportSingleFormGroup(const RegKey& key, | |
| 132 const RegToFieldMap& reg_to_field, | |
| 133 FormGroup* form_group, | |
| 134 PhoneNumber::PhoneCombineHelper* phone) { | |
| 135 if (!key.Valid()) | |
| 136 return false; | |
| 137 | |
| 138 bool has_non_empty_fields = false; | |
| 139 | |
| 140 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
| 141 for (uint32 i = 0; i < key.GetValueCount(); ++i) { | |
| 142 std::wstring value_name; | |
| 143 if (key.GetValueNameAt(i, &value_name) != ERROR_SUCCESS) | |
| 144 continue; | |
| 145 | |
| 146 RegToFieldMap::const_iterator it = reg_to_field.find(value_name); | |
| 147 if (it == reg_to_field.end()) | |
| 148 continue; // This field is not imported. | |
| 149 | |
| 150 string16 field_value = ReadAndDecryptValue(key, value_name.c_str()); | |
| 151 if (!field_value.empty()) { | |
| 152 if (it->second == CREDIT_CARD_NUMBER) | |
| 153 field_value = DecryptCCNumber(field_value); | |
| 154 | |
| 155 // Phone numbers are stored piece-by-piece, and then reconstructed from | |
| 156 // the pieces. The rest of the fields are set "as is". | |
| 157 if (!phone || !phone->SetInfo(it->second, field_value)) { | |
| 158 has_non_empty_fields = true; | |
| 159 form_group->SetInfo(it->second, field_value, app_locale); | |
| 160 } | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 return has_non_empty_fields; | |
| 165 } | |
| 166 | |
| 167 // Imports address data from the given registry |key| into the given |profile|, | |
| 168 // with the help of |reg_to_field|. Returns true if any fields were set, false | |
| 169 // otherwise. | |
| 170 bool ImportSingleProfile(const RegKey& key, | |
| 171 const RegToFieldMap& reg_to_field, | |
| 172 AutofillProfile* profile) { | |
| 173 PhoneNumber::PhoneCombineHelper phone; | |
| 174 bool has_non_empty_fields = | |
| 175 ImportSingleFormGroup(key, reg_to_field, profile, &phone); | |
| 176 | |
| 177 // Now re-construct the phones if needed. | |
| 178 string16 constructed_number; | |
| 179 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
| 180 if (phone.ParseNumber(*profile, app_locale, &constructed_number)) { | |
| 181 has_non_empty_fields = true; | |
| 182 profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, constructed_number); | |
| 183 } | |
| 184 | |
| 185 return has_non_empty_fields; | |
| 186 } | |
| 187 | |
| 188 // Imports profiles from the IE toolbar and stores them. Asynchronous | |
| 189 // if PersonalDataManager has not been loaded yet. Deletes itself on completion. | |
| 190 class AutofillImporter : public PersonalDataManagerObserver { | |
| 191 public: | |
| 192 explicit AutofillImporter(PersonalDataManager* personal_data_manager) | |
| 193 : personal_data_manager_(personal_data_manager) { | |
| 194 personal_data_manager_->AddObserver(this); | |
| 195 } | |
| 196 | |
| 197 bool ImportProfiles() { | |
| 198 if (!ImportCurrentUserProfiles(&profiles_, &credit_cards_)) { | |
| 199 delete this; | |
| 200 return false; | |
| 201 } | |
| 202 if (personal_data_manager_->IsDataLoaded()) | |
| 203 OnPersonalDataChanged(); | |
| 204 return true; | |
| 205 } | |
| 206 | |
| 207 // PersonalDataManagerObserver: | |
| 208 virtual void OnPersonalDataChanged() OVERRIDE { | |
| 209 for (std::vector<AutofillProfile>::const_iterator iter = profiles_.begin(); | |
| 210 iter != profiles_.end(); ++iter) { | |
| 211 personal_data_manager_->AddProfile(*iter); | |
| 212 } | |
| 213 for (std::vector<CreditCard>::const_iterator iter = credit_cards_.begin(); | |
| 214 iter != credit_cards_.end(); ++iter) { | |
| 215 personal_data_manager_->AddCreditCard(*iter); | |
| 216 } | |
| 217 delete this; | |
| 218 } | |
| 219 | |
| 220 private: | |
| 221 ~AutofillImporter() { | |
| 222 personal_data_manager_->RemoveObserver(this); | |
| 223 } | |
| 224 | |
| 225 PersonalDataManager* personal_data_manager_; | |
| 226 std::vector<AutofillProfile> profiles_; | |
| 227 std::vector<CreditCard> credit_cards_; | |
| 228 }; | |
| 229 | |
| 230 } // namespace | |
| 231 | |
| 232 // Imports Autofill profiles and credit cards from IE Toolbar if present and not | |
| 233 // password protected. Returns true if data is successfully retrieved. False if | |
| 234 // there is no data, data is password protected or error occurred. | |
| 235 bool ImportCurrentUserProfiles(std::vector<AutofillProfile>* profiles, | |
| 236 std::vector<CreditCard>* credit_cards) { | |
| 237 DCHECK(profiles); | |
| 238 DCHECK(credit_cards); | |
| 239 | |
| 240 // Create a map of possible fields for a quick access. | |
| 241 RegToFieldMap reg_to_field; | |
| 242 for (size_t i = 0; i < arraysize(profile_reg_values); ++i) { | |
| 243 reg_to_field[std::wstring(profile_reg_values[i].reg_value_name)] = | |
| 244 profile_reg_values[i].field_type; | |
| 245 } | |
| 246 | |
| 247 base::win::RegistryKeyIterator iterator_profiles(HKEY_CURRENT_USER, | |
| 248 kProfileKey); | |
| 249 for (; iterator_profiles.Valid(); ++iterator_profiles) { | |
| 250 std::wstring key_name(kProfileKey); | |
| 251 key_name.append(L"\\"); | |
| 252 key_name.append(iterator_profiles.Name()); | |
| 253 RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ); | |
| 254 AutofillProfile profile; | |
| 255 if (ImportSingleProfile(key, reg_to_field, &profile)) { | |
| 256 // Combine phones into whole phone #. | |
| 257 profiles->push_back(profile); | |
| 258 } | |
| 259 } | |
| 260 string16 password_hash; | |
| 261 string16 salt; | |
| 262 RegKey cc_key(HKEY_CURRENT_USER, kCreditCardKey, KEY_READ); | |
| 263 if (cc_key.Valid()) { | |
| 264 password_hash = ReadAndDecryptValue(cc_key, kPasswordHashValue); | |
| 265 salt = ReadAndDecryptValue(cc_key, kSaltValue); | |
| 266 } | |
| 267 | |
| 268 // We import CC profiles only if they are not password protected. | |
| 269 if (password_hash.empty() && IsEmptySalt(salt)) { | |
| 270 base::win::RegistryKeyIterator iterator_cc(HKEY_CURRENT_USER, | |
| 271 kCreditCardKey); | |
| 272 for (; iterator_cc.Valid(); ++iterator_cc) { | |
| 273 std::wstring key_name(kCreditCardKey); | |
| 274 key_name.append(L"\\"); | |
| 275 key_name.append(iterator_cc.Name()); | |
| 276 RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ); | |
| 277 CreditCard credit_card; | |
| 278 if (ImportSingleFormGroup(key, reg_to_field, &credit_card, NULL)) { | |
| 279 string16 cc_number = credit_card.GetRawInfo(CREDIT_CARD_NUMBER); | |
| 280 if (!cc_number.empty()) | |
| 281 credit_cards->push_back(credit_card); | |
| 282 } | |
| 283 } | |
| 284 } | |
| 285 return (profiles->size() + credit_cards->size()) > 0; | |
| 286 } | |
| 287 | |
| 288 bool ImportAutofillDataWin(PersonalDataManager* pdm) { | |
| 289 // In incognito mode we do not have PDM - and we should not import anything. | |
| 290 if (!pdm) | |
| 291 return false; | |
| 292 AutofillImporter *importer = new AutofillImporter(pdm); | |
| 293 // importer will self delete. | |
| 294 return importer->ImportProfiles(); | |
| 295 } | |
| OLD | NEW |