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