- add sources.
[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_prefs.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/permissions_updater.h"
18 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
19 #include "chrome/common/extensions/extension.h"
20 #include "chrome/common/extensions/extension_file_util.h"
21 #include "chrome/common/extensions/extension_l10n_util.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "extensions/common/id_util.h"
24 #include "extensions/common/manifest.h"
25 #include "sync/api/string_ordinal.h"
26
27 using content::BrowserThread;
28 using extensions::Extension;
29
30 namespace {
31
32 const char kUnpackedExtensionsBlacklistedError[] =
33     "Loading of unpacked extensions is disabled by the administrator.";
34
35 // Manages an ExtensionInstallPrompt for a particular extension.
36 class SimpleExtensionLoadPrompt : public ExtensionInstallPrompt::Delegate {
37  public:
38   SimpleExtensionLoadPrompt(const Extension* extension,
39                             Profile* profile,
40                             const base::Closure& callback);
41   virtual ~SimpleExtensionLoadPrompt();
42
43   void ShowPrompt();
44
45   // ExtensionInstallUI::Delegate
46   virtual void InstallUIProceed() OVERRIDE;
47   virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
48
49  private:
50   scoped_ptr<ExtensionInstallPrompt> install_ui_;
51   scoped_refptr<const Extension> extension_;
52   base::Closure callback_;
53 };
54
55 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
56     const Extension* extension,
57     Profile* profile,
58     const base::Closure& callback)
59     : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile(
60           profile)),
61       extension_(extension),
62       callback_(callback) {
63 }
64
65 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
66 }
67
68 void SimpleExtensionLoadPrompt::ShowPrompt() {
69   install_ui_->ConfirmInstall(
70       this,
71       extension_.get(),
72       ExtensionInstallPrompt::GetDefaultShowDialogCallback());
73 }
74
75 void SimpleExtensionLoadPrompt::InstallUIProceed() {
76   callback_.Run();
77   delete this;
78 }
79
80 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
81   delete this;
82 }
83
84 }  // namespace
85
86 namespace extensions {
87
88 // static
89 scoped_refptr<UnpackedInstaller> UnpackedInstaller::Create(
90     ExtensionService* extension_service) {
91   return scoped_refptr<UnpackedInstaller>(
92       new UnpackedInstaller(extension_service));
93 }
94
95 UnpackedInstaller::UnpackedInstaller(ExtensionService* extension_service)
96     : service_weak_(extension_service->AsWeakPtr()),
97       prompt_for_plugins_(true),
98       require_modern_manifest_version_(true),
99       installer_(extension_service->profile()) {
100   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101 }
102
103 UnpackedInstaller::~UnpackedInstaller() {
104   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
105         BrowserThread::CurrentlyOn(BrowserThread::FILE));
106 }
107
108 void UnpackedInstaller::Load(const base::FilePath& path_in) {
109   DCHECK(extension_path_.empty());
110   extension_path_ = path_in;
111   BrowserThread::PostTask(
112       BrowserThread::FILE,
113       FROM_HERE,
114       base::Bind(&UnpackedInstaller::GetAbsolutePath, this));
115 }
116
117 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath& path_in,
118                                             std::string* extension_id) {
119   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120   DCHECK(extension_path_.empty());
121
122   if (!service_weak_.get())
123     return false;
124   // 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
128   extension_path_ = base::MakeAbsoluteFilePath(path_in);
129
130   if (!IsLoadingUnpackedAllowed()) {
131     ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
132     return false;
133   }
134
135   std::string error;
136   installer_.set_extension(extension_file_util::LoadExtension(
137       extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get());
138
139   if (!installer_.extension().get() ||
140       !extension_l10n_util::ValidateExtensionLocales(
141           extension_path_,
142           installer_.extension()->manifest()->value(),
143           &error)) {
144     ReportExtensionLoadError(error);
145     return false;
146   }
147
148   ShowInstallPrompt();
149
150   *extension_id = installer_.extension()->id();
151   return true;
152 }
153
154 void UnpackedInstaller::ShowInstallPrompt() {
155   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
156   if (!service_weak_.get())
157     return;
158
159   const ExtensionSet* disabled_extensions =
160       service_weak_->disabled_extensions();
161   if (service_weak_->show_extensions_prompts() && prompt_for_plugins_ &&
162       PluginInfo::HasPlugins(installer_.extension().get()) &&
163       !disabled_extensions->Contains(installer_.extension()->id())) {
164     SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
165         installer_.extension().get(),
166         installer_.profile(),
167         base::Bind(&UnpackedInstaller::CallCheckRequirements, this));
168     prompt->ShowPrompt();
169     return;
170   }
171   CallCheckRequirements();
172 }
173
174 void UnpackedInstaller::CallCheckRequirements() {
175   installer_.CheckRequirements(
176       base::Bind(&UnpackedInstaller::OnRequirementsChecked, this));
177 }
178
179 void 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
188   ConfirmInstall();
189 }
190
191 int UnpackedInstaller::GetFlags() {
192   std::string id = id_util::GenerateIdForPath(extension_path_);
193   bool allow_file_access =
194       Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED);
195   ExtensionPrefs* prefs = service_weak_->extension_prefs();
196   if (prefs->HasAllowFileAccessSetting(id))
197     allow_file_access = prefs->AllowFileAccess(id);
198
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
208 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const {
209   if (!service_weak_.get())
210     return true;
211   // If there is a "*" in the extension blacklist, then no extensions should be
212   // allowed at all (except explicitly whitelisted extensions).
213   ExtensionPrefs* prefs = service_weak_->extension_prefs();
214   return !prefs->ExtensionsBlacklistedByDefault();
215 }
216
217 void UnpackedInstaller::GetAbsolutePath() {
218   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
219
220   extension_path_ = base::MakeAbsoluteFilePath(extension_path_);
221
222   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   }
231   BrowserThread::PostTask(
232       BrowserThread::UI, FROM_HERE,
233       base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
234 }
235
236 void UnpackedInstaller::CheckExtensionFileAccess() {
237   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
238   if (!service_weak_.get())
239     return;
240
241   if (!IsLoadingUnpackedAllowed()) {
242     ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError);
243     return;
244   }
245
246   BrowserThread::PostTask(
247       BrowserThread::FILE,
248       FROM_HERE,
249       base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags()));
250 }
251
252 void UnpackedInstaller::LoadWithFileAccess(int flags) {
253   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
254
255   std::string error;
256   installer_.set_extension(extension_file_util::LoadExtension(
257       extension_path_, Manifest::UNPACKED, flags, &error).get());
258
259   if (!installer_.extension().get() ||
260       !extension_l10n_util::ValidateExtensionLocales(
261           extension_path_,
262           installer_.extension()->manifest()->value(),
263           &error)) {
264     BrowserThread::PostTask(
265         BrowserThread::UI,
266         FROM_HERE,
267         base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
268     return;
269   }
270
271   BrowserThread::PostTask(
272       BrowserThread::UI,
273       FROM_HERE,
274       base::Bind(&UnpackedInstaller::ShowInstallPrompt, this));
275 }
276
277 void UnpackedInstaller::ReportExtensionLoadError(const std::string &error) {
278   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279   if (!service_weak_.get())
280     return;
281   service_weak_->ReportExtensionLoadError(extension_path_, error, true);
282 }
283
284 void UnpackedInstaller::ConfirmInstall() {
285   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
286   string16 error = installer_.CheckManagementPolicy();
287   if (!error.empty()) {
288     ReportExtensionLoadError(UTF16ToUTF8(error));
289     return;
290   }
291
292   PermissionsUpdater perms_updater(service_weak_->profile());
293   perms_updater.GrantActivePermissions(installer_.extension().get());
294
295   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 */);
301 }
302
303 }  // namespace extensions