| 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 |