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