NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / extensions / unpacked_installer.cc
blobec4b96b6e4e43ad517b1e8ec9050d95385d6c946
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_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;
32 namespace {
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 {
39 public:
40 SimpleExtensionLoadPrompt(const Extension* extension,
41 Profile* profile,
42 const base::Closure& callback);
43 virtual ~SimpleExtensionLoadPrompt();
45 void ShowPrompt();
47 // ExtensionInstallUI::Delegate
48 virtual void InstallUIProceed() OVERRIDE;
49 virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
51 private:
52 scoped_ptr<ExtensionInstallPrompt> install_ui_;
53 scoped_refptr<const Extension> extension_;
54 base::Closure callback_;
57 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
58 const Extension* extension,
59 Profile* profile,
60 const base::Closure& callback)
61 : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
62 profile)),
63 extension_(extension),
64 callback_(callback) {
67 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
70 void SimpleExtensionLoadPrompt::ShowPrompt() {
71 install_ui_->ConfirmInstall(
72 this,
73 extension_.get(),
74 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
77 void SimpleExtensionLoadPrompt::InstallUIProceed() {
78 callback_.Run();
79 delete this;
82 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
83 delete this;
86 } // namespace
88 namespace extensions {
90 // static
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(
115 BrowserThread::FILE,
116 FROM_HERE,
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())
126 return false;
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);
135 return false;
138 std::string error;
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(
144 extension_path_,
145 installer_.extension()->manifest()->value(),
146 &error)) {
147 ReportExtensionLoadError(error);
148 return false;
151 ShowInstallPrompt();
153 *extension_id = installer_.extension()->id();
154 return true;
157 void UnpackedInstaller::ShowInstallPrompt() {
158 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
159 if (!service_weak_.get())
160 return;
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();
172 return;
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, ' '));
188 return;
191 ConfirmInstall();
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;
208 return result;
211 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
212 if (!service_weak_.get())
213 return true;
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_);
225 std::string error;
226 if (!extension_file_util::CheckForIllegalFilenames(extension_path_,
227 &error)) {
228 BrowserThread::PostTask(
229 BrowserThread::UI,
230 FROM_HERE,
231 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
232 return;
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())
242 return;
244 if (!IsLoadingUnpackedAllowed()) {
245 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
246 return;
249 BrowserThread::PostTask(
250 BrowserThread::FILE,
251 FROM_HERE,
252 base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
255 void UnpackedInstaller::LoadWithFileAccess(int flags) {
256 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
258 std::string error;
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(
264 extension_path_,
265 installer_.extension()->manifest()->value(),
266 &error)) {
267 BrowserThread::PostTask(
268 BrowserThread::UI,
269 FROM_HERE,
270 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
271 return;
274 BrowserThread::PostTask(
275 BrowserThread::UI,
276 FROM_HERE,
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())
283 return;
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));
292 return;
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 */,
302 NOT_BLACKLISTED,
303 false /* don't wait for idle */);
306 } // namespace extensions