blob: 9af3285625148cd4131ba57670d0ed23a1f96851 [file] [log] [blame]
[email protected]764bc252013-01-08 03:19:031// 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.
4
5#include "chrome/browser/ui/extensions/extension_enable_flow.h"
6
dcheng9603ab92016-04-08 04:17:327#include "base/memory/ptr_util.h"
[email protected]7b1e364a2013-08-09 15:36:128#include "chrome/browser/chrome_notification_types.h"
[email protected]764bc252013-01-08 03:19:039#include "chrome/browser/extensions/extension_service.h"
treibbb9a1962015-02-25 13:40:5910#include "chrome/browser/extensions/extension_util.h"
[email protected]59b0e602014-01-30 00:41:2411#include "chrome/browser/profiles/profile.h"
mlerman9ccf2d82015-03-31 10:46:2912#include "chrome/browser/profiles/profiles_state.h"
[email protected]764bc252013-01-08 03:19:0313#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
mlerman9ccf2d82015-03-31 10:46:2914#include "chrome/browser/ui/user_manager.h"
[email protected]7b1e364a2013-08-09 15:36:1215#include "content/public/browser/notification_details.h"
16#include "content/public/browser/notification_source.h"
[email protected]dccba4f82014-05-29 00:52:5617#include "extensions/browser/extension_prefs.h"
[email protected]e066da32014-03-26 18:27:3518#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2419#include "extensions/browser/extension_system.h"
[email protected]764bc252013-01-08 03:19:0320
21using extensions::Extension;
22
23ExtensionEnableFlow::ExtensionEnableFlow(Profile* profile,
24 const std::string& extension_id,
25 ExtensionEnableFlowDelegate* delegate)
26 : profile_(profile),
27 extension_id_(extension_id),
[email protected]e2377032013-01-18 17:53:2228 delegate_(delegate),
29 parent_contents_(NULL),
[email protected]a97883a882014-05-13 11:49:2530 parent_window_(NULL),
rdevlin.cronin41593052016-01-08 01:40:1231 extension_registry_observer_(this),
32 weak_ptr_factory_(this) {}
[email protected]764bc252013-01-08 03:19:0333
34ExtensionEnableFlow::~ExtensionEnableFlow() {
35}
36
[email protected]e2377032013-01-18 17:53:2237void ExtensionEnableFlow::StartForWebContents(
38 content::WebContents* parent_contents) {
39 parent_contents_ = parent_contents;
40 parent_window_ = NULL;
41 Run();
42}
43
44void ExtensionEnableFlow::StartForNativeWindow(
45 gfx::NativeWindow parent_window) {
46 parent_contents_ = NULL;
47 parent_window_ = parent_window;
48 Run();
49}
50
[email protected]50736a12013-09-26 08:58:3451void ExtensionEnableFlow::StartForCurrentlyNonexistentWindow(
52 base::Callback<gfx::NativeWindow(void)> window_getter) {
53 window_getter_ = window_getter;
54 Run();
55}
56
[email protected]e2377032013-01-18 17:53:2257void ExtensionEnableFlow::Run() {
[email protected]764bc252013-01-08 03:19:0358 ExtensionService* service =
59 extensions::ExtensionSystem::Get(profile_)->extension_service();
60 const Extension* extension = service->GetExtensionById(extension_id_, true);
61 if (!extension) {
[email protected]e066da32014-03-26 18:27:3562 extension = extensions::ExtensionRegistry::Get(profile_)->GetExtensionById(
63 extension_id_, extensions::ExtensionRegistry::TERMINATED);
[email protected]764bc252013-01-08 03:19:0364 // It's possible (though unlikely) the app could have been uninstalled since
65 // the user clicked on it.
66 if (!extension)
67 return;
[email protected]7b1e364a2013-08-09 15:36:1268 // If the app was terminated, reload it first.
[email protected]764bc252013-01-08 03:19:0369 service->ReloadExtension(extension_id_);
[email protected]7b1e364a2013-08-09 15:36:1270
71 // ReloadExtension reallocates the Extension object.
[email protected]764bc252013-01-08 03:19:0372 extension = service->GetExtensionById(extension_id_, true);
[email protected]7b1e364a2013-08-09 15:36:1273
74 // |extension| could be NULL for asynchronous load, such as the case of
75 // an unpacked extension. Wait for the load to continue the flow.
76 if (!extension) {
77 StartObserving();
78 return;
79 }
80 }
81
82 CheckPermissionAndMaybePromptUser();
83}
84
85void ExtensionEnableFlow::CheckPermissionAndMaybePromptUser() {
86 ExtensionService* service =
87 extensions::ExtensionSystem::Get(profile_)->extension_service();
88 const Extension* extension = service->GetExtensionById(extension_id_, true);
89 if (!extension) {
90 delegate_->ExtensionEnableFlowAborted(false); // |delegate_| may delete us.
91 return;
[email protected]764bc252013-01-08 03:19:0392 }
93
treibbb9a1962015-02-25 13:40:5994 // Supervised users can't re-enable custodian-installed extensions.
95 if (extensions::util::IsExtensionSupervised(extension, profile_)) {
96 delegate_->ExtensionEnableFlowAborted(false); // |delegate_| may delete us.
97 return;
98 }
99
bcwhite3c35a602015-06-19 14:14:00100 if (profiles::IsProfileLocked(profile_->GetPath())) {
mlerman9ccf2d82015-03-31 10:46:29101 UserManager::Show(base::FilePath(),
102 profiles::USER_MANAGER_NO_TUTORIAL,
103 profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER);
104 return;
105 }
106
[email protected]7c82539c2014-02-19 06:09:17107 extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
108 if (!prefs->DidExtensionEscalatePermissions(extension_id_)) {
[email protected]764bc252013-01-08 03:19:03109 // Enable the extension immediately if its privileges weren't escalated.
110 // This is a no-op if the extension was previously terminated.
111 service->EnableExtension(extension_id_);
112
113 delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us.
114 return;
115 }
116
[email protected]e2377032013-01-18 17:53:22117 CreatePrompt();
rdevlin.croninf84cab72015-12-12 03:45:23118 ExtensionInstallPrompt::PromptType type =
119 ExtensionInstallPrompt::GetReEnablePromptTypeForExtension(profile_,
120 extension);
ricea34f96992016-08-31 10:14:30121 prompt_->ShowDialog(base::Bind(&ExtensionEnableFlow::InstallPromptDone,
122 weak_ptr_factory_.GetWeakPtr()),
123 extension, nullptr,
124 base::MakeUnique<ExtensionInstallPrompt::Prompt>(type),
125 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
[email protected]764bc252013-01-08 03:19:03126}
127
[email protected]e2377032013-01-18 17:53:22128void ExtensionEnableFlow::CreatePrompt() {
[email protected]50736a12013-09-26 08:58:34129 if (!window_getter_.is_null())
130 parent_window_ = window_getter_.Run();
[email protected]e2377032013-01-18 17:53:22131 prompt_.reset(parent_contents_ ?
132 new ExtensionInstallPrompt(parent_contents_) :
pkotwicz2175c622014-10-22 19:56:28133 new ExtensionInstallPrompt(profile_, parent_window_));
[email protected]e2377032013-01-18 17:53:22134}
135
[email protected]7b1e364a2013-08-09 15:36:12136void ExtensionEnableFlow::StartObserving() {
[email protected]a97883a882014-05-13 11:49:25137 extension_registry_observer_.Add(
138 extensions::ExtensionRegistry::Get(profile_));
[email protected]adf5a102014-07-31 12:44:06139 registrar_.Add(this,
140 extensions::NOTIFICATION_EXTENSION_LOAD_ERROR,
[email protected]7b1e364a2013-08-09 15:36:12141 content::Source<Profile>(profile_));
[email protected]7b1e364a2013-08-09 15:36:12142}
143
144void ExtensionEnableFlow::StopObserving() {
145 registrar_.RemoveAll();
[email protected]0a87b8d42014-06-04 12:44:53146 extension_registry_observer_.RemoveAll();
[email protected]7b1e364a2013-08-09 15:36:12147}
148
149void ExtensionEnableFlow::Observe(int type,
150 const content::NotificationSource& source,
151 const content::NotificationDetails& details) {
[email protected]adf5a102014-07-31 12:44:06152 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR, type);
[email protected]0a87b8d42014-06-04 12:44:53153 StopObserving();
154 delegate_->ExtensionEnableFlowAborted(false);
[email protected]7b1e364a2013-08-09 15:36:12155}
156
[email protected]a97883a882014-05-13 11:49:25157void ExtensionEnableFlow::OnExtensionLoaded(
158 content::BrowserContext* browser_context,
159 const Extension* extension) {
160 if (extension->id() == extension_id_) {
161 StopObserving();
162 CheckPermissionAndMaybePromptUser();
163 }
164}
165
[email protected]0a87b8d42014-06-04 12:44:53166void ExtensionEnableFlow::OnExtensionUninstalled(
167 content::BrowserContext* browser_context,
[email protected]e43c61f2014-07-20 21:46:34168 const Extension* extension,
169 extensions::UninstallReason reason) {
[email protected]0a87b8d42014-06-04 12:44:53170 if (extension->id() == extension_id_) {
171 StopObserving();
172 delegate_->ExtensionEnableFlowAborted(false);
173 }
174}
175
rdevlin.cronin41593052016-01-08 01:40:12176void ExtensionEnableFlow::InstallPromptDone(
177 ExtensionInstallPrompt::Result result) {
178 if (result == ExtensionInstallPrompt::Result::ACCEPTED) {
179 ExtensionService* service =
180 extensions::ExtensionSystem::Get(profile_)->extension_service();
[email protected]764bc252013-01-08 03:19:03181
rdevlin.cronin41593052016-01-08 01:40:12182 // The extension can be uninstalled in another window while the UI was
183 // showing. Treat it as a cancellation and notify |delegate_|.
184 const Extension* extension = service->GetExtensionById(extension_id_, true);
185 if (!extension) {
186 delegate_->ExtensionEnableFlowAborted(true);
187 return;
188 }
189
190 service->GrantPermissionsAndEnableExtension(extension);
191 delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us.
192 } else {
193 delegate_->ExtensionEnableFlowAborted(
194 result == ExtensionInstallPrompt::Result::USER_CANCELED);
195 // |delegate_| may delete us.
[email protected]e2377032013-01-18 17:53:22196 }
[email protected]764bc252013-01-08 03:19:03197}