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/threading/thread_restrictions.h"
12 #include "chrome/browser/extensions/extension_error_reporter.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 "content/public/browser/browser_thread.h"
20 #include "extensions/browser/extension_prefs.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/install_flag.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_l10n_util.h"
25 #include "extensions/common/file_util.h"
26 #include "extensions/common/id_util.h"
27 #include "extensions/common/manifest.h"
28 #include "sync/api/string_ordinal.h"
30 using content::BrowserThread;
31 using extensions::Extension;
35 const char kUnpackedExtensionsBlacklistedError[] =
36 "Loading of unpacked extensions is disabled by the administrator.";
38 // Manages an ExtensionInstallPrompt for a particular extension.
39 class SimpleExtensionLoadPrompt : public ExtensionInstallPrompt::Delegate {
41 SimpleExtensionLoadPrompt(const Extension* extension,
43 const base::Closure& callback);
44 virtual ~SimpleExtensionLoadPrompt();
48 // ExtensionInstallUI::Delegate
49 virtual void InstallUIProceed() OVERRIDE;
50 virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
53 scoped_ptr<ExtensionInstallPrompt> install_ui_;
54 scoped_refptr<const Extension> extension_;
55 base::Closure callback_;
58 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
59 const Extension* extension,
61 const base::Closure& callback)
62 : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
64 extension_(extension),
68 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
71 void SimpleExtensionLoadPrompt::ShowPrompt() {
72 switch (ExtensionInstallPrompt::g_auto_confirm_for_tests) {
73 case ExtensionInstallPrompt::NONE:
74 install_ui_->ConfirmInstall(
77 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
79 case ExtensionInstallPrompt::ACCEPT:
82 case ExtensionInstallPrompt::CANCEL:
83 InstallUIAbort(false);
87 void SimpleExtensionLoadPrompt::InstallUIProceed() {
92 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
98 namespace extensions {
101 scoped_refptr<UnpackedInstaller> UnpackedInstaller::Create(
102 ExtensionService* extension_service) {
103 DCHECK(extension_service);
104 return scoped_refptr<UnpackedInstaller>(
105 new UnpackedInstaller(extension_service));
108 UnpackedInstaller::UnpackedInstaller(ExtensionService* extension_service)
109 : service_weak_(extension_service->AsWeakPtr()),
110 prompt_for_plugins_(true),
111 require_modern_manifest_version_(true),
112 be_noisy_on_failure_(true),
113 install_checker_(extension_service->profile()) {
114 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117 UnpackedInstaller::~UnpackedInstaller() {
118 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
119 BrowserThread::CurrentlyOn(BrowserThread::FILE));
122 void UnpackedInstaller::Load(const base::FilePath& path_in) {
123 DCHECK(extension_path_.empty());
124 extension_path_ = path_in;
125 BrowserThread::PostTask(
128 base::Bind(&UnpackedInstaller::GetAbsolutePath, this));
131 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath& path_in,
132 std::string* extension_id) {
133 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
134 DCHECK(extension_path_.empty());
136 if (!service_weak_.get())
138 // Load extensions from the command line synchronously to avoid a race
139 // between extension loading and loading an URL from the command line.
140 base::ThreadRestrictions::ScopedAllowIO allow_io;
142 extension_path_ = base::MakeAbsoluteFilePath(path_in);
144 if (!IsLoadingUnpackedAllowed()) {
145 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
150 install_checker_.set_extension(
151 file_util::LoadExtension(
152 extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get());
155 !extension_l10n_util::ValidateExtensionLocales(
156 extension_path_, extension()->manifest()->value(), &error)) {
157 ReportExtensionLoadError(error);
163 *extension_id = extension()->id();
167 void UnpackedInstaller::ShowInstallPrompt() {
168 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169 if (!service_weak_.get())
172 const ExtensionSet& disabled_extensions =
173 ExtensionRegistry::Get(service_weak_->profile())->disabled_extensions();
174 if (service_weak_->show_extensions_prompts() && prompt_for_plugins_ &&
175 PluginInfo::HasPlugins(extension()) &&
176 !disabled_extensions.Contains(extension()->id())) {
177 SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
179 install_checker_.profile(),
180 base::Bind(&UnpackedInstaller::StartInstallChecks, this));
181 prompt->ShowPrompt();
184 StartInstallChecks();
187 void UnpackedInstaller::StartInstallChecks() {
188 install_checker_.Start(
189 ExtensionInstallChecker::CHECK_REQUIREMENTS |
190 ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY,
191 true /* fail fast */,
192 base::Bind(&UnpackedInstaller::OnInstallChecksComplete, this));
195 void UnpackedInstaller::OnInstallChecksComplete(int failed_checks) {
196 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
198 if (!install_checker_.policy_error().empty()) {
199 ReportExtensionLoadError(install_checker_.policy_error());
203 if (!install_checker_.requirement_errors().empty()) {
204 ReportExtensionLoadError(
205 JoinString(install_checker_.requirement_errors(), ' '));
212 int UnpackedInstaller::GetFlags() {
213 std::string id = id_util::GenerateIdForPath(extension_path_);
214 bool allow_file_access =
215 Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED);
216 ExtensionPrefs* prefs = ExtensionPrefs::Get(service_weak_->profile());
217 if (prefs->HasAllowFileAccessSetting(id))
218 allow_file_access = prefs->AllowFileAccess(id);
220 int result = Extension::FOLLOW_SYMLINKS_ANYWHERE;
221 if (allow_file_access)
222 result |= Extension::ALLOW_FILE_ACCESS;
223 if (require_modern_manifest_version_)
224 result |= Extension::REQUIRE_MODERN_MANIFEST_VERSION;
229 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
230 if (!service_weak_.get())
232 // If there is a "*" in the extension blacklist, then no extensions should be
233 // allowed at all (except explicitly whitelisted extensions).
234 ExtensionPrefs* prefs = ExtensionPrefs::Get(service_weak_->profile());
235 return !prefs->ExtensionsBlacklistedByDefault();
238 void UnpackedInstaller::GetAbsolutePath() {
239 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
241 extension_path_ = base::MakeAbsoluteFilePath(extension_path_);
244 if (!file_util::CheckForIllegalFilenames(extension_path_, &error)) {
245 BrowserThread::PostTask(
248 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
251 BrowserThread::PostTask(
252 BrowserThread::UI, FROM_HERE,
253 base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
256 void UnpackedInstaller::CheckExtensionFileAccess() {
257 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
258 if (!service_weak_.get())
261 if (!IsLoadingUnpackedAllowed()) {
262 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
266 BrowserThread::PostTask(
269 base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
272 void UnpackedInstaller::LoadWithFileAccess(int flags) {
273 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
276 install_checker_.set_extension(
277 file_util::LoadExtension(
278 extension_path_, Manifest::UNPACKED, flags, &error).get());
281 !extension_l10n_util::ValidateExtensionLocales(
282 extension_path_, extension()->manifest()->value(), &error)) {
283 BrowserThread::PostTask(
286 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
290 BrowserThread::PostTask(
293 base::Bind(&UnpackedInstaller::ShowInstallPrompt, this));
296 void UnpackedInstaller::ReportExtensionLoadError(const std::string &error) {
297 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299 if (service_weak_.get()) {
300 ExtensionErrorReporter::GetInstance()->ReportLoadError(
303 service_weak_->profile(),
304 be_noisy_on_failure_);
308 void UnpackedInstaller::InstallExtension() {
309 DCHECK_CURRENTLY_ON(BrowserThread::UI);
311 PermissionsUpdater perms_updater(service_weak_->profile());
312 perms_updater.GrantActivePermissions(extension());
314 service_weak_->OnExtensionInstalled(
315 extension(), syncer::StringOrdinal(), kInstallFlagInstallImmediately);
318 } // namespace extensions