Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / startup_helper.cc
1 // Copyright (c) 2012 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/startup_helper.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/sandboxed_unpacker.h"
18 #include "chrome/browser/extensions/webstore_startup_installer.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/chrome_extensions_client.h"
22 #include "components/crx_file/id_util.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/web_contents.h"
25 #include "extensions/common/extension.h"
26 #include "ipc/ipc_message.h"
27
28 #if defined(OS_WIN)
29 #include "extensions/browser/app_window/app_window.h"
30 #include "extensions/browser/app_window/app_window_registry.h"
31 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_util.h"
33 #endif
34
35 using content::BrowserThread;
36
37 namespace {
38
39 void PrintPackExtensionMessage(const std::string& message) {
40   VLOG(1) << message;
41 }
42
43 // On Windows, the jumplist action for installing an ephemeral app has to use
44 // the --install-from-webstore command line arg to initiate an install.
45 scoped_refptr<extensions::WebstoreStandaloneInstaller>
46 CreateEphemeralAppInstaller(
47     Profile* profile,
48     const std::string& app_id,
49     extensions::WebstoreStandaloneInstaller::Callback callback) {
50   scoped_refptr<extensions::WebstoreStandaloneInstaller> installer;
51
52 #if defined(OS_WIN)
53   using extensions::ExtensionRegistry;
54   ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
55   DCHECK(registry);
56   if (!registry->GetExtensionById(app_id, ExtensionRegistry::EVERYTHING) ||
57       !extensions::util::IsEphemeralApp(app_id, profile)) {
58     return installer;
59   }
60
61   extensions::AppWindowRegistry* app_window_registry =
62       extensions::AppWindowRegistry::Get(profile);
63   DCHECK(app_window_registry);
64   extensions::AppWindow* app_window =
65       app_window_registry->GetCurrentAppWindowForApp(app_id);
66   if (!app_window)
67     return installer;
68
69   installer = new extensions::WebstoreInstallWithPrompt(
70       app_id, profile, app_window->GetNativeWindow(), callback);
71 #endif
72
73   return installer;
74 }
75
76 }  // namespace
77
78 namespace extensions {
79
80 StartupHelper::StartupHelper() : pack_job_succeeded_(false) {
81   ExtensionsClient::Set(ChromeExtensionsClient::GetInstance());
82 }
83
84 void StartupHelper::OnPackSuccess(
85     const base::FilePath& crx_path,
86     const base::FilePath& output_private_key_path) {
87   pack_job_succeeded_ = true;
88   PrintPackExtensionMessage(
89       base::UTF16ToUTF8(
90           PackExtensionJob::StandardSuccessMessage(crx_path,
91                                                    output_private_key_path)));
92 }
93
94 void StartupHelper::OnPackFailure(const std::string& error_message,
95                                   ExtensionCreator::ErrorType type) {
96   PrintPackExtensionMessage(error_message);
97 }
98
99 bool StartupHelper::PackExtension(const CommandLine& cmd_line) {
100   if (!cmd_line.HasSwitch(switches::kPackExtension))
101     return false;
102
103   // Input Paths.
104   base::FilePath src_dir =
105       cmd_line.GetSwitchValuePath(switches::kPackExtension);
106   base::FilePath private_key_path;
107   if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
108     private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey);
109   }
110
111   // Launch a job to perform the packing on the file thread.  Ignore warnings
112   // from the packing process. (e.g. Overwrite any existing crx file.)
113   pack_job_ = new PackExtensionJob(this, src_dir, private_key_path,
114                                    ExtensionCreator::kOverwriteCRX);
115   pack_job_->set_asynchronous(false);
116   pack_job_->Start();
117
118   return pack_job_succeeded_;
119 }
120
121 namespace {
122
123 class ValidateCrxHelper : public SandboxedUnpackerClient {
124  public:
125   ValidateCrxHelper(const base::FilePath& crx_file,
126                     const base::FilePath& temp_dir,
127                     base::RunLoop* run_loop)
128       : crx_file_(crx_file), temp_dir_(temp_dir), run_loop_(run_loop),
129         finished_(false), success_(false) {}
130
131   bool finished() { return finished_; }
132   bool success() { return success_; }
133   const base::string16& error() { return error_; }
134
135   void Start() {
136     BrowserThread::PostTask(BrowserThread::FILE,
137                             FROM_HERE,
138                             base::Bind(&ValidateCrxHelper::StartOnFileThread,
139                                        this));
140   }
141
142  protected:
143   virtual ~ValidateCrxHelper() {}
144
145   virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
146                                const base::FilePath& extension_root,
147                                const base::DictionaryValue* original_manifest,
148                                const Extension* extension,
149                                const SkBitmap& install_icon) OVERRIDE {
150     finished_ = true;
151     success_ = true;
152     BrowserThread::PostTask(BrowserThread::UI,
153                             FROM_HERE,
154                             base::Bind(&ValidateCrxHelper::FinishOnUIThread,
155                                        this));
156   }
157
158   virtual void OnUnpackFailure(const base::string16& error) OVERRIDE {
159     finished_ = true;
160     success_ = false;
161     error_ = error;
162     BrowserThread::PostTask(BrowserThread::UI,
163                             FROM_HERE,
164                             base::Bind(&ValidateCrxHelper::FinishOnUIThread,
165                                        this));
166   }
167
168   void FinishOnUIThread() {
169     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
170     if (run_loop_->running())
171       run_loop_->Quit();
172   }
173
174   void StartOnFileThread() {
175     CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
176     scoped_refptr<base::MessageLoopProxy> file_thread_proxy =
177         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
178
179     scoped_refptr<SandboxedUnpacker> unpacker(
180         new SandboxedUnpacker(crx_file_,
181                               Manifest::INTERNAL,
182                               0, /* no special creation flags */
183                               temp_dir_,
184                               file_thread_proxy.get(),
185                               this));
186     unpacker->Start();
187   }
188
189   // The file being validated.
190   const base::FilePath& crx_file_;
191
192   // The temporary directory where the sandboxed unpacker will do work.
193   const base::FilePath& temp_dir_;
194
195   // Unowned pointer to a runloop, so our consumer can wait for us to finish.
196   base::RunLoop* run_loop_;
197
198   // Whether we're finished unpacking;
199   bool finished_;
200
201   // Whether the unpacking was successful.
202   bool success_;
203
204   // If the unpacking wasn't successful, this contains an error message.
205   base::string16 error_;
206 };
207
208 }  // namespace
209
210 bool StartupHelper::ValidateCrx(const CommandLine& cmd_line,
211                                 std::string* error) {
212   CHECK(error);
213   base::FilePath path = cmd_line.GetSwitchValuePath(switches::kValidateCrx);
214   if (path.empty()) {
215     *error = base::StringPrintf("Empty path passed for %s",
216                                 switches::kValidateCrx);
217     return false;
218   }
219   base::ScopedTempDir temp_dir;
220
221   if (!temp_dir.CreateUniqueTempDir()) {
222     *error = std::string("Failed to create temp dir");
223     return false;
224   }
225
226   base::RunLoop run_loop;
227   scoped_refptr<ValidateCrxHelper> helper(
228       new ValidateCrxHelper(path, temp_dir.path(), &run_loop));
229   helper->Start();
230   if (!helper->finished())
231     run_loop.Run();
232
233   bool success = helper->success();
234   if (!success)
235     *error = base::UTF16ToUTF8(helper->error());
236   return success;
237 }
238
239 namespace {
240
241 class AppInstallHelper {
242  public:
243   // A callback for when the install process is done.
244   typedef base::Callback<void()> DoneCallback;
245
246   AppInstallHelper();
247   virtual ~AppInstallHelper();
248   bool success() { return success_; }
249   const std::string& error() { return error_; }
250   void BeginInstall(Profile* profile,
251                     const std::string& id,
252                     bool show_prompt,
253                     DoneCallback callback);
254
255  private:
256   WebstoreStandaloneInstaller::Callback Callback();
257   void OnAppInstallComplete(bool success,
258                             const std::string& error,
259                             webstore_install::Result result);
260
261   DoneCallback done_callback_;
262
263   // These hold on to the result of the app install when it is complete.
264   bool success_;
265   std::string error_;
266
267   scoped_refptr<WebstoreStandaloneInstaller> installer_;
268 };
269
270 AppInstallHelper::AppInstallHelper() : success_(false) {}
271
272 AppInstallHelper::~AppInstallHelper() {}
273
274 WebstoreStandaloneInstaller::Callback AppInstallHelper::Callback() {
275   return base::Bind(&AppInstallHelper::OnAppInstallComplete,
276                     base::Unretained(this));
277 }
278
279 void AppInstallHelper::BeginInstall(
280     Profile* profile,
281     const std::string& id,
282     bool show_prompt,
283     DoneCallback done_callback) {
284   done_callback_ = done_callback;
285
286   WebstoreStandaloneInstaller::Callback callback =
287       base::Bind(&AppInstallHelper::OnAppInstallComplete,
288                  base::Unretained(this));
289
290   installer_ = CreateEphemeralAppInstaller(profile, id, callback);
291   if (!installer_.get()) {
292     installer_ =
293         new WebstoreStartupInstaller(id, profile, show_prompt, callback);
294   }
295   installer_->BeginInstall();
296 }
297
298 void AppInstallHelper::OnAppInstallComplete(bool success,
299                                             const std::string& error,
300                                             webstore_install::Result result) {
301   success_ = success;
302   error_= error;
303   done_callback_.Run();
304 }
305
306 void DeleteHelperAndRunCallback(AppInstallHelper* helper,
307                                 base::Callback<void()> callback) {
308   delete helper;
309   callback.Run();
310 }
311
312 }  // namespace
313
314 bool StartupHelper::InstallFromWebstore(const CommandLine& cmd_line,
315                                         Profile* profile) {
316   std::string id = cmd_line.GetSwitchValueASCII(switches::kInstallFromWebstore);
317   if (!crx_file::id_util::IdIsValid(id)) {
318     LOG(ERROR) << "Invalid id for " << switches::kInstallFromWebstore
319                << " : '" << id << "'";
320     return false;
321   }
322
323   AppInstallHelper helper;
324   base::RunLoop run_loop;
325   helper.BeginInstall(profile, id, true, run_loop.QuitClosure());
326   run_loop.Run();
327
328   if (!helper.success())
329     LOG(ERROR) << "InstallFromWebstore failed with error: " << helper.error();
330   return helper.success();
331 }
332
333 void StartupHelper::LimitedInstallFromWebstore(
334     const CommandLine& cmd_line,
335     Profile* profile,
336     base::Callback<void()> done_callback) {
337   std::string id = WebStoreIdFromLimitedInstallCmdLine(cmd_line);
338   if (!crx_file::id_util::IdIsValid(id)) {
339     LOG(ERROR) << "Invalid index for " << switches::kLimitedInstallFromWebstore;
340     done_callback.Run();
341     return;
342   }
343
344   AppInstallHelper* helper = new AppInstallHelper();
345   helper->BeginInstall(profile, id, false /*show_prompt*/,
346                        base::Bind(&DeleteHelperAndRunCallback,
347                                   helper, done_callback));
348 }
349
350 std::string StartupHelper::WebStoreIdFromLimitedInstallCmdLine(
351     const CommandLine& cmd_line) {
352   std::string index = cmd_line.GetSwitchValueASCII(
353       switches::kLimitedInstallFromWebstore);
354   std::string id;
355   if (index == "1") {
356     id = "nckgahadagoaajjgafhacjanaoiihapd";
357   } else if (index == "2") {
358     id = "ecglahbcnmdpdciemllbhojghbkagdje";
359   }
360   return id;
361 }
362
363 StartupHelper::~StartupHelper() {
364   if (pack_job_.get())
365     pack_job_->ClearClient();
366 }
367
368 }  // namespace extensions