OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "testing/gtest/include/gtest/gtest.h" | 5 #include "testing/gtest/include/gtest/gtest.h" |
6 | 6 |
7 // The order of these includes is important. | |
8 #include <windows.h> | 7 #include <windows.h> |
9 #include <unknwn.h> | |
10 #include <intshcut.h> | |
11 #include <shlguid.h> | |
12 #include <urlhist.h> | |
13 #include <shlobj.h> | |
14 #include <propvarutil.h> | |
15 | 8 |
16 #include <algorithm> | |
17 #include <vector> | 9 #include <vector> |
18 | 10 |
19 #include "base/bind.h" | 11 #include "base/string16.h" |
20 #include "base/compiler_specific.h" | |
21 #include "base/file_util.h" | |
22 #include "base/message_loop.h" | |
23 #include "base/path_service.h" | |
24 #include "base/stl_util.h" | |
25 #include "base/string_util.h" | |
26 #include "base/utf_string_conversions.h" | |
27 #include "base/win/registry.h" | |
28 #include "base/win/scoped_com_initializer.h" | |
29 #include "base/win/scoped_comptr.h" | |
30 #include "base/win/scoped_propvariant.h" | |
31 #include "base/win/windows_version.h" | |
32 #include "chrome/browser/history/history_types.h" | |
33 #include "chrome/browser/importer/ie_importer.h" | |
34 #include "chrome/browser/importer/importer_bridge.h" | |
35 #include "chrome/browser/importer/importer_data_types.h" | |
36 #include "chrome/browser/importer/importer_host.h" | |
37 #include "chrome/browser/importer/importer_progress_observer.h" | |
38 #include "chrome/browser/importer/importer_unittest_utils.h" | |
39 #include "chrome/browser/importer/pstore_declarations.h" | |
40 #include "chrome/browser/search_engines/template_url.h" | |
41 #include "chrome/common/chrome_paths.h" | |
42 #include "chrome/test/base/testing_profile.h" | |
43 #include "components/webdata/encryptor/ie7_password.h" | 12 #include "components/webdata/encryptor/ie7_password.h" |
44 #include "content/public/common/password_form.h" | |
45 | 13 |
46 namespace { | 14 TEST(IEImporterTest, IE7Importer) { |
47 | |
48 const char16 kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests"; | |
49 const char16 kUnitTestUserOverrideSubKey[] = | |
50 L"SOFTWARE\\Chromium Unit Tests\\HKCU Override"; | |
51 | |
52 const BookmarkInfo kIEBookmarks[] = { | |
53 {true, 2, {L"Links", L"SubFolderOfLinks"}, | |
54 L"SubLink", | |
55 "http://www.links-sublink.com/"}, | |
56 {true, 1, {L"Links"}, | |
57 L"TheLink", | |
58 "http://www.links-thelink.com/"}, | |
59 {false, 0, {}, | |
60 L"Google Home Page", | |
61 "http://www.google.com/"}, | |
62 {false, 0, {}, | |
63 L"TheLink", | |
64 "http://www.links-thelink.com/"}, | |
65 {false, 1, {L"SubFolder"}, | |
66 L"Title", | |
67 "http://www.link.com/"}, | |
68 {false, 0, {}, | |
69 L"WithPortAndQuery", | |
70 "http://host:8080/cgi?q=query"}, | |
71 {false, 1, {L"a"}, | |
72 L"\x4E2D\x6587", | |
73 "http://chinese-title-favorite/"}, | |
74 {false, 0, {}, | |
75 L"SubFolder", | |
76 "http://www.subfolder.com/"}, | |
77 }; | |
78 | |
79 const BookmarkInfo kIESortedBookmarks[] = { | |
80 {false, 0, {}, L"a", "http://www.google.com/0"}, | |
81 {false, 1, {L"b"}, L"a", "http://www.google.com/1"}, | |
82 {false, 1, {L"b"}, L"b", "http://www.google.com/2"}, | |
83 {false, 0, {}, L"c", "http://www.google.com/3"}, | |
84 }; | |
85 | |
86 const char16 kIEIdentifyUrl[] = | |
87 L"http://A79029D6-753E-4e27-B807-3D46AB1545DF.com:8080/path?key=value"; | |
88 const char16 kIEIdentifyTitle[] = | |
89 L"Unittest GUID"; | |
90 | |
91 const char16 kIEFavoritesOrderKey[] = | |
92 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\" | |
93 L"MenuOrder\\Favorites"; | |
94 | |
95 const char16 kFaviconStreamSuffix[] = L"url:favicon:$DATA"; | |
96 const char kDummyFaviconImageData[] = | |
97 "\x42\x4D" // Magic signature 'BM' | |
98 "\x1E\x00\x00\x00" // File size | |
99 "\x00\x00\x00\x00" // Reserved | |
100 "\x1A\x00\x00\x00" // Offset of the pixel data | |
101 "\x0C\x00\x00\x00" // Header Size | |
102 "\x01\x00\x01\x00" // Size: 1x1 | |
103 "\x01\x00" // Reserved | |
104 "\x18\x00" // 24-bits | |
105 "\x00\xFF\x00\x00"; // The pixel | |
106 | |
107 struct FaviconGroup { | |
108 const char16* favicon_url; | |
109 const char16* site_url[2]; | |
110 }; | |
111 | |
112 const FaviconGroup kIEFaviconGroup[2] = { | |
113 {L"http://www.google.com/favicon.ico", | |
114 {L"http://www.google.com/", | |
115 L"http://www.subfolder.com/"}}, | |
116 {L"http://example.com/favicon.ico", | |
117 {L"http://host:8080/cgi?q=query", | |
118 L"http://chinese-title-favorite/"}}, | |
119 }; | |
120 | |
121 bool CreateOrderBlob(const base::FilePath& favorites_folder, | |
122 const string16& path, | |
123 const std::vector<string16>& entries) { | |
124 if (entries.size() > 255) | |
125 return false; | |
126 | |
127 // Create a binary sequence for setting a specific order of favorites. | |
128 // The format depends on the version of Shell32.dll, so we cannot embed | |
129 // a binary constant here. | |
130 std::vector<uint8> blob(20, 0); | |
131 blob[16] = static_cast<uint8>(entries.size()); | |
132 | |
133 for (size_t i = 0; i < entries.size(); ++i) { | |
134 PIDLIST_ABSOLUTE id_list_full = ILCreateFromPath( | |
135 favorites_folder.Append(path).Append(entries[i]).value().c_str()); | |
136 PUITEMID_CHILD id_list = ILFindLastID(id_list_full); | |
137 // Include the trailing zero-length item id. Don't include the single | |
138 // element array. | |
139 size_t id_list_size = id_list->mkid.cb + sizeof(id_list->mkid.cb); | |
140 | |
141 blob.resize(blob.size() + 8); | |
142 uint32 total_size = id_list_size + 8; | |
143 memcpy(&blob[blob.size() - 8], &total_size, 4); | |
144 uint32 sort_index = i; | |
145 memcpy(&blob[blob.size() - 4], &sort_index, 4); | |
146 blob.resize(blob.size() + id_list_size); | |
147 memcpy(&blob[blob.size() - id_list_size], id_list, id_list_size); | |
148 ILFree(id_list_full); | |
149 } | |
150 | |
151 string16 key_path = kIEFavoritesOrderKey; | |
152 if (!path.empty()) | |
153 key_path += L"\\" + path; | |
154 base::win::RegKey key; | |
155 if (key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE) != | |
156 ERROR_SUCCESS) { | |
157 return false; | |
158 } | |
159 if (key.WriteValue(L"Order", &blob[0], blob.size(), REG_BINARY) != | |
160 ERROR_SUCCESS) { | |
161 return false; | |
162 } | |
163 return true; | |
164 } | |
165 | |
166 bool CreateUrlFileWithFavicon(const base::FilePath& file, | |
167 const std::wstring& url, | |
168 const std::wstring& favicon_url) { | |
169 base::win::ScopedComPtr<IUniformResourceLocator> locator; | |
170 HRESULT result = locator.CreateInstance(CLSID_InternetShortcut, NULL, | |
171 CLSCTX_INPROC_SERVER); | |
172 if (FAILED(result)) | |
173 return false; | |
174 base::win::ScopedComPtr<IPersistFile> persist_file; | |
175 result = persist_file.QueryFrom(locator); | |
176 if (FAILED(result)) | |
177 return false; | |
178 result = locator->SetURL(url.c_str(), 0); | |
179 if (FAILED(result)) | |
180 return false; | |
181 | |
182 // Write favicon url if specified. | |
183 if (!favicon_url.empty()) { | |
184 base::win::ScopedComPtr<IPropertySetStorage> property_set_storage; | |
185 if (FAILED(property_set_storage.QueryFrom(locator))) | |
186 return false; | |
187 base::win::ScopedComPtr<IPropertyStorage> property_storage; | |
188 if (FAILED(property_set_storage->Open(FMTID_Intshcut, | |
189 STGM_WRITE, | |
190 property_storage.Receive()))) { | |
191 return false; | |
192 } | |
193 PROPSPEC properties[] = {{PRSPEC_PROPID, PID_IS_ICONFILE}}; | |
194 // WriteMultiple takes an array of PROPVARIANTs, but since this code only | |
195 // needs an array of size 1: a pointer to |pv_icon| is equivalent. | |
196 base::win::ScopedPropVariant pv_icon; | |
197 if (FAILED(InitPropVariantFromString(favicon_url.c_str(), | |
198 pv_icon.Receive())) || | |
199 FAILED(property_storage->WriteMultiple(1, properties, &pv_icon, 0))) { | |
200 return false; | |
201 } | |
202 } | |
203 | |
204 // Save the .url file. | |
205 result = persist_file->Save(file.value().c_str(), TRUE); | |
206 if (FAILED(result)) | |
207 return false; | |
208 | |
209 // Write dummy favicon image data in NTFS alternate data stream. | |
210 return favicon_url.empty() || (file_util::WriteFile( | |
211 file.ReplaceExtension(kFaviconStreamSuffix), kDummyFaviconImageData, | |
212 sizeof kDummyFaviconImageData) != -1); | |
213 } | |
214 | |
215 bool CreateUrlFile(const base::FilePath& file, const std::wstring& url) { | |
216 return CreateUrlFileWithFavicon(file, url, std::wstring()); | |
217 } | |
218 | |
219 void ClearPStoreType(IPStore* pstore, const GUID* type, const GUID* subtype) { | |
220 base::win::ScopedComPtr<IEnumPStoreItems, NULL> item; | |
221 HRESULT result = pstore->EnumItems(0, type, subtype, 0, item.Receive()); | |
222 if (result == PST_E_OK) { | |
223 char16* item_name; | |
224 while (SUCCEEDED(item->Next(1, &item_name, 0))) { | |
225 pstore->DeleteItem(0, type, subtype, item_name, NULL, 0); | |
226 CoTaskMemFree(item_name); | |
227 } | |
228 } | |
229 pstore->DeleteSubtype(0, type, subtype, 0); | |
230 pstore->DeleteType(0, type, 0); | |
231 } | |
232 | |
233 void WritePStore(IPStore* pstore, const GUID* type, const GUID* subtype) { | |
234 struct PStoreItem { | |
235 char16* name; | |
236 int data_size; | |
237 char* data; | |
238 } items[] = { | |
239 {L"http://localhost:8080/security/index.htm#ref:StringData", 8, | |
240 "\x31\x00\x00\x00\x32\x00\x00\x00"}, | |
241 {L"http://localhost:8080/security/index.htm#ref:StringIndex", 20, | |
242 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00" | |
243 "\x00\x00\x2f\x00\x74\x00\x01\x00\x00\x00"}, | |
244 {L"user:StringData", 4, | |
245 "\x31\x00\x00\x00"}, | |
246 {L"user:StringIndex", 20, | |
247 "\x57\x49\x43\x4b\x18\x00\x00\x00\x01\x00" | |
248 "\x00\x00\x2f\x00\x74\x00\x00\x00\x00\x00"}, | |
249 }; | |
250 | |
251 for (int i = 0; i < arraysize(items); ++i) { | |
252 HRESULT res = pstore->WriteItem(0, type, subtype, items[i].name, | |
253 items[i].data_size, reinterpret_cast<BYTE*>(items[i].data), | |
254 NULL, 0, 0); | |
255 ASSERT_TRUE(res == PST_E_OK); | |
256 } | |
257 } | |
258 | |
259 class TestObserver : public ProfileWriter, | |
260 public importer::ImporterProgressObserver { | |
261 public: | |
262 TestObserver() : ProfileWriter(NULL) { | |
263 bookmark_count_ = 0; | |
264 history_count_ = 0; | |
265 password_count_ = 0; | |
266 favicon_count_ = 0; | |
267 } | |
268 | |
269 // importer::ImporterProgressObserver: | |
270 virtual void ImportStarted() OVERRIDE {} | |
271 virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {} | |
272 virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {} | |
273 virtual void ImportEnded() OVERRIDE { | |
274 MessageLoop::current()->Quit(); | |
275 EXPECT_EQ(arraysize(kIEBookmarks), bookmark_count_); | |
276 EXPECT_EQ(1, history_count_); | |
277 EXPECT_EQ(arraysize(kIEFaviconGroup), favicon_count_); | |
278 } | |
279 | |
280 virtual bool BookmarkModelIsLoaded() const { | |
281 // Profile is ready for writing. | |
282 return true; | |
283 } | |
284 | |
285 virtual bool TemplateURLServiceIsLoaded() const { | |
286 return true; | |
287 } | |
288 | |
289 virtual void AddPasswordForm(const content::PasswordForm& form) { | |
290 // Importer should obtain this password form only. | |
291 EXPECT_EQ(GURL("http://localhost:8080/security/index.htm"), form.origin); | |
292 EXPECT_EQ("http://localhost:8080/", form.signon_realm); | |
293 EXPECT_EQ(L"user", form.username_element); | |
294 EXPECT_EQ(L"1", form.username_value); | |
295 EXPECT_EQ(L"", form.password_element); | |
296 EXPECT_EQ(L"2", form.password_value); | |
297 EXPECT_EQ("", form.action.spec()); | |
298 ++password_count_; | |
299 } | |
300 | |
301 virtual void AddHistoryPage(const history::URLRows& page, | |
302 history::VisitSource visit_source) { | |
303 // Importer should read the specified URL. | |
304 for (size_t i = 0; i < page.size(); ++i) { | |
305 if (page[i].title() == kIEIdentifyTitle && | |
306 page[i].url() == GURL(kIEIdentifyUrl)) | |
307 ++history_count_; | |
308 } | |
309 EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_source); | |
310 } | |
311 | |
312 virtual void AddBookmarks(const std::vector<BookmarkEntry>& bookmarks, | |
313 const string16& top_level_folder_name) OVERRIDE { | |
314 ASSERT_LE(bookmark_count_ + bookmarks.size(), arraysize(kIEBookmarks)); | |
315 // Importer should import the IE Favorites folder the same as the list, | |
316 // in the same order. | |
317 for (size_t i = 0; i < bookmarks.size(); ++i) { | |
318 EXPECT_TRUE(EqualBookmarkEntry(bookmarks[i], | |
319 kIEBookmarks[bookmark_count_])); | |
320 ++bookmark_count_; | |
321 } | |
322 } | |
323 | |
324 virtual void AddKeyword(std::vector<TemplateURL*> template_url, | |
325 int default_keyword_index) { | |
326 // TODO(jcampan): bug 1169230: we should test keyword importing for IE. | |
327 // In order to do that we'll probably need to mock the Windows registry. | |
328 NOTREACHED(); | |
329 STLDeleteContainerPointers(template_url.begin(), template_url.end()); | |
330 } | |
331 | |
332 virtual void AddFavicons( | |
333 const std::vector<history::ImportedFaviconUsage>& usage) OVERRIDE { | |
334 // Importer should group the favicon information for each favicon URL. | |
335 for (size_t i = 0; i < arraysize(kIEFaviconGroup); ++i) { | |
336 GURL favicon_url(kIEFaviconGroup[i].favicon_url); | |
337 std::set<GURL> urls; | |
338 for (size_t j = 0; j < arraysize(kIEFaviconGroup[i].site_url); ++j) | |
339 urls.insert(GURL(kIEFaviconGroup[i].site_url[j])); | |
340 | |
341 SCOPED_TRACE(testing::Message() << "Expected Favicon: " << favicon_url); | |
342 | |
343 bool expected_favicon_url_found = false; | |
344 for (size_t j = 0; j < usage.size(); ++j) { | |
345 if (usage[j].favicon_url == favicon_url) { | |
346 EXPECT_EQ(urls, usage[j].urls); | |
347 expected_favicon_url_found = true; | |
348 break; | |
349 } | |
350 } | |
351 EXPECT_TRUE(expected_favicon_url_found); | |
352 } | |
353 | |
354 favicon_count_ += usage.size(); | |
355 } | |
356 | |
357 private: | |
358 ~TestObserver() {} | |
359 | |
360 size_t bookmark_count_; | |
361 size_t history_count_; | |
362 size_t password_count_; | |
363 size_t favicon_count_; | |
364 }; | |
365 | |
366 class MalformedFavoritesRegistryTestObserver | |
367 : public ProfileWriter, | |
368 public importer::ImporterProgressObserver { | |
369 public: | |
370 MalformedFavoritesRegistryTestObserver() : ProfileWriter(NULL) { | |
371 bookmark_count_ = 0; | |
372 } | |
373 | |
374 // importer::ImporterProgressObserver: | |
375 virtual void ImportStarted() OVERRIDE {} | |
376 virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {} | |
377 virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {} | |
378 virtual void ImportEnded() OVERRIDE { | |
379 MessageLoop::current()->Quit(); | |
380 EXPECT_EQ(arraysize(kIESortedBookmarks), bookmark_count_); | |
381 } | |
382 | |
383 virtual bool BookmarkModelIsLoaded() const { return true; } | |
384 virtual bool TemplateURLServiceIsLoaded() const { return true; } | |
385 | |
386 virtual void AddPasswordForm(const content::PasswordForm& form) {} | |
387 virtual void AddHistoryPage(const history::URLRows& page, | |
388 history::VisitSource visit_source) {} | |
389 virtual void AddKeyword(std::vector<TemplateURL*> template_url, | |
390 int default_keyword_index) {} | |
391 virtual void AddBookmarks(const std::vector<BookmarkEntry>& bookmarks, | |
392 const string16& top_level_folder_name) OVERRIDE { | |
393 ASSERT_LE(bookmark_count_ + bookmarks.size(), | |
394 arraysize(kIESortedBookmarks)); | |
395 for (size_t i = 0; i < bookmarks.size(); ++i) { | |
396 EXPECT_TRUE(EqualBookmarkEntry(bookmarks[i], | |
397 kIESortedBookmarks[bookmark_count_])); | |
398 ++bookmark_count_; | |
399 } | |
400 } | |
401 | |
402 private: | |
403 ~MalformedFavoritesRegistryTestObserver() {} | |
404 | |
405 size_t bookmark_count_; | |
406 }; | |
407 | |
408 } // namespace | |
409 | |
410 class IEImporterTest : public ImporterTest { | |
411 protected: | |
412 virtual void SetUp() OVERRIDE { | |
413 ImporterTest::SetUp(); | |
414 StartRegistryOverride(); | |
415 } | |
416 | |
417 virtual void TearDown() OVERRIDE { | |
418 EndRegistryOverride(); | |
419 } | |
420 | |
421 void StartRegistryOverride() { | |
422 EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, NULL)); | |
423 temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER, | |
424 kUnitTestUserOverrideSubKey, | |
425 KEY_ALL_ACCESS); | |
426 EXPECT_TRUE(temp_hkcu_hive_key_.Valid()); | |
427 EXPECT_EQ(ERROR_SUCCESS, | |
428 RegOverridePredefKey(HKEY_CURRENT_USER, | |
429 temp_hkcu_hive_key_.Handle())); | |
430 } | |
431 | |
432 void EndRegistryOverride() { | |
433 EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, NULL)); | |
434 temp_hkcu_hive_key_.Close(); | |
435 base::win::RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, | |
436 KEY_ALL_ACCESS); | |
437 key.DeleteKey(L""); | |
438 } | |
439 | |
440 base::win::RegKey temp_hkcu_hive_key_; | |
441 }; | |
442 | |
443 TEST_F(IEImporterTest, IEImporter) { | |
444 // Sets up a favorites folder. | |
445 base::win::ScopedCOMInitializer com_init; | |
446 base::FilePath path = temp_dir_.path().AppendASCII("Favorites"); | |
447 CreateDirectory(path.value().c_str(), NULL); | |
448 CreateDirectory(path.AppendASCII("SubFolder").value().c_str(), NULL); | |
449 base::FilePath links_path = path.AppendASCII("Links"); | |
450 CreateDirectory(links_path.value().c_str(), NULL); | |
451 CreateDirectory(links_path.AppendASCII("SubFolderOfLinks").value().c_str(), | |
452 NULL); | |
453 CreateDirectory(path.AppendASCII("\x0061").value().c_str(), NULL); | |
454 ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("Google Home Page.url"), | |
455 L"http://www.google.com/", | |
456 L"http://www.google.com/favicon.ico")); | |
457 ASSERT_TRUE(CreateUrlFile(path.AppendASCII("SubFolder\\Title.url"), | |
458 L"http://www.link.com/")); | |
459 ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("SubFolder.url"), | |
460 L"http://www.subfolder.com/", | |
461 L"http://www.google.com/favicon.ico")); | |
462 ASSERT_TRUE(CreateUrlFile(path.AppendASCII("TheLink.url"), | |
463 L"http://www.links-thelink.com/")); | |
464 ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("WithPortAndQuery.url"), | |
465 L"http://host:8080/cgi?q=query", | |
466 L"http://example.com/favicon.ico")); | |
467 ASSERT_TRUE(CreateUrlFileWithFavicon( | |
468 path.AppendASCII("\x0061").Append(L"\x4E2D\x6587.url"), | |
469 L"http://chinese-title-favorite/", | |
470 L"http://example.com/favicon.ico")); | |
471 ASSERT_TRUE(CreateUrlFile(links_path.AppendASCII("TheLink.url"), | |
472 L"http://www.links-thelink.com/")); | |
473 ASSERT_TRUE(CreateUrlFile( | |
474 links_path.AppendASCII("SubFolderOfLinks").AppendASCII("SubLink.url"), | |
475 L"http://www.links-sublink.com/")); | |
476 ASSERT_TRUE(CreateUrlFile(path.AppendASCII("IEDefaultLink.url"), | |
477 L"http://go.microsoft.com/fwlink/?linkid=140813")); | |
478 file_util::WriteFile(path.AppendASCII("InvalidUrlFile.url"), "x", 1); | |
479 file_util::WriteFile(path.AppendASCII("PlainTextFile.txt"), "x", 1); | |
480 | |
481 const char16* root_links[] = { | |
482 L"Links", | |
483 L"Google Home Page.url", | |
484 L"TheLink.url", | |
485 L"SubFolder", | |
486 L"WithPortAndQuery.url", | |
487 L"a", | |
488 L"SubFolder.url", | |
489 }; | |
490 ASSERT_TRUE(CreateOrderBlob( | |
491 base::FilePath(path), L"", | |
492 std::vector<string16>(root_links, root_links + arraysize(root_links)))); | |
493 | |
494 HRESULT res; | |
495 | |
496 // Sets up a special history link. | |
497 base::win::ScopedComPtr<IUrlHistoryStg2> url_history_stg2; | |
498 res = url_history_stg2.CreateInstance(CLSID_CUrlHistory, NULL, | |
499 CLSCTX_INPROC_SERVER); | |
500 ASSERT_TRUE(res == S_OK); | |
501 res = url_history_stg2->AddUrl(kIEIdentifyUrl, kIEIdentifyTitle, 0); | |
502 ASSERT_TRUE(res == S_OK); | |
503 | |
504 // Starts to import the above settings. | |
505 MessageLoop* loop = MessageLoop::current(); | |
506 scoped_refptr<ImporterHost> host(new ImporterHost); | |
507 | |
508 TestObserver* observer = new TestObserver(); | |
509 host->SetObserver(observer); | |
510 importer::SourceProfile source_profile; | |
511 source_profile.importer_type = importer::TYPE_IE; | |
512 source_profile.source_path = temp_dir_.path(); | |
513 | |
514 // IUrlHistoryStg2::AddUrl seems to reset the override. Ensure it here. | |
515 StartRegistryOverride(); | |
516 | |
517 loop->PostTask(FROM_HERE, base::Bind( | |
518 &ImporterHost::StartImportSettings, | |
519 host.get(), | |
520 source_profile, | |
521 profile_.get(), | |
522 importer::HISTORY | importer::PASSWORDS | importer::FAVORITES, | |
523 observer)); | |
524 loop->Run(); | |
525 | |
526 // Cleans up. | |
527 url_history_stg2->DeleteUrl(kIEIdentifyUrl, 0); | |
528 url_history_stg2.Release(); | |
529 } | |
530 | |
531 TEST_F(IEImporterTest, IEImporterMalformedFavoritesRegistry) { | |
532 // Sets up a favorites folder. | |
533 base::win::ScopedCOMInitializer com_init; | |
534 base::FilePath path = temp_dir_.path().AppendASCII("Favorites"); | |
535 CreateDirectory(path.value().c_str(), NULL); | |
536 CreateDirectory(path.AppendASCII("b").value().c_str(), NULL); | |
537 ASSERT_TRUE(CreateUrlFile(path.AppendASCII("a.url"), | |
538 L"http://www.google.com/0")); | |
539 ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("a.url"), | |
540 L"http://www.google.com/1")); | |
541 ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("b.url"), | |
542 L"http://www.google.com/2")); | |
543 ASSERT_TRUE(CreateUrlFile(path.AppendASCII("c.url"), | |
544 L"http://www.google.com/3")); | |
545 | |
546 struct BadBinaryData { | |
547 const char* data; | |
548 int length; | |
549 }; | |
550 static const BadBinaryData kBadBinary[] = { | |
551 // number_of_items field is truncated | |
552 {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | |
553 "\x00\xff\xff\xff", 17}, | |
554 // number_of_items = 0xffff, but the byte sequence is too short. | |
555 {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | |
556 "\xff\xff\x00\x00", 20}, | |
557 // number_of_items = 1, size_of_item is too big. | |
558 {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | |
559 "\x01\x00\x00\x00" | |
560 "\xff\xff\x00\x00\x00\x00\x00\x00" | |
561 "\x00\x00\x00\x00", 32}, | |
562 // number_of_items = 1, size_of_item = 16, size_of_shid is too big. | |
563 {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | |
564 "\x01\x00\x00\x00" | |
565 "\x10\x00\x00\x00\x00\x00\x00\x00" | |
566 "\xff\x7f\x00\x00" "\x00\x00\x00\x00", 36}, | |
567 // number_of_items = 1, size_of_item = 16, size_of_shid is too big. | |
568 {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | |
569 "\x01\x00\x00\x00" | |
570 "\x10\x00\x00\x00\x00\x00\x00\x00" | |
571 "\x06\x00\x00\x00" "\x00\x00\x00\x00", 36}, | |
572 }; | |
573 | |
574 // Verify malformed registry data are safely ignored and alphabetical | |
575 // sort is performed. | |
576 for (size_t i = 0; i < arraysize(kBadBinary); ++i) { | |
577 base::win::RegKey key; | |
578 ASSERT_EQ(ERROR_SUCCESS, | |
579 key.Create(HKEY_CURRENT_USER, kIEFavoritesOrderKey, KEY_WRITE)); | |
580 ASSERT_EQ(ERROR_SUCCESS, | |
581 key.WriteValue(L"Order", kBadBinary[i].data, kBadBinary[i].length, | |
582 REG_BINARY)); | |
583 | |
584 // Starts to import the above settings. | |
585 MessageLoop* loop = MessageLoop::current(); | |
586 scoped_refptr<ImporterHost> host(new ImporterHost); | |
587 | |
588 MalformedFavoritesRegistryTestObserver* observer = | |
589 new MalformedFavoritesRegistryTestObserver(); | |
590 host->SetObserver(observer); | |
591 importer::SourceProfile source_profile; | |
592 source_profile.importer_type = importer::TYPE_IE; | |
593 source_profile.source_path = temp_dir_.path(); | |
594 | |
595 loop->PostTask(FROM_HERE, base::Bind( | |
596 &ImporterHost::StartImportSettings, | |
597 host.get(), | |
598 source_profile, | |
599 profile_.get(), | |
600 importer::FAVORITES, | |
601 observer)); | |
602 loop->Run(); | |
603 } | |
604 } | |
605 | |
606 TEST_F(IEImporterTest, IE7Importer) { | |
607 // This is the unencrypted values of my keys under Storage2. | 15 // This is the unencrypted values of my keys under Storage2. |
608 // The passwords have been manually changed to abcdef... but the size remains | 16 // The passwords have been manually changed to abcdef... but the size remains |
609 // the same. | 17 // the same. |
610 unsigned char data1[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00" | 18 unsigned char data1[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00" |
611 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00" | 19 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00" |
612 "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00" | 20 "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00" |
613 "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01" | 21 "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01" |
614 "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76" | 22 "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76" |
615 "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00" | 23 "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00" |
616 "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00" | 24 "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00" |
(...skipping 26 matching lines...) Expand all Loading... |
643 ASSERT_TRUE(ie7_password::GetUserPassFromData(decrypted_data1, &username, | 51 ASSERT_TRUE(ie7_password::GetUserPassFromData(decrypted_data1, &username, |
644 &password)); | 52 &password)); |
645 EXPECT_EQ(L"abcdefgh", username); | 53 EXPECT_EQ(L"abcdefgh", username); |
646 EXPECT_EQ(L"abcdefghijkl", password); | 54 EXPECT_EQ(L"abcdefghijkl", password); |
647 | 55 |
648 ASSERT_TRUE(ie7_password::GetUserPassFromData(decrypted_data2, &username, | 56 ASSERT_TRUE(ie7_password::GetUserPassFromData(decrypted_data2, &username, |
649 &password)); | 57 &password)); |
650 EXPECT_EQ(L"abcdefghi", username); | 58 EXPECT_EQ(L"abcdefghi", username); |
651 EXPECT_EQ(L"abcdefg", password); | 59 EXPECT_EQ(L"abcdefg", password); |
652 } | 60 } |
OLD | NEW |