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