blob: 52de886631aa5029b2b6b15c49aff6590a16a733 [file] [log] [blame]
[email protected]098fa7a2013-03-08 22:11:171// Copyright (c) 2013 The Chromium Authors. All rights reserved.
[email protected]d8c8f25f2011-11-02 18:18:012// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/unpacked_installer.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/file_util.h"
[email protected]46acbf12013-06-10 18:43:4210#include "base/strings/string_util.h"
[email protected]99d21312013-05-14 15:51:1311#include "base/strings/utf_string_conversions.h"
[email protected]bebe1d02012-08-02 20:17:0912#include "base/threading/thread_restrictions.h"
[email protected]c82da8c42012-06-08 19:49:1113#include "chrome/browser/extensions/extension_install_prompt.h"
[email protected]00b38242012-07-18 18:43:2214#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]d8c8f25f2011-11-02 18:18:0115#include "chrome/browser/extensions/extension_prefs.h"
16#include "chrome/browser/extensions/extension_service.h"
[email protected]0d904312012-01-25 23:00:1617#include "chrome/browser/extensions/permissions_updater.h"
[email protected]098fa7a2013-03-08 22:11:1718#include "chrome/common/extensions/api/plugins/plugins_handler.h"
[email protected]d8c8f25f2011-11-02 18:18:0119#include "chrome/common/extensions/extension_file_util.h"
[email protected]557c7bd2013-09-18 21:51:2520#include "chrome/common/extensions/extension_l10n_util.h"
[email protected]79a60642012-10-20 21:03:1821#include "content/public/browser/browser_thread.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
[email protected]993da5e2013-03-23 21:25:1623#include "extensions/common/id_util.h"
[email protected]d42c11152013-08-22 19:36:3224#include "extensions/common/manifest.h"
[email protected]36b643212012-09-07 12:53:0025#include "sync/api/string_ordinal.h"
[email protected]d8c8f25f2011-11-02 18:18:0126
[email protected]545ab7a2011-11-03 14:54:2127using content::BrowserThread;
[email protected]1c321ee2012-05-21 03:02:3428using extensions::Extension;
[email protected]545ab7a2011-11-03 14:54:2129
[email protected]d8c8f25f2011-11-02 18:18:0130namespace {
31
[email protected]8e7b2cf42012-04-18 14:26:5832const char kUnpackedExtensionsBlacklistedError[] =
33 "Loading of unpacked extensions is disabled by the administrator.";
34
[email protected]c82da8c42012-06-08 19:49:1135// Manages an ExtensionInstallPrompt for a particular extension.
36class SimpleExtensionLoadPrompt : public ExtensionInstallPrompt::Delegate {
[email protected]d8c8f25f2011-11-02 18:18:0137 public:
[email protected]849749d2013-05-06 17:30:4538 SimpleExtensionLoadPrompt(const Extension* extension,
39 Profile* profile,
40 const base::Closure& callback);
[email protected]49aeab62013-02-07 02:53:1141 virtual ~SimpleExtensionLoadPrompt();
[email protected]d8c8f25f2011-11-02 18:18:0142
43 void ShowPrompt();
44
45 // ExtensionInstallUI::Delegate
[email protected]0d904312012-01-25 23:00:1646 virtual void InstallUIProceed() OVERRIDE;
47 virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
[email protected]d8c8f25f2011-11-02 18:18:0148
49 private:
[email protected]c82da8c42012-06-08 19:49:1150 scoped_ptr<ExtensionInstallPrompt> install_ui_;
[email protected]d8c8f25f2011-11-02 18:18:0151 scoped_refptr<const Extension> extension_;
[email protected]849749d2013-05-06 17:30:4552 base::Closure callback_;
[email protected]d8c8f25f2011-11-02 18:18:0153};
54
55SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
[email protected]849749d2013-05-06 17:30:4556 const Extension* extension,
[email protected]d8c8f25f2011-11-02 18:18:0157 Profile* profile,
[email protected]849749d2013-05-06 17:30:4558 const base::Closure& callback)
59 : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
60 profile)),
61 extension_(extension),
62 callback_(callback) {
[email protected]d8c8f25f2011-11-02 18:18:0163}
64
65SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
66}
67
68void SimpleExtensionLoadPrompt::ShowPrompt() {
[email protected]af6efb22012-10-12 02:23:0569 install_ui_->ConfirmInstall(
[email protected]849749d2013-05-06 17:30:4570 this,
[email protected]dc24976f2013-06-02 21:15:0971 extension_.get(),
[email protected]849749d2013-05-06 17:30:4572 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
[email protected]d8c8f25f2011-11-02 18:18:0173}
74
75void SimpleExtensionLoadPrompt::InstallUIProceed() {
[email protected]849749d2013-05-06 17:30:4576 callback_.Run();
[email protected]d8c8f25f2011-11-02 18:18:0177 delete this;
78}
79
80void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
81 delete this;
82}
83
84} // namespace
85
86namespace extensions {
87
88// static
89scoped_refptr<UnpackedInstaller> UnpackedInstaller::Create(
90 ExtensionService* extension_service) {
91 return scoped_refptr<UnpackedInstaller>(
92 new UnpackedInstaller(extension_service));
93}
94
95UnpackedInstaller::UnpackedInstaller(ExtensionService* extension_service)
96 : service_weak_(extension_service->AsWeakPtr()),
[email protected]b7462f32012-09-02 15:18:1297 prompt_for_plugins_(true),
[email protected]9d02fa12013-02-19 05:12:5798 require_modern_manifest_version_(true),
[email protected]849749d2013-05-06 17:30:4599 installer_(extension_service->profile()) {
[email protected]d8c8f25f2011-11-02 18:18:01100 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101}
102
103UnpackedInstaller::~UnpackedInstaller() {
104 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
105 BrowserThread::CurrentlyOn(BrowserThread::FILE));
106}
107
[email protected]650b2d52013-02-10 03:41:45108void UnpackedInstaller::Load(const base::FilePath& path_in) {
[email protected]98270432012-09-11 20:51:24109 DCHECK(extension_path_.empty());
[email protected]d8c8f25f2011-11-02 18:18:01110 extension_path_ = path_in;
[email protected]849749d2013-05-06 17:30:45111 BrowserThread::PostTask(
112 BrowserThread::FILE,
113 FROM_HERE,
[email protected]d8c8f25f2011-11-02 18:18:01114 base::Bind(&UnpackedInstaller::GetAbsolutePath, this));
115}
116
[email protected]2a69b942013-05-31 09:37:53117bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath& path_in,
118 std::string* extension_id) {
[email protected]98270432012-09-11 20:51:24119 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120 DCHECK(extension_path_.empty());
121
[email protected]e8dad9b2013-06-04 04:43:45122 if (!service_weak_.get())
[email protected]2a69b942013-05-31 09:37:53123 return false;
[email protected]d8c8f25f2011-11-02 18:18:01124 // Load extensions from the command line synchronously to avoid a race
125 // between extension loading and loading an URL from the command line.
126 base::ThreadRestrictions::ScopedAllowIO allow_io;
127
[email protected]15476932013-04-12 05:17:15128 extension_path_ = base::MakeAbsoluteFilePath(path_in);
[email protected]d8c8f25f2011-11-02 18:18:01129
[email protected]8e7b2cf42012-04-18 14:26:58130 if (!IsLoadingUnpackedAllowed()) {
131 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
[email protected]2a69b942013-05-31 09:37:53132 return false;
[email protected]8e7b2cf42012-04-18 14:26:58133 }
134
[email protected]d8c8f25f2011-11-02 18:18:01135 std::string error;
[email protected]849749d2013-05-06 17:30:45136 installer_.set_extension(extension_file_util::LoadExtension(
[email protected]cadac622013-06-11 16:46:36137 extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get());
[email protected]d8c8f25f2011-11-02 18:18:01138
[email protected]557c7bd2013-09-18 21:51:25139 if (!installer_.extension().get() ||
140 !extension_l10n_util::ValidateExtensionLocales(
141 extension_path_,
142 installer_.extension()->manifest()->value(),
143 &error)) {
[email protected]8e7b2cf42012-04-18 14:26:58144 ReportExtensionLoadError(error);
[email protected]2a69b942013-05-31 09:37:53145 return false;
[email protected]d8c8f25f2011-11-02 18:18:01146 }
147
[email protected]849749d2013-05-06 17:30:45148 ShowInstallPrompt();
[email protected]2a69b942013-05-31 09:37:53149
150 *extension_id = installer_.extension()->id();
151 return true;
[email protected]98270432012-09-11 20:51:24152}
153
[email protected]849749d2013-05-06 17:30:45154void UnpackedInstaller::ShowInstallPrompt() {
[email protected]98270432012-09-11 20:51:24155 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]e8dad9b2013-06-04 04:43:45156 if (!service_weak_.get())
[email protected]849749d2013-05-06 17:30:45157 return;
158
159 const ExtensionSet* disabled_extensions =
160 service_weak_->disabled_extensions();
[email protected]cadac622013-06-11 16:46:36161 if (service_weak_->show_extensions_prompts() && prompt_for_plugins_ &&
162 PluginInfo::HasPlugins(installer_.extension().get()) &&
[email protected]849749d2013-05-06 17:30:45163 !disabled_extensions->Contains(installer_.extension()->id())) {
164 SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
[email protected]cadac622013-06-11 16:46:36165 installer_.extension().get(),
[email protected]849749d2013-05-06 17:30:45166 installer_.profile(),
167 base::Bind(&UnpackedInstaller::CallCheckRequirements, this));
168 prompt->ShowPrompt();
169 return;
170 }
171 CallCheckRequirements();
172}
173
174void UnpackedInstaller::CallCheckRequirements() {
175 installer_.CheckRequirements(
[email protected]98270432012-09-11 20:51:24176 base::Bind(&UnpackedInstaller::OnRequirementsChecked, this));
177}
178
179void UnpackedInstaller::OnRequirementsChecked(
180 std::vector<std::string> requirement_errors) {
181 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
182
183 if (!requirement_errors.empty()) {
184 ReportExtensionLoadError(JoinString(requirement_errors, ' '));
185 return;
186 }
187
[email protected]849749d2013-05-06 17:30:45188 ConfirmInstall();
[email protected]d8c8f25f2011-11-02 18:18:01189}
190
[email protected]b7462f32012-09-02 15:18:12191int UnpackedInstaller::GetFlags() {
[email protected]993da5e2013-03-23 21:25:16192 std::string id = id_util::GenerateIdForPath(extension_path_);
[email protected]b7462f32012-09-02 15:18:12193 bool allow_file_access =
[email protected]12075d12013-02-27 05:38:05194 Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED);
[email protected]849749d2013-05-06 17:30:45195 ExtensionPrefs* prefs = service_weak_->extension_prefs();
196 if (prefs->HasAllowFileAccessSetting(id))
197 allow_file_access = prefs->AllowFileAccess(id);
[email protected]b7462f32012-09-02 15:18:12198
199 int result = Extension::FOLLOW_SYMLINKS_ANYWHERE;
200 if (allow_file_access)
201 result |= Extension::ALLOW_FILE_ACCESS;
202 if (require_modern_manifest_version_)
203 result |= Extension::REQUIRE_MODERN_MANIFEST_VERSION;
204
205 return result;
206}
207
[email protected]8e7b2cf42012-04-18 14:26:58208bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
[email protected]e8dad9b2013-06-04 04:43:45209 if (!service_weak_.get())
[email protected]8e7b2cf42012-04-18 14:26:58210 return true;
211 // If there is a "*" in the extension blacklist, then no extensions should be
212 // allowed at all (except explicitly whitelisted extensions).
[email protected]849749d2013-05-06 17:30:45213 ExtensionPrefs* prefs = service_weak_->extension_prefs();
214 return !prefs->ExtensionsBlacklistedByDefault();
[email protected]8e7b2cf42012-04-18 14:26:58215}
216
[email protected]d8c8f25f2011-11-02 18:18:01217void UnpackedInstaller::GetAbsolutePath() {
218 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
219
[email protected]15476932013-04-12 05:17:15220 extension_path_ = base::MakeAbsoluteFilePath(extension_path_);
[email protected]d8c8f25f2011-11-02 18:18:01221
[email protected]5ccca8ad2013-08-19 22:35:34222 std::string error;
223 if (!extension_file_util::CheckForIllegalFilenames(extension_path_,
224 &error)) {
225 BrowserThread::PostTask(
226 BrowserThread::UI,
227 FROM_HERE,
228 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
229 return;
230 }
[email protected]849749d2013-05-06 17:30:45231 BrowserThread::PostTask(
232 BrowserThread::UI, FROM_HERE,
[email protected]d8c8f25f2011-11-02 18:18:01233 base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
234}
235
236void UnpackedInstaller::CheckExtensionFileAccess() {
237 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]e8dad9b2013-06-04 04:43:45238 if (!service_weak_.get())
[email protected]8e7b2cf42012-04-18 14:26:58239 return;
240
241 if (!IsLoadingUnpackedAllowed()) {
242 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
243 return;
244 }
245
[email protected]849749d2013-05-06 17:30:45246 BrowserThread::PostTask(
247 BrowserThread::FILE,
248 FROM_HERE,
249 base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
[email protected]d8c8f25f2011-11-02 18:18:01250}
251
[email protected]b7462f32012-09-02 15:18:12252void UnpackedInstaller::LoadWithFileAccess(int flags) {
[email protected]d8c8f25f2011-11-02 18:18:01253 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]b7462f32012-09-02 15:18:12254
[email protected]d8c8f25f2011-11-02 18:18:01255 std::string error;
[email protected]849749d2013-05-06 17:30:45256 installer_.set_extension(extension_file_util::LoadExtension(
[email protected]cadac622013-06-11 16:46:36257 extension_path_, Manifest::UNPACKED, flags, &error).get());
[email protected]d8c8f25f2011-11-02 18:18:01258
[email protected]557c7bd2013-09-18 21:51:25259 if (!installer_.extension().get() ||
260 !extension_l10n_util::ValidateExtensionLocales(
261 extension_path_,
262 installer_.extension()->manifest()->value(),
263 &error)) {
[email protected]849749d2013-05-06 17:30:45264 BrowserThread::PostTask(
265 BrowserThread::UI,
266 FROM_HERE,
267 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
[email protected]d8c8f25f2011-11-02 18:18:01268 return;
269 }
270
[email protected]849749d2013-05-06 17:30:45271 BrowserThread::PostTask(
272 BrowserThread::UI,
273 FROM_HERE,
274 base::Bind(&UnpackedInstaller::ShowInstallPrompt, this));
[email protected]d8c8f25f2011-11-02 18:18:01275}
276
277void UnpackedInstaller::ReportExtensionLoadError(const std::string &error) {
278 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]e8dad9b2013-06-04 04:43:45279 if (!service_weak_.get())
[email protected]d8c8f25f2011-11-02 18:18:01280 return;
281 service_weak_->ReportExtensionLoadError(extension_path_, error, true);
282}
283
[email protected]849749d2013-05-06 17:30:45284void UnpackedInstaller::ConfirmInstall() {
285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
286 string16 error = installer_.CheckManagementPolicy();
287 if (!error.empty()) {
[email protected]99d21312013-05-14 15:51:13288 ReportExtensionLoadError(UTF16ToUTF8(error));
[email protected]d8c8f25f2011-11-02 18:18:01289 return;
[email protected]d8c8f25f2011-11-02 18:18:01290 }
[email protected]0d904312012-01-25 23:00:16291
292 PermissionsUpdater perms_updater(service_weak_->profile());
[email protected]cadac622013-06-11 16:46:36293 perms_updater.GrantActivePermissions(installer_.extension().get());
[email protected]9d02fa12013-02-19 05:12:57294
[email protected]9f3c8532013-07-31 19:52:07295 service_weak_->OnExtensionInstalled(
296 installer_.extension().get(),
297 syncer::StringOrdinal(),
298 false /* no requirement errors */,
299 Blacklist::NOT_BLACKLISTED,
300 false /* don't wait for idle */);
[email protected]d8c8f25f2011-11-02 18:18:01301}
302
303} // namespace extensions