1 // Copyright 2017 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 "extensions/browser/extension_registrar.h"
6
7 #include <memory>
8
9 #include "base/location.h"
10 #include "base/macros.h"
11 #include "base/optional.h"
12 #include "base/threading/sequenced_task_runner_handle.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/test/test_notification_tracker.h"
15 #include "extensions/browser/extension_prefs.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/browser/extensions_test.h"
18 #include "extensions/browser/notification_types.h"
19 #include "extensions/browser/runtime_data.h"
20 #include "extensions/browser/test_extension_registry_observer.h"
21 #include "extensions/browser/test_extensions_browser_client.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_builder.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace extensions {
28
29 namespace {
30
31 using testing::Return;
32 using testing::_;
33
34 using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
35
36 class TestExtensionSystem : public MockExtensionSystem {
37 public:
TestExtensionSystem(content::BrowserContext * context)38 explicit TestExtensionSystem(content::BrowserContext* context)
39 : MockExtensionSystem(context),
40 runtime_data_(ExtensionRegistry::Get(context)) {}
41
~TestExtensionSystem()42 ~TestExtensionSystem() override {}
43
44 // MockExtensionSystem:
RegisterExtensionWithRequestContexts(const Extension * extension,base::OnceClosure callback)45 void RegisterExtensionWithRequestContexts(
46 const Extension* extension,
47 base::OnceClosure callback) override {
48 base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
49 std::move(callback));
50 }
runtime_data()51 RuntimeData* runtime_data() override { return &runtime_data_; }
52
53 private:
54 RuntimeData runtime_data_;
55 DISALLOW_COPY_AND_ASSIGN(TestExtensionSystem);
56 };
57
58 class TestExtensionRegistrarDelegate : public ExtensionRegistrar::Delegate {
59 public:
60 TestExtensionRegistrarDelegate() = default;
61 ~TestExtensionRegistrarDelegate() override = default;
62
63 // ExtensionRegistrar::Delegate:
64 MOCK_METHOD2(PreAddExtension,
65 void(const Extension* extension,
66 const Extension* old_extension));
67 MOCK_METHOD1(PostActivateExtension,
68 void(scoped_refptr<const Extension> extension));
69 MOCK_METHOD1(PostDeactivateExtension,
70 void(scoped_refptr<const Extension> extension));
71 MOCK_METHOD3(LoadExtensionForReload,
72 void(const ExtensionId& extension_id,
73 const base::FilePath& path,
74 LoadErrorBehavior load_error_behavior));
75 MOCK_METHOD1(CanEnableExtension, bool(const Extension* extension));
76 MOCK_METHOD1(CanDisableExtension, bool(const Extension* extension));
77 MOCK_METHOD1(ShouldBlockExtension, bool(const Extension* extension));
78
79 private:
80 DISALLOW_COPY_AND_ASSIGN(TestExtensionRegistrarDelegate);
81 };
82
83 } // namespace
84
85 class ExtensionRegistrarTest : public ExtensionsTest {
86 public:
87 ExtensionRegistrarTest() = default;
88 ~ExtensionRegistrarTest() override = default;
89
SetUp()90 void SetUp() override {
91 ExtensionsTest::SetUp();
92 extensions_browser_client()->set_extension_system_factory(&factory_);
93 extension_ = ExtensionBuilder("extension").Build();
94 registrar_.emplace(browser_context(), delegate());
95
96 notification_tracker_.ListenFor(
97 extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
98 content::Source<content::BrowserContext>(browser_context()));
99 notification_tracker_.ListenFor(
100 extensions::NOTIFICATION_EXTENSION_REMOVED,
101 content::Source<content::BrowserContext>(browser_context()));
102
103 // Mock defaults.
104 ON_CALL(delegate_, CanEnableExtension(extension_.get()))
105 .WillByDefault(Return(true));
106 ON_CALL(delegate_, CanDisableExtension(extension_.get()))
107 .WillByDefault(Return(true));
108 ON_CALL(delegate_, ShouldBlockExtension(extension_.get()))
109 .WillByDefault(Return(false));
110 EXPECT_CALL(delegate_, PostActivateExtension(_)).Times(0);
111 EXPECT_CALL(delegate_, PostDeactivateExtension(_)).Times(0);
112 }
113
114 protected:
115 // Boilerplate to verify the mock's expected calls. With a SCOPED_TRACE at the
116 // call site, this includes the caller's function in the Gtest trace on
117 // failure. Otherwise, the failures are unhelpfully listed at the end of the
118 // test.
VerifyMock()119 void VerifyMock() {
120 EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&delegate_));
121
122 // Re-add the expectations for functions that must not be called.
123 EXPECT_CALL(delegate_, PostActivateExtension(_)).Times(0);
124 EXPECT_CALL(delegate_, PostDeactivateExtension(_)).Times(0);
125 }
126
127 // Adds the extension as enabled and verifies the result.
AddEnabledExtension()128 void AddEnabledExtension() {
129 SCOPED_TRACE("AddEnabledExtension");
130 ExtensionRegistry* extension_registry =
131 ExtensionRegistry::Get(browser_context());
132
133 EXPECT_CALL(delegate_, PostActivateExtension(extension_));
134 registrar_->AddExtension(extension_);
135 ExpectInSet(ExtensionRegistry::ENABLED);
136 EXPECT_FALSE(IsExtensionReady());
137
138 TestExtensionRegistryObserver(extension_registry).WaitForExtensionReady();
139 EXPECT_TRUE(IsExtensionReady());
140
141 EXPECT_EQ(disable_reason::DISABLE_NONE,
142 ExtensionPrefs::Get(browser_context())
143 ->GetDisableReasons(extension()->id()));
144
145 VerifyMock();
146 }
147
148 // Adds the extension as disabled and verifies the result.
AddDisabledExtension()149 void AddDisabledExtension() {
150 SCOPED_TRACE("AddDisabledExtension");
151 ExtensionPrefs::Get(browser_context())
152 ->SetExtensionDisabled(extension_->id(),
153 disable_reason::DISABLE_USER_ACTION);
154 registrar_->AddExtension(extension_);
155 ExpectInSet(ExtensionRegistry::DISABLED);
156 EXPECT_FALSE(IsExtensionReady());
157 EXPECT_TRUE(notification_tracker_.Check1AndReset(
158 extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED));
159 }
160
161 // Adds the extension as blacklisted and verifies the result.
AddBlacklistedExtension()162 void AddBlacklistedExtension() {
163 SCOPED_TRACE("AddBlacklistedExtension");
164 ExtensionPrefs::Get(browser_context())
165 ->SetExtensionBlacklistState(extension_->id(), BLACKLISTED_MALWARE);
166 registrar_->AddExtension(extension_);
167 ExpectInSet(ExtensionRegistry::BLACKLISTED);
168 EXPECT_FALSE(IsExtensionReady());
169 EXPECT_EQ(0u, notification_tracker_.size());
170 }
171
172 // Adds the extension as blocked and verifies the result.
AddBlockedExtension()173 void AddBlockedExtension() {
174 SCOPED_TRACE("AddBlockedExtension");
175 registrar_->AddExtension(extension_);
176 ExpectInSet(ExtensionRegistry::BLOCKED);
177 EXPECT_FALSE(IsExtensionReady());
178 EXPECT_EQ(0u, notification_tracker_.size());
179 }
180
181 // Removes an enabled extension and verifies the result.
RemoveEnabledExtension()182 void RemoveEnabledExtension() {
183 SCOPED_TRACE("RemoveEnabledExtension");
184 // Calling RemoveExtension removes its entry from the enabled list and
185 // removes the extension.
186 EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
187 registrar_->RemoveExtension(extension_->id(),
188 UnloadedExtensionReason::UNINSTALL);
189 ExpectInSet(ExtensionRegistry::NONE);
190
191 // Removing an enabled extension should trigger a notification.
192 EXPECT_TRUE(notification_tracker_.Check1AndReset(
193 extensions::NOTIFICATION_EXTENSION_REMOVED));
194
195 VerifyMock();
196 }
197
198 // Removes a disabled extension and verifies the result.
RemoveDisabledExtension()199 void RemoveDisabledExtension() {
200 SCOPED_TRACE("RemoveDisabledExtension");
201 // Calling RemoveExtension removes its entry from the disabled list and
202 // removes the extension.
203 registrar_->RemoveExtension(extension_->id(),
204 UnloadedExtensionReason::UNINSTALL);
205 ExpectInSet(ExtensionRegistry::NONE);
206
207 // Removing a disabled extension should trigger a notification.
208 EXPECT_TRUE(notification_tracker_.Check1AndReset(
209 extensions::NOTIFICATION_EXTENSION_REMOVED));
210 }
211
212 // Removes a blacklisted extension and verifies the result.
RemoveBlacklistedExtension()213 void RemoveBlacklistedExtension() {
214 SCOPED_TRACE("RemoveBlacklistedExtension");
215 // Calling RemoveExtension removes the extension.
216 // TODO(michaelpg): Blacklisted extensions shouldn't need to be
217 // "deactivated". See crbug.com/708230.
218 EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
219 registrar_->RemoveExtension(extension_->id(),
220 UnloadedExtensionReason::UNINSTALL);
221
222 // RemoveExtension does not un-blacklist the extension.
223 ExpectInSet(ExtensionRegistry::BLACKLISTED);
224
225 // Removing a blacklisted extension should trigger a notification.
226 EXPECT_TRUE(notification_tracker_.Check1AndReset(
227 extensions::NOTIFICATION_EXTENSION_REMOVED));
228
229 VerifyMock();
230 }
231
232 // Removes a blocked extension and verifies the result.
RemoveBlockedExtension()233 void RemoveBlockedExtension() {
234 SCOPED_TRACE("RemoveBlockedExtension");
235 // Calling RemoveExtension removes the extension.
236 // TODO(michaelpg): Blocked extensions shouldn't need to be
237 // "deactivated". See crbug.com/708230.
238 EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
239 registrar_->RemoveExtension(extension_->id(),
240 UnloadedExtensionReason::UNINSTALL);
241
242 // RemoveExtension does not un-block the extension.
243 ExpectInSet(ExtensionRegistry::BLOCKED);
244
245 // Removing a blocked extension should trigger a notification.
246 EXPECT_TRUE(notification_tracker_.Check1AndReset(
247 extensions::NOTIFICATION_EXTENSION_REMOVED));
248
249 VerifyMock();
250 }
251
EnableExtension()252 void EnableExtension() {
253 SCOPED_TRACE("EnableExtension");
254 ExtensionRegistry* extension_registry =
255 ExtensionRegistry::Get(browser_context());
256
257 EXPECT_CALL(delegate_, PostActivateExtension(extension_));
258 registrar_->EnableExtension(extension_->id());
259 ExpectInSet(ExtensionRegistry::ENABLED);
260 EXPECT_FALSE(IsExtensionReady());
261
262 TestExtensionRegistryObserver(extension_registry).WaitForExtensionReady();
263 ExpectInSet(ExtensionRegistry::ENABLED);
264 EXPECT_TRUE(IsExtensionReady());
265
266 VerifyMock();
267 }
268
DisableEnabledExtension()269 void DisableEnabledExtension() {
270 SCOPED_TRACE("DisableEnabledExtension");
271 EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
272 registrar_->DisableExtension(extension_->id(),
273 disable_reason::DISABLE_USER_ACTION);
274 ExpectInSet(ExtensionRegistry::DISABLED);
275 EXPECT_FALSE(IsExtensionReady());
276
277 VerifyMock();
278 }
279
DisableTerminatedExtension()280 void DisableTerminatedExtension() {
281 SCOPED_TRACE("DisableTerminatedExtension");
282 // PostDeactivateExtension should not be called.
283 registrar_->DisableExtension(extension_->id(),
284 disable_reason::DISABLE_USER_ACTION);
285 ExpectInSet(ExtensionRegistry::DISABLED);
286 EXPECT_FALSE(IsExtensionReady());
287 }
288
TerminateExtension()289 void TerminateExtension() {
290 SCOPED_TRACE("TerminateExtension");
291 EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
292 registrar_->TerminateExtension(extension_->id());
293 ExpectInSet(ExtensionRegistry::TERMINATED);
294 EXPECT_FALSE(IsExtensionReady());
295 VerifyMock();
296 }
297
UntrackTerminatedExtension()298 void UntrackTerminatedExtension() {
299 SCOPED_TRACE("UntrackTerminatedExtension");
300 registrar()->UntrackTerminatedExtension(extension()->id());
301 ExpectInSet(ExtensionRegistry::NONE);
302 EXPECT_TRUE(notification_tracker_.Check1AndReset(
303 extensions::NOTIFICATION_EXTENSION_REMOVED));
304 }
305
306 // Directs ExtensionRegistrar to reload the extension and verifies the
307 // delegate is invoked correctly.
ReloadEnabledExtension()308 void ReloadEnabledExtension() {
309 SCOPED_TRACE("ReloadEnabledExtension");
310 EXPECT_CALL(delegate_, PostDeactivateExtension(extension()));
311 EXPECT_CALL(delegate_,
312 LoadExtensionForReload(extension()->id(), extension()->path(),
313 LoadErrorBehavior::kNoisy));
314 registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kNoisy);
315 VerifyMock();
316
317 // ExtensionRegistrar should have disabled the extension in preparation for
318 // a reload.
319 ExpectInSet(ExtensionRegistry::DISABLED);
320 EXPECT_EQ(disable_reason::DISABLE_RELOAD,
321 ExtensionPrefs::Get(browser_context())
322 ->GetDisableReasons(extension()->id()));
323 }
324
325 // Directs ExtensionRegistrar to reload the terminated extension and verifies
326 // the delegate is invoked correctly.
ReloadTerminatedExtension()327 void ReloadTerminatedExtension() {
328 SCOPED_TRACE("ReloadTerminatedExtension");
329 EXPECT_CALL(delegate_,
330 LoadExtensionForReload(extension()->id(), extension()->path(),
331 LoadErrorBehavior::kNoisy));
332 registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kNoisy);
333 VerifyMock();
334
335 // The extension should remain in the terminated set until the reload
336 // completes successfully.
337 ExpectInSet(ExtensionRegistry::TERMINATED);
338 // Unlike when reloading an enabled extension, the extension hasn't been
339 // disabled and shouldn't have the DISABLE_RELOAD disable reason.
340 EXPECT_EQ(disable_reason::DISABLE_NONE,
341 ExtensionPrefs::Get(browser_context())
342 ->GetDisableReasons(extension()->id()));
343 }
344
345 // Verifies that the extension is in the given set in the ExtensionRegistry
346 // and not in other sets.
ExpectInSet(ExtensionRegistry::IncludeFlag set_id)347 void ExpectInSet(ExtensionRegistry::IncludeFlag set_id) {
348 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
349
350 EXPECT_EQ(set_id == ExtensionRegistry::ENABLED,
351 registry->enabled_extensions().Contains(extension_->id()));
352
353 EXPECT_EQ(set_id == ExtensionRegistry::DISABLED,
354 registry->disabled_extensions().Contains(extension_->id()));
355
356 EXPECT_EQ(set_id == ExtensionRegistry::TERMINATED,
357 registry->terminated_extensions().Contains(extension_->id()));
358
359 EXPECT_EQ(set_id == ExtensionRegistry::BLACKLISTED,
360 registry->blacklisted_extensions().Contains(extension_->id()));
361
362 EXPECT_EQ(set_id == ExtensionRegistry::BLOCKED,
363 registry->blocked_extensions().Contains(extension_->id()));
364 }
365
IsExtensionReady()366 bool IsExtensionReady() {
367 return ExtensionRegistry::Get(browser_context())
368 ->ready_extensions()
369 .Contains(extension_->id());
370 }
371
registrar()372 ExtensionRegistrar* registrar() { return ®istrar_.value(); }
delegate()373 TestExtensionRegistrarDelegate* delegate() { return &delegate_; }
374
extension() const375 scoped_refptr<const Extension> extension() const { return extension_; }
376
377 private:
378 MockExtensionSystemFactory<TestExtensionSystem> factory_;
379 // Use NiceMock to allow uninteresting calls, so the delegate can be queried
380 // any number of times. We will explicitly disallow unexpected calls to
381 // PostActivateExtension/PostDeactivateExtension with EXPECT_CALL statements.
382 testing::NiceMock<TestExtensionRegistrarDelegate> delegate_;
383 scoped_refptr<const Extension> extension_;
384
385 content::TestNotificationTracker notification_tracker_;
386
387 // Initialized in SetUp().
388 base::Optional<ExtensionRegistrar> registrar_;
389
390 DISALLOW_COPY_AND_ASSIGN(ExtensionRegistrarTest);
391 };
392
TEST_F(ExtensionRegistrarTest,Basic)393 TEST_F(ExtensionRegistrarTest, Basic) {
394 AddEnabledExtension();
395 RemoveEnabledExtension();
396 }
397
TEST_F(ExtensionRegistrarTest,AlreadyEnabled)398 TEST_F(ExtensionRegistrarTest, AlreadyEnabled) {
399 AddEnabledExtension();
400
401 // As the extension is already enabled, this is a no-op.
402 registrar()->EnableExtension(extension()->id());
403 ExpectInSet(ExtensionRegistry::ENABLED);
404 EXPECT_TRUE(IsExtensionReady());
405
406 RemoveEnabledExtension();
407 }
408
TEST_F(ExtensionRegistrarTest,Disable)409 TEST_F(ExtensionRegistrarTest, Disable) {
410 AddEnabledExtension();
411
412 // Disable the extension before removing it.
413 DisableEnabledExtension();
414 RemoveDisabledExtension();
415 }
416
TEST_F(ExtensionRegistrarTest,DisableAndEnable)417 TEST_F(ExtensionRegistrarTest, DisableAndEnable) {
418 AddEnabledExtension();
419
420 // Disable then enable the extension.
421 DisableEnabledExtension();
422 EnableExtension();
423
424 RemoveEnabledExtension();
425 }
426
TEST_F(ExtensionRegistrarTest,AddDisabled)427 TEST_F(ExtensionRegistrarTest, AddDisabled) {
428 // An extension can be added as disabled, then removed.
429 AddDisabledExtension();
430 RemoveDisabledExtension();
431
432 // An extension can be added as disabled, then enabled.
433 AddDisabledExtension();
434 EnableExtension();
435 RemoveEnabledExtension();
436 }
437
TEST_F(ExtensionRegistrarTest,AddForceEnabled)438 TEST_F(ExtensionRegistrarTest, AddForceEnabled) {
439 // Prevent the extension from being disabled.
440 ON_CALL(*delegate(), CanDisableExtension(extension().get()))
441 .WillByDefault(Return(false));
442 AddEnabledExtension();
443
444 // Extension cannot be disabled.
445 registrar()->DisableExtension(extension()->id(),
446 disable_reason::DISABLE_USER_ACTION);
447 ExpectInSet(ExtensionRegistry::ENABLED);
448 }
449
TEST_F(ExtensionRegistrarTest,AddForceDisabled)450 TEST_F(ExtensionRegistrarTest, AddForceDisabled) {
451 // Prevent the extension from being enabled.
452 ON_CALL(*delegate(), CanEnableExtension(extension().get()))
453 .WillByDefault(Return(false));
454 AddDisabledExtension();
455
456 // Extension cannot be enabled.
457 registrar()->EnableExtension(extension()->id());
458 ExpectInSet(ExtensionRegistry::DISABLED);
459 }
460
TEST_F(ExtensionRegistrarTest,AddBlacklisted)461 TEST_F(ExtensionRegistrarTest, AddBlacklisted) {
462 AddBlacklistedExtension();
463
464 // A blacklisted extension cannot be enabled/disabled/reloaded.
465 registrar()->EnableExtension(extension()->id());
466 ExpectInSet(ExtensionRegistry::BLACKLISTED);
467 registrar()->DisableExtension(extension()->id(),
468 disable_reason::DISABLE_USER_ACTION);
469 ExpectInSet(ExtensionRegistry::BLACKLISTED);
470 registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kQuiet);
471 ExpectInSet(ExtensionRegistry::BLACKLISTED);
472
473 RemoveBlacklistedExtension();
474 }
475
TEST_F(ExtensionRegistrarTest,AddBlocked)476 TEST_F(ExtensionRegistrarTest, AddBlocked) {
477 // Block extensions.
478 ON_CALL(*delegate(), ShouldBlockExtension(extension().get()))
479 .WillByDefault(Return(true));
480
481 // A blocked extension can be added.
482 AddBlockedExtension();
483
484 // Extension cannot be enabled/disabled.
485 registrar()->EnableExtension(extension()->id());
486 ExpectInSet(ExtensionRegistry::BLOCKED);
487 registrar()->DisableExtension(extension()->id(),
488 disable_reason::DISABLE_USER_ACTION);
489 ExpectInSet(ExtensionRegistry::BLOCKED);
490
491 RemoveBlockedExtension();
492 }
493
TEST_F(ExtensionRegistrarTest,TerminateExtension)494 TEST_F(ExtensionRegistrarTest, TerminateExtension) {
495 AddEnabledExtension();
496 TerminateExtension();
497
498 // RemoveExtension only handles enabled or disabled extensions.
499 registrar()->RemoveExtension(extension()->id(),
500 UnloadedExtensionReason::UNINSTALL);
501 ExpectInSet(ExtensionRegistry::TERMINATED);
502
503 UntrackTerminatedExtension();
504 }
505
TEST_F(ExtensionRegistrarTest,DisableTerminatedExtension)506 TEST_F(ExtensionRegistrarTest, DisableTerminatedExtension) {
507 AddEnabledExtension();
508 TerminateExtension();
509 DisableTerminatedExtension();
510 RemoveDisabledExtension();
511 }
512
TEST_F(ExtensionRegistrarTest,EnableTerminatedExtension)513 TEST_F(ExtensionRegistrarTest, EnableTerminatedExtension) {
514 AddEnabledExtension();
515 TerminateExtension();
516
517 // Enable the terminated extension.
518 UntrackTerminatedExtension();
519 AddEnabledExtension();
520
521 RemoveEnabledExtension();
522 }
523
TEST_F(ExtensionRegistrarTest,ReloadExtension)524 TEST_F(ExtensionRegistrarTest, ReloadExtension) {
525 AddEnabledExtension();
526 ReloadEnabledExtension();
527
528 // Add the now-reloaded extension back into the registrar.
529 AddEnabledExtension();
530 }
531
TEST_F(ExtensionRegistrarTest,RemoveReloadedExtension)532 TEST_F(ExtensionRegistrarTest, RemoveReloadedExtension) {
533 AddEnabledExtension();
534 ReloadEnabledExtension();
535
536 // Simulate the delegate failing to load the extension and removing it
537 // instead.
538 RemoveDisabledExtension();
539
540 // Attempting to reload it silently fails.
541 registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kQuiet);
542 ExpectInSet(ExtensionRegistry::NONE);
543 }
544
TEST_F(ExtensionRegistrarTest,ReloadTerminatedExtension)545 TEST_F(ExtensionRegistrarTest, ReloadTerminatedExtension) {
546 AddEnabledExtension();
547 TerminateExtension();
548
549 // Reload the terminated extension.
550 ReloadTerminatedExtension();
551
552 // Complete the reload by adding the extension. Expect the extension to be
553 // enabled once re-added to the registrar, since ExtensionPrefs shouldn't say
554 // it's disabled.
555 AddEnabledExtension();
556 }
557
558 } // namespace extensions
559