Upstream version 5.34.104.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/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"
28
29 using content::BrowserThread;
30 using extensions::Extension;
31
32 namespace {
33
34 const char kUnpackedExtensionsBlacklistedError[] =
35     "Loading of unpacked extensions is disabled by the administrator.";
36
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();
44
45   void ShowPrompt();
46
47   // ExtensionInstallUI::Delegate
48   virtual void InstallUIProceed() OVERRIDE;
49   virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
50
51  private:
52   scoped_ptr<ExtensionInstallPrompt> install_ui_;
53   scoped_refptr<const Extension> extension_;
54   base::Closure callback_;
55 };
56
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) {
65 }
66
67 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
68 }
69
70 void SimpleExtensionLoadPrompt::ShowPrompt() {
71   install_ui_->ConfirmInstall(
72       this,
73       extension_.get(),
74       ExtensionInstallPrompt::GetDefaultShowDialogCallback());
75 }
76
77 void SimpleExtensionLoadPrompt::InstallUIProceed() {
78   callback_.Run();
79   delete this;
80 }
81
82 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
83   delete this;
84 }
85
86 }  // namespace
87
88 namespace extensions {
89
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));
96 }
97
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));
104 }
105
106 UnpackedInstaller::~UnpackedInstaller() {
107   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
108         BrowserThread::CurrentlyOn(BrowserThread::FILE));
109 }
110
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));
118 }
119
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());
124
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;
130
131   extension_path_ = base::MakeAbsoluteFilePath(path_in);
132
133   if (!IsLoadingUnpackedAllowed()) {
134     ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
135     return false;
136   }
137
138   std::string error;
139   installer_.set_extension(extension_file_util::LoadExtension(
140       extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get());
141
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;
149   }
150
151   ShowInstallPrompt();
152
153   *extension_id = installer_.extension()->id();
154   return true;
155 }
156
157 void UnpackedInstaller::ShowInstallPrompt() {
158   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
159   if (!service_weak_.get())
160     return;
161
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;
173   }
174   CallCheckRequirements();
175 }
176
177 void UnpackedInstaller::CallCheckRequirements() {
178   installer_.CheckRequirements(
179       base::Bind(&UnpackedInstaller::OnRequirementsChecked, this));
180 }
181
182 void UnpackedInstaller::OnRequirementsChecked(
183     std::vector<std::string> requirement_errors) {
184   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
185
186   if (!requirement_errors.empty()) {
187     ReportExtensionLoadError(JoinString(requirement_errors, ' '));
188     return;
189   }
190
191   ConfirmInstall();
192 }
193
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);
201
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;
207
208   return result;
209 }
210
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();
218 }
219
220 void UnpackedInstaller::GetAbsolutePath() {
221   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
222
223   extension_path_ = base::MakeAbsoluteFilePath(extension_path_);
224
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;
233   }
234   BrowserThread::PostTask(
235       BrowserThread::UI, FROM_HERE,
236       base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
237 }
238
239 void UnpackedInstaller::CheckExtensionFileAccess() {
240   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
241   if (!service_weak_.get())
242     return;
243
244   if (!IsLoadingUnpackedAllowed()) {
245     ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
246     return;
247   }
248
249   BrowserThread::PostTask(
250       BrowserThread::FILE,
251       FROM_HERE,
252       base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
253 }
254
255 void UnpackedInstaller::LoadWithFileAccess(int flags) {
256   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
257
258   std::string error;
259   installer_.set_extension(extension_file_util::LoadExtension(
260       extension_path_, Manifest::UNPACKED, flags, &error).get());
261
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;
272   }
273
274   BrowserThread::PostTask(
275       BrowserThread::UI,
276       FROM_HERE,
277       base::Bind(&UnpackedInstaller::ShowInstallPrompt, this));
278 }
279
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);
285 }
286
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;
293   }
294
295   PermissionsUpdater perms_updater(service_weak_->profile());
296   perms_updater.GrantActivePermissions(installer_.extension().get());
297
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 */);
304 }
305
306 }  // namespace extensions