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_prefs.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/permissions_updater.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/common/extension.h"
23 #include "extensions/common/id_util.h"
24 #include "extensions/common/manifest.h"
25 #include "sync/api/string_ordinal.h"
27 using content::BrowserThread
;
28 using extensions::Extension
;
32 const char kUnpackedExtensionsBlacklistedError
[] =
33 "Loading of unpacked extensions is disabled by the administrator.";
35 // Manages an ExtensionInstallPrompt for a particular extension.
36 class SimpleExtensionLoadPrompt
: public ExtensionInstallPrompt::Delegate
{
38 SimpleExtensionLoadPrompt(const Extension
* extension
,
40 const base::Closure
& callback
);
41 virtual ~SimpleExtensionLoadPrompt();
45 // ExtensionInstallUI::Delegate
46 virtual void InstallUIProceed() OVERRIDE
;
47 virtual void InstallUIAbort(bool user_initiated
) OVERRIDE
;
50 scoped_ptr
<ExtensionInstallPrompt
> install_ui_
;
51 scoped_refptr
<const Extension
> extension_
;
52 base::Closure callback_
;
55 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
56 const Extension
* extension
,
58 const base::Closure
& callback
)
59 : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
61 extension_(extension
),
65 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
68 void SimpleExtensionLoadPrompt::ShowPrompt() {
69 install_ui_
->ConfirmInstall(
72 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
75 void SimpleExtensionLoadPrompt::InstallUIProceed() {
80 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated
) {
86 namespace extensions
{
89 scoped_refptr
<UnpackedInstaller
> UnpackedInstaller::Create(
90 ExtensionService
* extension_service
) {
91 DCHECK(extension_service
);
92 return scoped_refptr
<UnpackedInstaller
>(
93 new UnpackedInstaller(extension_service
));
96 UnpackedInstaller::UnpackedInstaller(ExtensionService
* extension_service
)
97 : service_weak_(extension_service
->AsWeakPtr()),
98 prompt_for_plugins_(true),
99 require_modern_manifest_version_(true),
100 installer_(extension_service
->profile()) {
101 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
104 UnpackedInstaller::~UnpackedInstaller() {
105 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
) ||
106 BrowserThread::CurrentlyOn(BrowserThread::FILE));
109 void UnpackedInstaller::Load(const base::FilePath
& path_in
) {
110 DCHECK(extension_path_
.empty());
111 extension_path_
= path_in
;
112 BrowserThread::PostTask(
115 base::Bind(&UnpackedInstaller::GetAbsolutePath
, this));
118 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath
& path_in
,
119 std::string
* extension_id
) {
120 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
121 DCHECK(extension_path_
.empty());
123 if (!service_weak_
.get())
125 // Load extensions from the command line synchronously to avoid a race
126 // between extension loading and loading an URL from the command line.
127 base::ThreadRestrictions::ScopedAllowIO allow_io
;
129 extension_path_
= base::MakeAbsoluteFilePath(path_in
);
131 if (!IsLoadingUnpackedAllowed()) {
132 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError
);
137 installer_
.set_extension(extension_file_util::LoadExtension(
138 extension_path_
, Manifest::COMMAND_LINE
, GetFlags(), &error
).get());
140 if (!installer_
.extension().get() ||
141 !extension_l10n_util::ValidateExtensionLocales(
143 installer_
.extension()->manifest()->value(),
145 ReportExtensionLoadError(error
);
151 *extension_id
= installer_
.extension()->id();
155 void UnpackedInstaller::ShowInstallPrompt() {
156 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
157 if (!service_weak_
.get())
160 const ExtensionSet
* disabled_extensions
=
161 service_weak_
->disabled_extensions();
162 if (service_weak_
->show_extensions_prompts() && prompt_for_plugins_
&&
163 PluginInfo::HasPlugins(installer_
.extension().get()) &&
164 !disabled_extensions
->Contains(installer_
.extension()->id())) {
165 SimpleExtensionLoadPrompt
* prompt
= new SimpleExtensionLoadPrompt(
166 installer_
.extension().get(),
167 installer_
.profile(),
168 base::Bind(&UnpackedInstaller::CallCheckRequirements
, this));
169 prompt
->ShowPrompt();
172 CallCheckRequirements();
175 void UnpackedInstaller::CallCheckRequirements() {
176 installer_
.CheckRequirements(
177 base::Bind(&UnpackedInstaller::OnRequirementsChecked
, this));
180 void UnpackedInstaller::OnRequirementsChecked(
181 std::vector
<std::string
> requirement_errors
) {
182 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
184 if (!requirement_errors
.empty()) {
185 ReportExtensionLoadError(JoinString(requirement_errors
, ' '));
192 int UnpackedInstaller::GetFlags() {
193 std::string id
= id_util::GenerateIdForPath(extension_path_
);
194 bool allow_file_access
=
195 Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED
);
196 ExtensionPrefs
* prefs
= service_weak_
->extension_prefs();
197 if (prefs
->HasAllowFileAccessSetting(id
))
198 allow_file_access
= prefs
->AllowFileAccess(id
);
200 int result
= Extension::FOLLOW_SYMLINKS_ANYWHERE
;
201 if (allow_file_access
)
202 result
|= Extension::ALLOW_FILE_ACCESS
;
203 if (require_modern_manifest_version_
)
204 result
|= Extension::REQUIRE_MODERN_MANIFEST_VERSION
;
209 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
210 if (!service_weak_
.get())
212 // If there is a "*" in the extension blacklist, then no extensions should be
213 // allowed at all (except explicitly whitelisted extensions).
214 ExtensionPrefs
* prefs
= service_weak_
->extension_prefs();
215 return !prefs
->ExtensionsBlacklistedByDefault();
218 void UnpackedInstaller::GetAbsolutePath() {
219 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
221 extension_path_
= base::MakeAbsoluteFilePath(extension_path_
);
224 if (!extension_file_util::CheckForIllegalFilenames(extension_path_
,
226 BrowserThread::PostTask(
229 base::Bind(&UnpackedInstaller::ReportExtensionLoadError
, this, error
));
232 BrowserThread::PostTask(
233 BrowserThread::UI
, FROM_HERE
,
234 base::Bind(&UnpackedInstaller::CheckExtensionFileAccess
, this));
237 void UnpackedInstaller::CheckExtensionFileAccess() {
238 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
239 if (!service_weak_
.get())
242 if (!IsLoadingUnpackedAllowed()) {
243 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError
);
247 BrowserThread::PostTask(
250 base::Bind(&UnpackedInstaller::LoadWithFileAccess
, this, GetFlags()));
253 void UnpackedInstaller::LoadWithFileAccess(int flags
) {
254 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
257 installer_
.set_extension(extension_file_util::LoadExtension(
258 extension_path_
, Manifest::UNPACKED
, flags
, &error
).get());
260 if (!installer_
.extension().get() ||
261 !extension_l10n_util::ValidateExtensionLocales(
263 installer_
.extension()->manifest()->value(),
265 BrowserThread::PostTask(
268 base::Bind(&UnpackedInstaller::ReportExtensionLoadError
, this, error
));
272 BrowserThread::PostTask(
275 base::Bind(&UnpackedInstaller::ShowInstallPrompt
, this));
278 void UnpackedInstaller::ReportExtensionLoadError(const std::string
&error
) {
279 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
280 if (!service_weak_
.get())
282 service_weak_
->ReportExtensionLoadError(extension_path_
, error
, true);
285 void UnpackedInstaller::ConfirmInstall() {
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
287 base::string16 error
= installer_
.CheckManagementPolicy();
288 if (!error
.empty()) {
289 ReportExtensionLoadError(base::UTF16ToUTF8(error
));
293 PermissionsUpdater
perms_updater(service_weak_
->profile());
294 perms_updater
.GrantActivePermissions(installer_
.extension().get());
296 service_weak_
->OnExtensionInstalled(
297 installer_
.extension().get(),
298 syncer::StringOrdinal(),
299 false /* no requirement errors */,
301 false /* don't wait for idle */);
304 } // namespace extensions