Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / unpacked_installer.cc
blobb23e0188e15651df21797d1dc5baaf4bf002c15d
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/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;
30 namespace {
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 {
37 public:
38 SimpleExtensionLoadPrompt(const Extension* extension,
39 Profile* profile,
40 const base::Closure& callback);
41 virtual ~SimpleExtensionLoadPrompt();
43 void ShowPrompt();
45 // ExtensionInstallUI::Delegate
46 virtual void InstallUIProceed() OVERRIDE;
47 virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
49 private:
50 scoped_ptr<ExtensionInstallPrompt> install_ui_;
51 scoped_refptr<const Extension> extension_;
52 base::Closure callback_;
55 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
56 const Extension* extension,
57 Profile* profile,
58 const base::Closure& callback)
59 : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
60 profile)),
61 extension_(extension),
62 callback_(callback) {
65 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
68 void SimpleExtensionLoadPrompt::ShowPrompt() {
69 install_ui_->ConfirmInstall(
70 this,
71 extension_.get(),
72 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
75 void SimpleExtensionLoadPrompt::InstallUIProceed() {
76 callback_.Run();
77 delete this;
80 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
81 delete this;
84 } // namespace
86 namespace extensions {
88 // static
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(
113 BrowserThread::FILE,
114 FROM_HERE,
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())
124 return false;
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);
133 return false;
136 std::string error;
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(
142 extension_path_,
143 installer_.extension()->manifest()->value(),
144 &error)) {
145 ReportExtensionLoadError(error);
146 return false;
149 ShowInstallPrompt();
151 *extension_id = installer_.extension()->id();
152 return true;
155 void UnpackedInstaller::ShowInstallPrompt() {
156 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
157 if (!service_weak_.get())
158 return;
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();
170 return;
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, ' '));
186 return;
189 ConfirmInstall();
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;
206 return result;
209 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
210 if (!service_weak_.get())
211 return true;
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_);
223 std::string error;
224 if (!extension_file_util::CheckForIllegalFilenames(extension_path_,
225 &error)) {
226 BrowserThread::PostTask(
227 BrowserThread::UI,
228 FROM_HERE,
229 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
230 return;
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())
240 return;
242 if (!IsLoadingUnpackedAllowed()) {
243 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
244 return;
247 BrowserThread::PostTask(
248 BrowserThread::FILE,
249 FROM_HERE,
250 base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
253 void UnpackedInstaller::LoadWithFileAccess(int flags) {
254 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
256 std::string error;
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(
262 extension_path_,
263 installer_.extension()->manifest()->value(),
264 &error)) {
265 BrowserThread::PostTask(
266 BrowserThread::UI,
267 FROM_HERE,
268 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
269 return;
272 BrowserThread::PostTask(
273 BrowserThread::UI,
274 FROM_HERE,
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())
281 return;
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));
290 return;
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 */,
300 NOT_BLACKLISTED,
301 false /* don't wait for idle */);
304 } // namespace extensions