Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / unpacked_installer.cc
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.
4
5 #include "chrome/browser/extensions/unpacked_installer.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "chrome/browser/extensions/extension_error_reporter.h"
15 #include "chrome/browser/extensions/extension_install_prompt.h"
16 #include "chrome/browser/extensions/extension_install_ui.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/permissions_updater.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "extensions/browser/extension_prefs.h"
24 #include "extensions/browser/extension_registry.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/extension_l10n_util.h"
27 #include "extensions/common/file_util.h"
28 #include "extensions/common/id_util.h"
29 #include "extensions/common/manifest.h"
30 #include "sync/api/string_ordinal.h"
31
32 using content::BrowserThread;
33 using extensions::Extension;
34
35 namespace {
36
37 const char kUnpackedExtensionsBlacklistedError[] =
38     "Loading of unpacked extensions is disabled by the administrator.";
39
40 // Manages an ExtensionInstallPrompt for a particular extension.
41 class SimpleExtensionLoadPrompt : public ExtensionInstallPrompt::Delegate {
42  public:
43   SimpleExtensionLoadPrompt(const Extension* extension,
44                             Profile* profile,
45                             const base::Closure& callback);
46   virtual ~SimpleExtensionLoadPrompt();
47
48   void ShowPrompt();
49
50   // ExtensionInstallUI::Delegate
51   virtual void InstallUIProceed() OVERRIDE;
52   virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
53
54  private:
55   scoped_ptr<ExtensionInstallPrompt> install_ui_;
56   scoped_refptr<const Extension> extension_;
57   base::Closure callback_;
58 };
59
60 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
61     const Extension* extension,
62     Profile* profile,
63     const base::Closure& callback)
64     : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
65           profile)),
66       extension_(extension),
67       callback_(callback) {
68 }
69
70 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
71 }
72
73 void SimpleExtensionLoadPrompt::ShowPrompt() {
74   std::string confirm = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
75       switches::kAppsGalleryInstallAutoConfirmForTests);
76   if (confirm == "accept") {
77     InstallUIProceed();
78     return;
79   }
80   if (confirm == "cancel") {
81     InstallUIAbort(false);
82     return;
83   }
84
85   install_ui_->ConfirmInstall(
86       this,
87       extension_.get(),
88       ExtensionInstallPrompt::GetDefaultShowDialogCallback());
89 }
90
91 void SimpleExtensionLoadPrompt::InstallUIProceed() {
92   callback_.Run();
93   delete this;
94 }
95
96 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
97   delete this;
98 }
99
100 }  // namespace
101
102 namespace extensions {
103
104 // static
105 scoped_refptr<UnpackedInstaller> UnpackedInstaller::Create(
106     ExtensionService* extension_service) {
107   DCHECK(extension_service);
108   return scoped_refptr<UnpackedInstaller>(
109       new UnpackedInstaller(extension_service));
110 }
111
112 UnpackedInstaller::UnpackedInstaller(ExtensionService* extension_service)
113     : service_weak_(extension_service->AsWeakPtr()),
114       prompt_for_plugins_(true),
115       require_modern_manifest_version_(true),
116       be_noisy_on_failure_(true),
117       installer_(extension_service->profile()) {
118   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119 }
120
121 UnpackedInstaller::~UnpackedInstaller() {
122   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
123         BrowserThread::CurrentlyOn(BrowserThread::FILE));
124 }
125
126 void UnpackedInstaller::Load(const base::FilePath& path_in) {
127   DCHECK(extension_path_.empty());
128   extension_path_ = path_in;
129   BrowserThread::PostTask(
130       BrowserThread::FILE,
131       FROM_HERE,
132       base::Bind(&UnpackedInstaller::GetAbsolutePath, this));
133 }
134
135 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath& path_in,
136                                             std::string* extension_id) {
137   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
138   DCHECK(extension_path_.empty());
139
140   if (!service_weak_.get())
141     return false;
142   // Load extensions from the command line synchronously to avoid a race
143   // between extension loading and loading an URL from the command line.
144   base::ThreadRestrictions::ScopedAllowIO allow_io;
145
146   extension_path_ = base::MakeAbsoluteFilePath(path_in);
147
148   if (!IsLoadingUnpackedAllowed()) {
149     ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
150     return false;
151   }
152
153   std::string error;
154   installer_.set_extension(
155       file_util::LoadExtension(
156           extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get());
157
158   if (!installer_.extension().get() ||
159       !extension_l10n_util::ValidateExtensionLocales(
160           extension_path_,
161           installer_.extension()->manifest()->value(),
162           &error)) {
163     ReportExtensionLoadError(error);
164     return false;
165   }
166
167   ShowInstallPrompt();
168
169   *extension_id = installer_.extension()->id();
170   return true;
171 }
172
173 void UnpackedInstaller::ShowInstallPrompt() {
174   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175   if (!service_weak_.get())
176     return;
177
178   const ExtensionSet& disabled_extensions =
179       ExtensionRegistry::Get(service_weak_->profile())->disabled_extensions();
180   if (service_weak_->show_extensions_prompts() && prompt_for_plugins_ &&
181       PluginInfo::HasPlugins(installer_.extension().get()) &&
182       !disabled_extensions.Contains(installer_.extension()->id())) {
183     SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
184         installer_.extension().get(),
185         installer_.profile(),
186         base::Bind(&UnpackedInstaller::CallCheckRequirements, this));
187     prompt->ShowPrompt();
188     return;
189   }
190   CallCheckRequirements();
191 }
192
193 void UnpackedInstaller::CallCheckRequirements() {
194   installer_.CheckRequirements(
195       base::Bind(&UnpackedInstaller::OnRequirementsChecked, this));
196 }
197
198 void UnpackedInstaller::OnRequirementsChecked(
199     std::vector<std::string> requirement_errors) {
200   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
201
202   if (!requirement_errors.empty()) {
203     ReportExtensionLoadError(JoinString(requirement_errors, ' '));
204     return;
205   }
206
207   ConfirmInstall();
208 }
209
210 int UnpackedInstaller::GetFlags() {
211   std::string id = id_util::GenerateIdForPath(extension_path_);
212   bool allow_file_access =
213       Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED);
214   ExtensionPrefs* prefs = ExtensionPrefs::Get(service_weak_->profile());
215   if (prefs->HasAllowFileAccessSetting(id))
216     allow_file_access = prefs->AllowFileAccess(id);
217
218   int result = Extension::FOLLOW_SYMLINKS_ANYWHERE;
219   if (allow_file_access)
220     result |= Extension::ALLOW_FILE_ACCESS;
221   if (require_modern_manifest_version_)
222     result |= Extension::REQUIRE_MODERN_MANIFEST_VERSION;
223
224   return result;
225 }
226
227 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
228   if (!service_weak_.get())
229     return true;
230   // If there is a "*" in the extension blacklist, then no extensions should be
231   // allowed at all (except explicitly whitelisted extensions).
232   ExtensionPrefs* prefs = ExtensionPrefs::Get(service_weak_->profile());
233   return !prefs->ExtensionsBlacklistedByDefault();
234 }
235
236 void UnpackedInstaller::GetAbsolutePath() {
237   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
238
239   extension_path_ = base::MakeAbsoluteFilePath(extension_path_);
240
241   std::string error;
242   if (!file_util::CheckForIllegalFilenames(extension_path_, &error)) {
243     BrowserThread::PostTask(
244         BrowserThread::UI,
245         FROM_HERE,
246         base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
247     return;
248   }
249   BrowserThread::PostTask(
250       BrowserThread::UI, FROM_HERE,
251       base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
252 }
253
254 void UnpackedInstaller::CheckExtensionFileAccess() {
255   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256   if (!service_weak_.get())
257     return;
258
259   if (!IsLoadingUnpackedAllowed()) {
260     ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
261     return;
262   }
263
264   BrowserThread::PostTask(
265       BrowserThread::FILE,
266       FROM_HERE,
267       base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
268 }
269
270 void UnpackedInstaller::LoadWithFileAccess(int flags) {
271   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
272
273   std::string error;
274   installer_.set_extension(
275       file_util::LoadExtension(
276           extension_path_, Manifest::UNPACKED, flags, &error).get());
277
278   if (!installer_.extension().get() ||
279       !extension_l10n_util::ValidateExtensionLocales(
280           extension_path_,
281           installer_.extension()->manifest()->value(),
282           &error)) {
283     BrowserThread::PostTask(
284         BrowserThread::UI,
285         FROM_HERE,
286         base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
287     return;
288   }
289
290   BrowserThread::PostTask(
291       BrowserThread::UI,
292       FROM_HERE,
293       base::Bind(&UnpackedInstaller::ShowInstallPrompt, this));
294 }
295
296 void UnpackedInstaller::ReportExtensionLoadError(const std::string &error) {
297   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
298   if (!on_failure_callback_.is_null())
299     on_failure_callback_.Run(extension_path_, error);
300
301   if (service_weak_.get()) {
302     ExtensionErrorReporter::GetInstance()->ReportLoadError(
303         extension_path_,
304         error,
305         service_weak_->profile(),
306         be_noisy_on_failure_);
307   }
308 }
309
310 void UnpackedInstaller::ConfirmInstall() {
311   DCHECK_CURRENTLY_ON(BrowserThread::UI);
312   base::string16 error = installer_.CheckManagementPolicy();
313   if (!error.empty()) {
314     ReportExtensionLoadError(base::UTF16ToUTF8(error));
315     return;
316   }
317
318   PermissionsUpdater perms_updater(service_weak_->profile());
319   perms_updater.GrantActivePermissions(installer_.extension().get());
320
321   service_weak_->OnExtensionInstalled(
322       installer_.extension().get(),
323       syncer::StringOrdinal(),
324       false /* no requirement errors */,
325       NOT_BLACKLISTED,
326       false /* don't wait for idle */);
327 }
328
329 }  // namespace extensions