1 // Copyright (c) 2013 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 "chrome/browser/extensions/unpacked_installer.h"
8 #include "base/callback.h"
9 #include "base/file_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "chrome/browser/extensions/extension_install_prompt.h"
14 #include "chrome/browser/extensions/extension_install_ui.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/permissions_updater.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
19 #include "chrome/common/extensions/extension_file_util.h"
20 #include "chrome/common/extensions/extension_l10n_util.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/common/extension.h"
25 #include "extensions/common/id_util.h"
26 #include "extensions/common/manifest.h"
27 #include "sync/api/string_ordinal.h"
29 using content::BrowserThread
;
30 using extensions::Extension
;
34 const char kUnpackedExtensionsBlacklistedError
[] =
35 "Loading of unpacked extensions is disabled by the administrator.";
37 // Manages an ExtensionInstallPrompt for a particular extension.
38 class SimpleExtensionLoadPrompt
: public ExtensionInstallPrompt::Delegate
{
40 SimpleExtensionLoadPrompt(const Extension
* extension
,
42 const base::Closure
& callback
);
43 virtual ~SimpleExtensionLoadPrompt();
47 // ExtensionInstallUI::Delegate
48 virtual void InstallUIProceed() OVERRIDE
;
49 virtual void InstallUIAbort(bool user_initiated
) OVERRIDE
;
52 scoped_ptr
<ExtensionInstallPrompt
> install_ui_
;
53 scoped_refptr
<const Extension
> extension_
;
54 base::Closure callback_
;
57 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
58 const Extension
* extension
,
60 const base::Closure
& callback
)
61 : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
63 extension_(extension
),
67 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
70 void SimpleExtensionLoadPrompt::ShowPrompt() {
71 install_ui_
->ConfirmInstall(
74 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
77 void SimpleExtensionLoadPrompt::InstallUIProceed() {
82 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated
) {
88 namespace extensions
{
91 scoped_refptr
<UnpackedInstaller
> UnpackedInstaller::Create(
92 ExtensionService
* extension_service
) {
93 DCHECK(extension_service
);
94 return scoped_refptr
<UnpackedInstaller
>(
95 new UnpackedInstaller(extension_service
));
98 UnpackedInstaller::UnpackedInstaller(ExtensionService
* extension_service
)
99 : service_weak_(extension_service
->AsWeakPtr()),
100 prompt_for_plugins_(true),
101 require_modern_manifest_version_(true),
102 installer_(extension_service
->profile()) {
103 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
106 UnpackedInstaller::~UnpackedInstaller() {
107 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
) ||
108 BrowserThread::CurrentlyOn(BrowserThread::FILE));
111 void UnpackedInstaller::Load(const base::FilePath
& path_in
) {
112 DCHECK(extension_path_
.empty());
113 extension_path_
= path_in
;
114 BrowserThread::PostTask(
117 base::Bind(&UnpackedInstaller::GetAbsolutePath
, this));
120 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath
& path_in
,
121 std::string
* extension_id
) {
122 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
123 DCHECK(extension_path_
.empty());
125 if (!service_weak_
.get())
127 // Load extensions from the command line synchronously to avoid a race
128 // between extension loading and loading an URL from the command line.
129 base::ThreadRestrictions::ScopedAllowIO allow_io
;
131 extension_path_
= base::MakeAbsoluteFilePath(path_in
);
133 if (!IsLoadingUnpackedAllowed()) {
134 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError
);
139 installer_
.set_extension(extension_file_util::LoadExtension(
140 extension_path_
, Manifest::COMMAND_LINE
, GetFlags(), &error
).get());
142 if (!installer_
.extension().get() ||
143 !extension_l10n_util::ValidateExtensionLocales(
145 installer_
.extension()->manifest()->value(),
147 ReportExtensionLoadError(error
);
153 *extension_id
= installer_
.extension()->id();
157 void UnpackedInstaller::ShowInstallPrompt() {
158 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
159 if (!service_weak_
.get())
162 const ExtensionSet
& disabled_extensions
=
163 ExtensionRegistry::Get(service_weak_
->profile())->disabled_extensions();
164 if (service_weak_
->show_extensions_prompts() && prompt_for_plugins_
&&
165 PluginInfo::HasPlugins(installer_
.extension().get()) &&
166 !disabled_extensions
.Contains(installer_
.extension()->id())) {
167 SimpleExtensionLoadPrompt
* prompt
= new SimpleExtensionLoadPrompt(
168 installer_
.extension().get(),
169 installer_
.profile(),
170 base::Bind(&UnpackedInstaller::CallCheckRequirements
, this));
171 prompt
->ShowPrompt();
174 CallCheckRequirements();
177 void UnpackedInstaller::CallCheckRequirements() {
178 installer_
.CheckRequirements(
179 base::Bind(&UnpackedInstaller::OnRequirementsChecked
, this));
182 void UnpackedInstaller::OnRequirementsChecked(
183 std::vector
<std::string
> requirement_errors
) {
184 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
186 if (!requirement_errors
.empty()) {
187 ReportExtensionLoadError(JoinString(requirement_errors
, ' '));
194 int UnpackedInstaller::GetFlags() {
195 std::string id
= id_util::GenerateIdForPath(extension_path_
);
196 bool allow_file_access
=
197 Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED
);
198 ExtensionPrefs
* prefs
= service_weak_
->extension_prefs();
199 if (prefs
->HasAllowFileAccessSetting(id
))
200 allow_file_access
= prefs
->AllowFileAccess(id
);
202 int result
= Extension::FOLLOW_SYMLINKS_ANYWHERE
;
203 if (allow_file_access
)
204 result
|= Extension::ALLOW_FILE_ACCESS
;
205 if (require_modern_manifest_version_
)
206 result
|= Extension::REQUIRE_MODERN_MANIFEST_VERSION
;
211 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
212 if (!service_weak_
.get())
214 // If there is a "*" in the extension blacklist, then no extensions should be
215 // allowed at all (except explicitly whitelisted extensions).
216 ExtensionPrefs
* prefs
= service_weak_
->extension_prefs();
217 return !prefs
->ExtensionsBlacklistedByDefault();
220 void UnpackedInstaller::GetAbsolutePath() {
221 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
223 extension_path_
= base::MakeAbsoluteFilePath(extension_path_
);
226 if (!extension_file_util::CheckForIllegalFilenames(extension_path_
,
228 BrowserThread::PostTask(
231 base::Bind(&UnpackedInstaller::ReportExtensionLoadError
, this, error
));
234 BrowserThread::PostTask(
235 BrowserThread::UI
, FROM_HERE
,
236 base::Bind(&UnpackedInstaller::CheckExtensionFileAccess
, this));
239 void UnpackedInstaller::CheckExtensionFileAccess() {
240 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
241 if (!service_weak_
.get())
244 if (!IsLoadingUnpackedAllowed()) {
245 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError
);
249 BrowserThread::PostTask(
252 base::Bind(&UnpackedInstaller::LoadWithFileAccess
, this, GetFlags()));
255 void UnpackedInstaller::LoadWithFileAccess(int flags
) {
256 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
259 installer_
.set_extension(extension_file_util::LoadExtension(
260 extension_path_
, Manifest::UNPACKED
, flags
, &error
).get());
262 if (!installer_
.extension().get() ||
263 !extension_l10n_util::ValidateExtensionLocales(
265 installer_
.extension()->manifest()->value(),
267 BrowserThread::PostTask(
270 base::Bind(&UnpackedInstaller::ReportExtensionLoadError
, this, error
));
274 BrowserThread::PostTask(
277 base::Bind(&UnpackedInstaller::ShowInstallPrompt
, this));
280 void UnpackedInstaller::ReportExtensionLoadError(const std::string
&error
) {
281 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
282 if (!service_weak_
.get())
284 service_weak_
->ReportExtensionLoadError(extension_path_
, error
, true);
287 void UnpackedInstaller::ConfirmInstall() {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
289 base::string16 error
= installer_
.CheckManagementPolicy();
290 if (!error
.empty()) {
291 ReportExtensionLoadError(base::UTF16ToUTF8(error
));
295 PermissionsUpdater
perms_updater(service_weak_
->profile());
296 perms_updater
.GrantActivePermissions(installer_
.extension().get());
298 service_weak_
->OnExtensionInstalled(
299 installer_
.extension().get(),
300 syncer::StringOrdinal(),
301 false /* no requirement errors */,
303 false /* don't wait for idle */);
306 } // namespace extensions