| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/memory/weak_ptr.h" | 17 #include "base/memory/weak_ptr.h" |
| 18 #include "base/metrics/field_trial.h" | 18 #include "base/metrics/field_trial.h" |
| 19 #include "base/test/mock_entropy_provider.h" | 19 #include "base/test/mock_entropy_provider.h" |
| 20 #include "base/test/scoped_feature_list.h" | 20 #include "base/test/scoped_feature_list.h" |
| 21 #include "chrome/browser/chrome_notification_types.h" | 21 #include "chrome/browser/chrome_notification_types.h" |
| 22 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" | 22 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" |
| 23 #include "chrome/browser/extensions/chrome_test_extension_loader.h" |
| 23 #include "chrome/browser/extensions/component_loader.h" | 24 #include "chrome/browser/extensions/component_loader.h" |
| 24 #include "chrome/browser/extensions/extension_service.h" | 25 #include "chrome/browser/extensions/extension_service.h" |
| 25 #include "chrome/browser/extensions/extension_service_test_with_install.h" | 26 #include "chrome/browser/extensions/extension_service_test_with_install.h" |
| 26 #include "chrome/browser/extensions/extension_sync_data.h" | 27 #include "chrome/browser/extensions/extension_sync_data.h" |
| 27 #include "chrome/browser/extensions/extension_sync_service.h" | 28 #include "chrome/browser/extensions/extension_sync_service.h" |
| 28 #include "chrome/browser/extensions/extension_util.h" | 29 #include "chrome/browser/extensions/extension_util.h" |
| 29 #include "chrome/browser/extensions/scripting_permissions_modifier.h" | 30 #include "chrome/browser/extensions/scripting_permissions_modifier.h" |
| 30 #include "chrome/browser/extensions/updater/extension_updater.h" | 31 #include "chrome/browser/extensions/updater/extension_updater.h" |
| 31 #include "chrome/browser/sync/profile_sync_service_factory.h" | 32 #include "chrome/browser/sync/profile_sync_service_factory.h" |
| 32 #include "chrome/browser/themes/theme_service.h" | 33 #include "chrome/browser/themes/theme_service.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 | 88 |
| 88 const char autoupdate[] = "ogjcoiohnmldgjemafoockdghcjciccf"; | 89 const char autoupdate[] = "ogjcoiohnmldgjemafoockdghcjciccf"; |
| 89 const char good0[] = "behllobkkfkfnphdnhnkndlbkcpglgmj"; | 90 const char good0[] = "behllobkkfkfnphdnhnkndlbkcpglgmj"; |
| 90 const char good2[] = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; | 91 const char good2[] = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; |
| 91 const char good2048[] = "nmgjhmhbleinmjpbdhgajfjkbijcmgbh"; | 92 const char good2048[] = "nmgjhmhbleinmjpbdhgajfjkbijcmgbh"; |
| 92 const char good_crx[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; | 93 const char good_crx[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; |
| 93 const char page_action[] = "obcimlgaoabeegjmmpldobjndiealpln"; | 94 const char page_action[] = "obcimlgaoabeegjmmpldobjndiealpln"; |
| 94 const char permissions_increase[] = "pgdpcfcocojkjfbgpiianjngphoopgmo"; | 95 const char permissions_increase[] = "pgdpcfcocojkjfbgpiianjngphoopgmo"; |
| 95 const char theme2_crx[] = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf"; | 96 const char theme2_crx[] = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf"; |
| 96 | 97 |
| 98 ExtensionSyncData GetDisableSyncData(const Extension& extension, |
| 99 int disable_reasons) { |
| 100 bool enabled = false; |
| 101 bool incognito_enabled = false; |
| 102 bool remote_install = false; |
| 103 bool installed_by_custodian = false; |
| 104 ExtensionSyncData::OptionalBoolean has_all_urls = |
| 105 ExtensionSyncData::BOOLEAN_UNSET; |
| 106 return ExtensionSyncData(extension, enabled, disable_reasons, |
| 107 incognito_enabled, remote_install, has_all_urls, |
| 108 installed_by_custodian); |
| 109 } |
| 110 |
| 111 ExtensionSyncData GetEnableSyncData(const Extension& extension) { |
| 112 bool enabled = true; |
| 113 bool incognito_enabled = false; |
| 114 bool remote_install = false; |
| 115 bool installed_by_custodian = false; |
| 116 ExtensionSyncData::OptionalBoolean has_all_urls = |
| 117 ExtensionSyncData::BOOLEAN_UNSET; |
| 118 return ExtensionSyncData(extension, enabled, Extension::DISABLE_NONE, |
| 119 incognito_enabled, remote_install, has_all_urls, |
| 120 installed_by_custodian); |
| 121 } |
| 122 |
| 97 SyncChangeList MakeSyncChangeList(const std::string& id, | 123 SyncChangeList MakeSyncChangeList(const std::string& id, |
| 98 const sync_pb::EntitySpecifics& specifics, | 124 const sync_pb::EntitySpecifics& specifics, |
| 99 SyncChange::SyncChangeType change_type) { | 125 SyncChange::SyncChangeType change_type) { |
| 100 syncer::SyncData sync_data = | 126 syncer::SyncData sync_data = |
| 101 syncer::SyncData::CreateLocalData(id, "Name", specifics); | 127 syncer::SyncData::CreateLocalData(id, "Name", specifics); |
| 102 return SyncChangeList(1, SyncChange(FROM_HERE, change_type, sync_data)); | 128 return SyncChangeList(1, SyncChange(FROM_HERE, change_type, sync_data)); |
| 103 } | 129 } |
| 104 | 130 |
| 105 // This is a FakeSyncChangeProcessor specialization that maintains a store of | 131 // This is a FakeSyncChangeProcessor specialization that maintains a store of |
| 106 // SyncData items in the superclass' data_ member variable, treating it like a | 132 // SyncData items in the superclass' data_ member variable, treating it like a |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 // Helper to call MergeDataAndStartSyncing with no server data and dummy | 219 // Helper to call MergeDataAndStartSyncing with no server data and dummy |
| 194 // change processor / error factory. | 220 // change processor / error factory. |
| 195 void StartSyncing(syncer::ModelType type) { | 221 void StartSyncing(syncer::ModelType type) { |
| 196 ASSERT_TRUE(type == syncer::EXTENSIONS || type == syncer::APPS); | 222 ASSERT_TRUE(type == syncer::EXTENSIONS || type == syncer::APPS); |
| 197 extension_sync_service()->MergeDataAndStartSyncing( | 223 extension_sync_service()->MergeDataAndStartSyncing( |
| 198 type, syncer::SyncDataList(), | 224 type, syncer::SyncDataList(), |
| 199 base::MakeUnique<syncer::FakeSyncChangeProcessor>(), | 225 base::MakeUnique<syncer::FakeSyncChangeProcessor>(), |
| 200 base::MakeUnique<syncer::SyncErrorFactoryMock>()); | 226 base::MakeUnique<syncer::SyncErrorFactoryMock>()); |
| 201 } | 227 } |
| 202 | 228 |
| 229 void DisableExtensionFromSync(const Extension& extension, |
| 230 int disable_reasons) { |
| 231 ExtensionSyncData disable_extension = |
| 232 GetDisableSyncData(extension, Extension::DISABLE_USER_ACTION); |
| 233 SyncChangeList list( |
| 234 1, disable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| 235 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); |
| 236 } |
| 237 |
| 238 void EnableExtensionFromSync(const Extension& extension) { |
| 239 ExtensionSyncData enable_extension = GetEnableSyncData(extension); |
| 240 SyncChangeList list( |
| 241 1, enable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| 242 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); |
| 243 } |
| 244 |
| 203 protected: | 245 protected: |
| 204 // Paths to some of the fake extensions. | 246 // Paths to some of the fake extensions. |
| 205 base::FilePath good0_path() { | 247 base::FilePath good0_path() { |
| 206 return data_dir() | 248 return data_dir() |
| 207 .AppendASCII("good") | 249 .AppendASCII("good") |
| 208 .AppendASCII("Extensions") | 250 .AppendASCII("Extensions") |
| 209 .AppendASCII(good0) | 251 .AppendASCII(good0) |
| 210 .AppendASCII("1.0.0.0"); | 252 .AppendASCII("1.0.0.0"); |
| 211 } | 253 } |
| 212 | 254 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 Extension::DISABLE_USER_ACTION, false, | 375 Extension::DISABLE_USER_ACTION, false, |
| 334 false, ExtensionSyncData::BOOLEAN_UNSET, | 376 false, ExtensionSyncData::BOOLEAN_UNSET, |
| 335 false); | 377 false); |
| 336 SyncChangeList list( | 378 SyncChangeList list( |
| 337 1, disable_good_crx.GetSyncChange(SyncChange::ACTION_UPDATE)); | 379 1, disable_good_crx.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| 338 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); | 380 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); |
| 339 | 381 |
| 340 ASSERT_FALSE(service()->IsExtensionEnabled(good0)); | 382 ASSERT_FALSE(service()->IsExtensionEnabled(good0)); |
| 341 } | 383 } |
| 342 | 384 |
| 385 // Test that sync can enable and disable installed extensions. |
| 386 TEST_F(ExtensionServiceSyncTest, ReenableDisabledExtensionFromSync) { |
| 387 InitializeEmptyExtensionService(); |
| 388 |
| 389 // Enable sync. |
| 390 browser_sync::ProfileSyncService* sync_service = |
| 391 ProfileSyncServiceFactory::GetForProfile(profile()); |
| 392 sync_service->SetFirstSetupComplete(); |
| 393 |
| 394 service()->Init(); |
| 395 |
| 396 // Load up a simple extension. |
| 397 extensions::ChromeTestExtensionLoader extension_loader(profile()); |
| 398 extension_loader.set_pack_extension(true); |
| 399 scoped_refptr<const Extension> extension = extension_loader.LoadExtension( |
| 400 data_dir().AppendASCII("simple_with_file")); |
| 401 ASSERT_TRUE(extension); |
| 402 const std::string kExtensionId = extension->id(); |
| 403 ASSERT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| 404 |
| 405 syncer::FakeSyncChangeProcessor* processor_raw = nullptr; |
| 406 { |
| 407 auto processor = base::MakeUnique<syncer::FakeSyncChangeProcessor>(); |
| 408 processor_raw = processor.get(); |
| 409 extension_sync_service()->MergeDataAndStartSyncing( |
| 410 syncer::EXTENSIONS, syncer::SyncDataList(), std::move(processor), |
| 411 base::MakeUnique<syncer::SyncErrorFactoryMock>()); |
| 412 } |
| 413 processor_raw->changes().clear(); |
| 414 |
| 415 DisableExtensionFromSync(*extension, Extension::DISABLE_USER_ACTION); |
| 416 |
| 417 // The extension should be disabled. |
| 418 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| 419 EXPECT_EQ(Extension::DISABLE_USER_ACTION, |
| 420 ExtensionPrefs::Get(profile())->GetDisableReasons(kExtensionId)); |
| 421 EXPECT_TRUE(processor_raw->changes().empty()); |
| 422 |
| 423 // Enable the extension. Sync should push the new state. |
| 424 service()->EnableExtension(kExtensionId); |
| 425 { |
| 426 ASSERT_EQ(1u, processor_raw->changes().size()); |
| 427 const SyncChange& change = processor_raw->changes()[0]; |
| 428 EXPECT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); |
| 429 std::unique_ptr<ExtensionSyncData> data = |
| 430 ExtensionSyncData::CreateFromSyncData(change.sync_data()); |
| 431 EXPECT_EQ(kExtensionId, data->id()); |
| 432 EXPECT_EQ(0, data->disable_reasons()); |
| 433 EXPECT_TRUE(data->enabled()); |
| 434 } |
| 435 |
| 436 // Disable the extension again. Sync should push the new state. |
| 437 processor_raw->changes().clear(); |
| 438 service()->DisableExtension(kExtensionId, Extension::DISABLE_USER_ACTION); |
| 439 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| 440 { |
| 441 ASSERT_EQ(1u, processor_raw->changes().size()); |
| 442 const SyncChange& change = processor_raw->changes()[0]; |
| 443 EXPECT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); |
| 444 std::unique_ptr<ExtensionSyncData> data = |
| 445 ExtensionSyncData::CreateFromSyncData(change.sync_data()); |
| 446 EXPECT_EQ(kExtensionId, data->id()); |
| 447 EXPECT_EQ(Extension::DISABLE_USER_ACTION, data->disable_reasons()); |
| 448 EXPECT_FALSE(data->enabled()); |
| 449 } |
| 450 processor_raw->changes().clear(); |
| 451 |
| 452 // Enable the extension via sync. |
| 453 EnableExtensionFromSync(*extension); |
| 454 |
| 455 // The extension should be enabled. |
| 456 EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| 457 EXPECT_TRUE(processor_raw->changes().empty()); |
| 458 } |
| 459 |
| 460 // Tests that default-installed extensions won't be affected by incoming sync |
| 461 // data. (It's feasible to have a sync entry for an extension that could be |
| 462 // default installed, since one installation may be default-installed while |
| 463 // another may not be). |
| 464 TEST_F(ExtensionServiceSyncTest, |
| 465 DefaultInstalledExtensionsAreNotReenabledOrDisabledBySync) { |
| 466 InitializeEmptyExtensionService(); |
| 467 |
| 468 // Enable sync. |
| 469 browser_sync::ProfileSyncService* sync_service = |
| 470 ProfileSyncServiceFactory::GetForProfile(profile()); |
| 471 sync_service->SetFirstSetupComplete(); |
| 472 |
| 473 service()->Init(); |
| 474 |
| 475 // Load up an extension that's considered default installed. |
| 476 extensions::ChromeTestExtensionLoader extension_loader(profile()); |
| 477 extension_loader.set_pack_extension(true); |
| 478 extension_loader.add_creation_flag(Extension::WAS_INSTALLED_BY_DEFAULT); |
| 479 scoped_refptr<const Extension> extension = extension_loader.LoadExtension( |
| 480 data_dir().AppendASCII("simple_with_file")); |
| 481 ASSERT_TRUE(extension); |
| 482 |
| 483 // The extension shouldn't sync. |
| 484 EXPECT_FALSE(extensions::util::ShouldSync(extension.get(), profile())); |
| 485 const std::string kExtensionId = extension->id(); |
| 486 ASSERT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| 487 |
| 488 syncer::FakeSyncChangeProcessor* processor_raw = nullptr; |
| 489 { |
| 490 auto processor = base::MakeUnique<syncer::FakeSyncChangeProcessor>(); |
| 491 processor_raw = processor.get(); |
| 492 extension_sync_service()->MergeDataAndStartSyncing( |
| 493 syncer::EXTENSIONS, syncer::SyncDataList(), std::move(processor), |
| 494 base::MakeUnique<syncer::SyncErrorFactoryMock>()); |
| 495 } |
| 496 processor_raw->changes().clear(); |
| 497 |
| 498 // Sync state says the extension is disabled (e.g. on another machine). |
| 499 DisableExtensionFromSync(*extension, Extension::DISABLE_USER_ACTION); |
| 500 |
| 501 // The extension should still be enabled, since it's default-installed. |
| 502 EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| 503 EXPECT_TRUE(processor_raw->changes().empty()); |
| 504 |
| 505 // Now disable the extension locally. Sync should *not* push new state. |
| 506 service()->DisableExtension(kExtensionId, Extension::DISABLE_USER_ACTION); |
| 507 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| 508 EXPECT_TRUE(processor_raw->changes().empty()); |
| 509 |
| 510 // Sync state says the extension is enabled. |
| 511 EnableExtensionFromSync(*extension); |
| 512 |
| 513 // As above, the extension should not have been affected by sync. |
| 514 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| 515 EXPECT_TRUE(processor_raw->changes().empty()); |
| 516 |
| 517 // And re-enabling the extension should not push new state to sync. |
| 518 service()->EnableExtension(kExtensionId); |
| 519 EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| 520 EXPECT_TRUE(processor_raw->changes().empty()); |
| 521 } |
| 522 |
| 343 TEST_F(ExtensionServiceSyncTest, IgnoreSyncChangesWhenLocalStateIsMoreRecent) { | 523 TEST_F(ExtensionServiceSyncTest, IgnoreSyncChangesWhenLocalStateIsMoreRecent) { |
| 344 // Start the extension service with three extensions already installed. | 524 // Start the extension service with three extensions already installed. |
| 345 base::FilePath source_install_dir = | 525 base::FilePath source_install_dir = |
| 346 data_dir().AppendASCII("good").AppendASCII("Extensions"); | 526 data_dir().AppendASCII("good").AppendASCII("Extensions"); |
| 347 base::FilePath pref_path = | 527 base::FilePath pref_path = |
| 348 source_install_dir.DirName().Append(chrome::kPreferencesFilename); | 528 source_install_dir.DirName().Append(chrome::kPreferencesFilename); |
| 349 | 529 |
| 350 InitializeInstalledExtensionService(pref_path, source_install_dir); | 530 InitializeInstalledExtensionService(pref_path, source_install_dir); |
| 351 | 531 |
| 352 // The user has enabled sync. | 532 // The user has enabled sync. |
| (...skipping 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1355 EXPECT_EQ(expect_enabled, service()->IsExtensionEnabled(id)); | 1535 EXPECT_EQ(expect_enabled, service()->IsExtensionEnabled(id)); |
| 1356 EXPECT_EQ(test_case.expect_disable_reasons, prefs->GetDisableReasons(id)); | 1536 EXPECT_EQ(test_case.expect_disable_reasons, prefs->GetDisableReasons(id)); |
| 1357 | 1537 |
| 1358 // Remove the extension again, so we can install it again for the next case. | 1538 // Remove the extension again, so we can install it again for the next case. |
| 1359 UninstallExtension(id, false, expect_enabled ? Extension::ENABLED | 1539 UninstallExtension(id, false, expect_enabled ? Extension::ENABLED |
| 1360 : Extension::DISABLED); | 1540 : Extension::DISABLED); |
| 1361 } | 1541 } |
| 1362 } | 1542 } |
| 1363 | 1543 |
| 1364 TEST_F(ExtensionServiceSyncTest, ProcessSyncDataDeferredEnable) { | 1544 TEST_F(ExtensionServiceSyncTest, ProcessSyncDataDeferredEnable) { |
| 1545 // The permissions_increase test extension has a different update URL. |
| 1546 // In order to make it syncable, we have to pretend it syncs from the |
| 1547 // webstore. |
| 1548 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| 1549 switches::kAppsGalleryUpdateURL, |
| 1550 "http://localhost/autoupdate/updates.xml"); |
| 1551 |
| 1365 InitializeEmptyExtensionService(); | 1552 InitializeEmptyExtensionService(); |
| 1366 extension_sync_service()->MergeDataAndStartSyncing( | 1553 extension_sync_service()->MergeDataAndStartSyncing( |
| 1367 syncer::EXTENSIONS, syncer::SyncDataList(), | 1554 syncer::EXTENSIONS, syncer::SyncDataList(), |
| 1368 base::MakeUnique<syncer::FakeSyncChangeProcessor>(), | 1555 base::MakeUnique<syncer::FakeSyncChangeProcessor>(), |
| 1369 base::MakeUnique<syncer::SyncErrorFactoryMock>()); | 1556 base::MakeUnique<syncer::SyncErrorFactoryMock>()); |
| 1370 | 1557 |
| 1371 base::FilePath base_path = data_dir().AppendASCII("permissions_increase"); | 1558 base::FilePath base_path = data_dir().AppendASCII("permissions_increase"); |
| 1372 base::FilePath pem_path = base_path.AppendASCII("permissions.pem"); | 1559 base::FilePath pem_path = base_path.AppendASCII("permissions.pem"); |
| 1373 | 1560 |
| 1374 base::FilePath path = base_path.AppendASCII("v1"); | 1561 base::FilePath path = base_path.AppendASCII("v1"); |
| (...skipping 1099 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2474 break; | 2661 break; |
| 2475 } | 2662 } |
| 2476 } | 2663 } |
| 2477 } | 2664 } |
| 2478 EXPECT_TRUE(found_delete); | 2665 EXPECT_TRUE(found_delete); |
| 2479 | 2666 |
| 2480 // Make sure there is one extension, and there are no more apps. | 2667 // Make sure there is one extension, and there are no more apps. |
| 2481 EXPECT_EQ(1u, extensions_processor.data().size()); | 2668 EXPECT_EQ(1u, extensions_processor.data().size()); |
| 2482 EXPECT_TRUE(apps_processor.data().empty()); | 2669 EXPECT_TRUE(apps_processor.data().empty()); |
| 2483 } | 2670 } |
| OLD | NEW |