app_list: Re-enable people search.
[chromium-blink-merge.git] / chrome / browser / extensions / unpacked_installer.cc
blob11a548702263917beb8db456ff6612d2843b3061
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"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/files/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_management.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/browser/ui/extensions/extension_install_ui_factory.h"
19 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
20 #include "components/crx_file/id_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/browser/install/extension_install_ui.h"
25 #include "extensions/browser/install_flag.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_l10n_util.h"
28 #include "extensions/common/file_util.h"
29 #include "extensions/common/manifest.h"
30 #include "extensions/common/manifest_handlers/shared_module_info.h"
31 #include "sync/api/string_ordinal.h"
33 using content::BrowserThread;
34 using extensions::Extension;
35 using extensions::SharedModuleInfo;
37 namespace {
39 const char kUnpackedExtensionsBlacklistedError[] =
40 "Loading of unpacked extensions is disabled by the administrator.";
42 const char kImportMinVersionNewer[] =
43 "'import' version requested is newer than what is installed.";
44 const char kImportMissing[] = "'import' extension is not installed.";
45 const char kImportNotSharedModule[] = "'import' is not a shared module.";
47 // Manages an ExtensionInstallPrompt for a particular extension.
48 class SimpleExtensionLoadPrompt : public ExtensionInstallPrompt::Delegate {
49 public:
50 SimpleExtensionLoadPrompt(const Extension* extension,
51 Profile* profile,
52 const base::Closure& callback);
53 ~SimpleExtensionLoadPrompt() override;
55 void ShowPrompt();
57 // ExtensionInstallUI::Delegate
58 void InstallUIProceed() override;
59 void InstallUIAbort(bool user_initiated) override;
61 private:
62 scoped_ptr<ExtensionInstallPrompt> install_ui_;
63 scoped_refptr<const Extension> extension_;
64 base::Closure callback_;
67 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
68 const Extension* extension,
69 Profile* profile,
70 const base::Closure& callback)
71 : extension_(extension), callback_(callback) {
72 scoped_ptr<extensions::ExtensionInstallUI> ui(
73 extensions::CreateExtensionInstallUI(profile));
74 install_ui_.reset(new ExtensionInstallPrompt(
75 profile, ui->GetDefaultInstallDialogParent()));
78 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
81 void SimpleExtensionLoadPrompt::ShowPrompt() {
82 switch (ExtensionInstallPrompt::g_auto_confirm_for_tests) {
83 case ExtensionInstallPrompt::NONE:
84 install_ui_->ConfirmInstall(
85 this,
86 extension_.get(),
87 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
88 break;
89 case ExtensionInstallPrompt::ACCEPT:
90 InstallUIProceed();
91 break;
92 case ExtensionInstallPrompt::CANCEL:
93 InstallUIAbort(false);
97 void SimpleExtensionLoadPrompt::InstallUIProceed() {
98 callback_.Run();
99 delete this;
102 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
103 delete this;
106 } // namespace
108 namespace extensions {
110 // static
111 scoped_refptr<UnpackedInstaller> UnpackedInstaller::Create(
112 ExtensionService* extension_service) {
113 DCHECK(extension_service);
114 return scoped_refptr<UnpackedInstaller>(
115 new UnpackedInstaller(extension_service));
118 UnpackedInstaller::UnpackedInstaller(ExtensionService* extension_service)
119 : service_weak_(extension_service->AsWeakPtr()),
120 prompt_for_plugins_(true),
121 require_modern_manifest_version_(true),
122 be_noisy_on_failure_(true),
123 install_checker_(extension_service->profile()) {
124 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
127 UnpackedInstaller::~UnpackedInstaller() {
128 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
129 BrowserThread::CurrentlyOn(BrowserThread::FILE));
132 void UnpackedInstaller::Load(const base::FilePath& path_in) {
133 DCHECK(extension_path_.empty());
134 extension_path_ = path_in;
135 BrowserThread::PostTask(
136 BrowserThread::FILE,
137 FROM_HERE,
138 base::Bind(&UnpackedInstaller::GetAbsolutePath, this));
141 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath& path_in,
142 std::string* extension_id) {
143 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144 DCHECK(extension_path_.empty());
146 if (!service_weak_.get())
147 return false;
148 // Load extensions from the command line synchronously to avoid a race
149 // between extension loading and loading an URL from the command line.
150 base::ThreadRestrictions::ScopedAllowIO allow_io;
152 extension_path_ = base::MakeAbsoluteFilePath(path_in);
154 if (!IsLoadingUnpackedAllowed()) {
155 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
156 return false;
159 std::string error;
160 install_checker_.set_extension(
161 file_util::LoadExtension(
162 extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get());
164 if (!extension() ||
165 !extension_l10n_util::ValidateExtensionLocales(
166 extension_path_, extension()->manifest()->value(), &error)) {
167 ReportExtensionLoadError(error);
168 return false;
171 PermissionsUpdater(
172 service_weak_->profile(), PermissionsUpdater::INIT_FLAG_TRANSIENT)
173 .InitializePermissions(extension());
174 ShowInstallPrompt();
176 *extension_id = extension()->id();
177 return true;
180 void UnpackedInstaller::ShowInstallPrompt() {
181 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
182 if (!service_weak_.get())
183 return;
185 const ExtensionSet& disabled_extensions =
186 ExtensionRegistry::Get(service_weak_->profile())->disabled_extensions();
187 if (service_weak_->show_extensions_prompts() && prompt_for_plugins_ &&
188 PluginInfo::HasPlugins(extension()) &&
189 !disabled_extensions.Contains(extension()->id())) {
190 SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
191 extension(),
192 install_checker_.profile(),
193 base::Bind(&UnpackedInstaller::StartInstallChecks, this));
194 prompt->ShowPrompt();
195 return;
197 StartInstallChecks();
200 void UnpackedInstaller::StartInstallChecks() {
201 // TODO(crbug.com/421128): Enable these checks all the time. The reason
202 // they are disabled for extensions loaded from the command-line is that
203 // installing unpacked extensions is asynchronous, but there can be
204 // dependencies between the extensions loaded by the command line.
205 if (extension()->manifest()->location() != Manifest::COMMAND_LINE) {
206 ExtensionService* service = service_weak_.get();
207 if (!service || service->browser_terminating())
208 return;
210 // TODO(crbug.com/420147): Move this code to a utility class to avoid
211 // duplication of SharedModuleService::CheckImports code.
212 if (SharedModuleInfo::ImportsModules(extension())) {
213 const std::vector<SharedModuleInfo::ImportInfo>& imports =
214 SharedModuleInfo::GetImports(extension());
215 std::vector<SharedModuleInfo::ImportInfo>::const_iterator i;
216 for (i = imports.begin(); i != imports.end(); ++i) {
217 Version version_required(i->minimum_version);
218 const Extension* imported_module =
219 service->GetExtensionById(i->extension_id, true);
220 if (!imported_module) {
221 ReportExtensionLoadError(kImportMissing);
222 return;
223 } else if (imported_module &&
224 !SharedModuleInfo::IsSharedModule(imported_module)) {
225 ReportExtensionLoadError(kImportNotSharedModule);
226 return;
227 } else if (imported_module && (version_required.IsValid() &&
228 imported_module->version()->CompareTo(
229 version_required) < 0)) {
230 ReportExtensionLoadError(kImportMinVersionNewer);
231 return;
237 install_checker_.Start(
238 ExtensionInstallChecker::CHECK_REQUIREMENTS |
239 ExtensionInstallChecker::CHECK_MANAGEMENT_POLICY,
240 true /* fail fast */,
241 base::Bind(&UnpackedInstaller::OnInstallChecksComplete, this));
244 void UnpackedInstaller::OnInstallChecksComplete(int failed_checks) {
245 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247 if (!install_checker_.policy_error().empty()) {
248 ReportExtensionLoadError(install_checker_.policy_error());
249 return;
252 if (!install_checker_.requirement_errors().empty()) {
253 ReportExtensionLoadError(
254 JoinString(install_checker_.requirement_errors(), ' '));
255 return;
258 InstallExtension();
261 int UnpackedInstaller::GetFlags() {
262 std::string id = crx_file::id_util::GenerateIdForPath(extension_path_);
263 bool allow_file_access =
264 Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED);
265 ExtensionPrefs* prefs = ExtensionPrefs::Get(service_weak_->profile());
266 if (prefs->HasAllowFileAccessSetting(id))
267 allow_file_access = prefs->AllowFileAccess(id);
269 int result = Extension::FOLLOW_SYMLINKS_ANYWHERE;
270 if (allow_file_access)
271 result |= Extension::ALLOW_FILE_ACCESS;
272 if (require_modern_manifest_version_)
273 result |= Extension::REQUIRE_MODERN_MANIFEST_VERSION;
275 return result;
278 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
279 if (!service_weak_.get())
280 return true;
281 // If there is a "*" in the extension blacklist, then no extensions should be
282 // allowed at all (except explicitly whitelisted extensions).
283 return !ExtensionManagementFactory::GetForBrowserContext(
284 service_weak_->profile())->BlacklistedByDefault();
287 void UnpackedInstaller::GetAbsolutePath() {
288 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
290 extension_path_ = base::MakeAbsoluteFilePath(extension_path_);
292 std::string error;
293 if (!file_util::CheckForIllegalFilenames(extension_path_, &error)) {
294 BrowserThread::PostTask(
295 BrowserThread::UI,
296 FROM_HERE,
297 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
298 return;
300 BrowserThread::PostTask(
301 BrowserThread::UI, FROM_HERE,
302 base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
305 void UnpackedInstaller::CheckExtensionFileAccess() {
306 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
307 if (!service_weak_.get())
308 return;
310 if (!IsLoadingUnpackedAllowed()) {
311 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
312 return;
315 BrowserThread::PostTask(
316 BrowserThread::FILE,
317 FROM_HERE,
318 base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
321 void UnpackedInstaller::LoadWithFileAccess(int flags) {
322 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
324 std::string error;
325 install_checker_.set_extension(
326 file_util::LoadExtension(
327 extension_path_, Manifest::UNPACKED, flags, &error).get());
329 if (!extension() ||
330 !extension_l10n_util::ValidateExtensionLocales(
331 extension_path_, extension()->manifest()->value(), &error)) {
332 BrowserThread::PostTask(
333 BrowserThread::UI,
334 FROM_HERE,
335 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
336 return;
339 BrowserThread::PostTask(
340 BrowserThread::UI,
341 FROM_HERE,
342 base::Bind(&UnpackedInstaller::ShowInstallPrompt, this));
345 void UnpackedInstaller::ReportExtensionLoadError(const std::string &error) {
346 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348 if (service_weak_.get()) {
349 ExtensionErrorReporter::GetInstance()->ReportLoadError(
350 extension_path_,
351 error,
352 service_weak_->profile(),
353 be_noisy_on_failure_);
357 void UnpackedInstaller::InstallExtension() {
358 DCHECK_CURRENTLY_ON(BrowserThread::UI);
360 PermissionsUpdater perms_updater(service_weak_->profile());
361 perms_updater.InitializePermissions(extension());
362 perms_updater.GrantActivePermissions(extension());
364 service_weak_->OnExtensionInstalled(
365 extension(), syncer::StringOrdinal(), kInstallFlagInstallImmediately);
368 } // namespace extensions