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.
5 #include "base/files/file_path.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/threading/sequenced_worker_pool.h"
8 #include "chrome/app/chrome_command_ids.h"
9 #include "chrome/browser/extensions/extension_browsertest.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_sync_service.h"
12 #include "chrome/browser/extensions/updater/extension_updater.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/global_error/global_error.h"
16 #include "chrome/browser/ui/global_error/global_error_service.h"
17 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/test/test_utils.h"
21 #include "extensions/browser/extension_prefs.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/common/extension.h"
25 #include "net/url_request/test_url_request_interceptor.h"
26 #include "net/url_request/url_fetcher.h"
27 #include "sync/protocol/extension_specifics.pb.h"
28 #include "sync/protocol/sync.pb.h"
30 using content::BrowserThread;
31 using extensions::Extension;
32 using extensions::ExtensionRegistry;
33 using extensions::ExtensionPrefs;
35 class ExtensionDisabledGlobalErrorTest : public ExtensionBrowserTest {
37 void SetUpCommandLine(CommandLine* command_line) override {
38 ExtensionBrowserTest::SetUpCommandLine(command_line);
39 command_line->AppendSwitchASCII(switches::kAppsGalleryUpdateURL,
40 "http://localhost/autoupdate/updates.xml");
43 void SetUpOnMainThread() override {
44 ExtensionBrowserTest::SetUpOnMainThread();
45 EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
46 service_ = extensions::ExtensionSystem::Get(
47 browser()->profile())->extension_service();
48 registry_ = ExtensionRegistry::Get(browser()->profile());
49 const base::FilePath test_dir =
50 test_data_dir_.AppendASCII("permissions_increase");
51 const base::FilePath pem_path = test_dir.AppendASCII("permissions.pem");
52 path_v1_ = PackExtensionWithOptions(
53 test_dir.AppendASCII("v1"),
54 scoped_temp_dir_.path().AppendASCII("permissions1.crx"),
57 path_v2_ = PackExtensionWithOptions(
58 test_dir.AppendASCII("v2"),
59 scoped_temp_dir_.path().AppendASCII("permissions2.crx"),
62 path_v3_ = PackExtensionWithOptions(
63 test_dir.AppendASCII("v3"),
64 scoped_temp_dir_.path().AppendASCII("permissions3.crx"),
69 // Returns the ExtensionDisabledGlobalError, if present.
70 // Caution: currently only supports one error at a time.
71 GlobalError* GetExtensionDisabledGlobalError() {
72 return GlobalErrorServiceFactory::GetForProfile(browser()->profile())->
73 GetGlobalErrorByMenuItemCommandID(IDC_EXTENSION_DISABLED_FIRST);
76 // Install the initial version, which should happen just fine.
77 const Extension* InstallIncreasingPermissionExtensionV1() {
78 size_t size_before = registry_->enabled_extensions().size();
79 const Extension* extension = InstallExtension(path_v1_, 1);
82 if (registry_->enabled_extensions().size() != size_before + 1)
87 // Upgrade to a version that wants more permissions. We should disable the
88 // extension and prompt the user to reenable.
89 const Extension* UpdateIncreasingPermissionExtension(
90 const Extension* extension,
91 const base::FilePath& crx_path,
92 int expected_change) {
93 size_t size_before = registry_->enabled_extensions().size();
94 if (UpdateExtension(extension->id(), crx_path, expected_change))
96 content::RunAllBlockingPoolTasksUntilIdle();
97 EXPECT_EQ(size_before + expected_change,
98 registry_->enabled_extensions().size());
99 if (registry_->disabled_extensions().size() != 1u)
102 return registry_->disabled_extensions().begin()->get();
105 // Helper function to install an extension and upgrade it to a version
106 // requiring additional permissions. Returns the new disabled Extension.
107 const Extension* InstallAndUpdateIncreasingPermissionsExtension() {
108 const Extension* extension = InstallIncreasingPermissionExtensionV1();
109 extension = UpdateIncreasingPermissionExtension(extension, path_v2_, -1);
113 ExtensionService* service_;
114 ExtensionRegistry* registry_;
115 base::ScopedTempDir scoped_temp_dir_;
116 base::FilePath path_v1_;
117 base::FilePath path_v2_;
118 base::FilePath path_v3_;
121 // Tests the process of updating an extension to one that requires higher
122 // permissions, and accepting the permissions.
123 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, AcceptPermissions) {
124 const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
125 ASSERT_TRUE(extension);
126 ASSERT_TRUE(GetExtensionDisabledGlobalError());
127 const size_t size_before = registry_->enabled_extensions().size();
129 service_->GrantPermissionsAndEnableExtension(extension);
130 EXPECT_EQ(size_before + 1, registry_->enabled_extensions().size());
131 EXPECT_EQ(0u, registry_->disabled_extensions().size());
132 ASSERT_FALSE(GetExtensionDisabledGlobalError());
135 // Tests uninstalling an extension that was disabled due to higher permissions.
136 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, Uninstall) {
137 const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
138 ASSERT_TRUE(extension);
139 ASSERT_TRUE(GetExtensionDisabledGlobalError());
140 const size_t size_before = registry_->enabled_extensions().size();
142 UninstallExtension(extension->id());
143 EXPECT_EQ(size_before, registry_->enabled_extensions().size());
144 EXPECT_EQ(0u, registry_->disabled_extensions().size());
145 ASSERT_FALSE(GetExtensionDisabledGlobalError());
148 // Tests that no error appears if the user disabled the extension.
149 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, UserDisabled) {
150 const Extension* extension = InstallIncreasingPermissionExtensionV1();
151 DisableExtension(extension->id());
152 extension = UpdateIncreasingPermissionExtension(extension, path_v2_, 0);
153 ASSERT_FALSE(GetExtensionDisabledGlobalError());
156 // Test that no error appears if the disable reason is unknown
157 // (but probably was by the user).
158 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest,
159 UnknownReasonSamePermissions) {
160 const Extension* extension = InstallIncreasingPermissionExtensionV1();
161 DisableExtension(extension->id());
162 // Clear disable reason to simulate legacy disables.
163 ExtensionPrefs::Get(browser()->profile())
164 ->ClearDisableReasons(extension->id());
165 // Upgrade to version 2. Infer from version 1 having the same permissions
166 // granted by the user that it was disabled by the user.
167 extension = UpdateIncreasingPermissionExtension(extension, path_v2_, 0);
168 ASSERT_TRUE(extension);
169 ASSERT_FALSE(GetExtensionDisabledGlobalError());
172 // Test that an error appears if the disable reason is unknown
173 // (but probably was for increased permissions).
174 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest,
175 UnknownReasonHigherPermissions) {
176 const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
177 // Clear disable reason to simulate legacy disables.
178 ExtensionPrefs::Get(service_->profile())
179 ->ClearDisableReasons(extension->id());
180 // We now have version 2 but only accepted permissions for version 1.
181 GlobalError* error = GetExtensionDisabledGlobalError();
183 // Also, remove the upgrade error for version 2.
184 GlobalErrorServiceFactory::GetForProfile(browser()->profile())->
185 RemoveGlobalError(error);
187 // Upgrade to version 3, with even higher permissions. Infer from
188 // version 2 having higher-than-granted permissions that it was disabled
189 // for permissions increase.
190 extension = UpdateIncreasingPermissionExtension(extension, path_v3_, 0);
191 ASSERT_TRUE(extension);
192 ASSERT_TRUE(GetExtensionDisabledGlobalError());
195 // Test that an error appears if the extension gets disabled because a
196 // version with higher permissions was installed by sync.
197 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest,
198 HigherPermissionsFromSync) {
199 // Get data for extension v2 (disabled) into sync.
200 const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
201 std::string extension_id = extension->id();
202 ExtensionSyncService* sync_service = ExtensionSyncService::Get(
203 browser()->profile());
204 extensions::ExtensionSyncData sync_data =
205 sync_service->GetExtensionSyncData(*extension);
206 UninstallExtension(extension_id);
209 // Install extension v1.
210 InstallIncreasingPermissionExtensionV1();
212 // Note: This interceptor gets requests on the IO thread.
213 net::LocalHostTestURLRequestInterceptor interceptor(
214 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
215 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
216 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
217 net::URLFetcher::SetEnableInterceptionForTests(true);
218 interceptor.SetResponseIgnoreQuery(
219 GURL("http://localhost/autoupdate/updates.xml"),
220 test_data_dir_.AppendASCII("permissions_increase")
221 .AppendASCII("updates.xml"));
222 interceptor.SetResponseIgnoreQuery(
223 GURL("http://localhost/autoupdate/v2.crx"),
224 scoped_temp_dir_.path().AppendASCII("permissions2.crx"));
226 extensions::ExtensionUpdater::CheckParams params;
227 service_->updater()->set_default_check_params(params);
229 // Sync is replacing an older version, so it pends.
230 EXPECT_FALSE(sync_service->ProcessExtensionSyncData(sync_data));
232 WaitForExtensionInstall();
233 content::RunAllBlockingPoolTasksUntilIdle();
235 extension = service_->GetExtensionById(extension_id, true);
236 ASSERT_TRUE(extension);
237 EXPECT_EQ("2", extension->VersionString());
238 EXPECT_EQ(1u, registry_->disabled_extensions().size());
239 EXPECT_EQ(Extension::DISABLE_PERMISSIONS_INCREASE,
240 ExtensionPrefs::Get(service_->profile())
241 ->GetDisableReasons(extension_id));
242 EXPECT_TRUE(GetExtensionDisabledGlobalError());
245 // Test that an error appears if an extension gets installed server side.
246 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, RemoteInstall) {
247 static const char extension_id[] = "pgdpcfcocojkjfbgpiianjngphoopgmo";
248 ExtensionSyncService* sync_service =
249 ExtensionSyncService::Get(browser()->profile());
251 // Note: This interceptor gets requests on the IO thread.
252 net::LocalHostTestURLRequestInterceptor interceptor(
253 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
254 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
255 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
256 net::URLFetcher::SetEnableInterceptionForTests(true);
257 interceptor.SetResponseIgnoreQuery(
258 GURL("http://localhost/autoupdate/updates.xml"),
259 test_data_dir_.AppendASCII("permissions_increase")
260 .AppendASCII("updates.xml"));
261 interceptor.SetResponseIgnoreQuery(
262 GURL("http://localhost/autoupdate/v2.crx"),
263 scoped_temp_dir_.path().AppendASCII("permissions2.crx"));
265 extensions::ExtensionUpdater::CheckParams params;
266 service_->updater()->set_default_check_params(params);
268 sync_pb::EntitySpecifics specifics;
269 specifics.mutable_extension()->set_id(extension_id);
270 specifics.mutable_extension()->set_enabled(false);
271 specifics.mutable_extension()->set_remote_install(true);
272 specifics.mutable_extension()->set_update_url(
273 "http://localhost/autoupdate/updates.xml");
274 specifics.mutable_extension()->set_version("2");
275 syncer::SyncData sync_data =
276 syncer::SyncData::CreateRemoteData(1234567,
279 syncer::AttachmentIdList(),
280 syncer::AttachmentServiceProxy());
281 // Sync is installing a new extension, so it pends.
282 EXPECT_FALSE(sync_service->ProcessExtensionSyncData(
283 extensions::ExtensionSyncData(sync_data)));
285 WaitForExtensionInstall();
286 content::RunAllBlockingPoolTasksUntilIdle();
288 const Extension* extension = service_->GetExtensionById(extension_id, true);
289 ASSERT_TRUE(extension);
290 EXPECT_EQ("2", extension->VersionString());
291 EXPECT_EQ(1u, registry_->disabled_extensions().size());
292 EXPECT_EQ(Extension::DISABLE_REMOTE_INSTALL,
293 ExtensionPrefs::Get(service_->profile())
294 ->GetDisableReasons(extension_id));
295 EXPECT_TRUE(GetExtensionDisabledGlobalError());