15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/startup_helper.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/file_path.h"
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/run_loop.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/sandboxed_unpacker.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_startup_installer.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
21ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chrome/common/extensions/chrome_extensions_client.h"
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_WIN)
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window.h"
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window_registry.h"
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/extension_registry.h"
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/extension_util.h"
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::BrowserThread;
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)namespace extensions {
3834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrintPackExtensionMessage(const std::string& message) {
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << message;
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// On Windows, the jumplist action for installing an ephemeral app has to use
4634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)// the --install-ephemeral-app-from-webstore command line arg to initiate an
4734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)// install.
4834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)scoped_refptr<WebstoreStandaloneInstaller> CreateEphemeralAppInstaller(
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Profile* profile,
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& app_id,
5134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    WebstoreStandaloneInstaller::Callback callback) {
5234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  scoped_refptr<WebstoreStandaloneInstaller> installer;
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_WIN)
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(registry);
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!registry->GetExtensionById(app_id, ExtensionRegistry::EVERYTHING) ||
5834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      !util::IsEphemeralApp(app_id, profile)) {
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return installer;
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  AppWindowRegistry* app_window_registry = AppWindowRegistry::Get(profile);
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(app_window_registry);
6434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  AppWindow* app_window =
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      app_window_registry->GetCurrentAppWindowForApp(app_id);
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!app_window)
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return installer;
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  installer = new WebstoreInstallWithPrompt(
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      app_id, profile, app_window->GetNativeWindow(), callback);
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return installer;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StartupHelper::StartupHelper() : pack_job_succeeded_(false) {
79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ExtensionsClient::Set(ChromeExtensionsClient::GetInstance());
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupHelper::OnPackSuccess(
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& crx_path,
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& output_private_key_path) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pack_job_succeeded_ = true;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrintPackExtensionMessage(
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF16ToUTF8(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          PackExtensionJob::StandardSuccessMessage(crx_path,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   output_private_key_path)));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartupHelper::OnPackFailure(const std::string& error_message,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  ExtensionCreator::ErrorType type) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrintPackExtensionMessage(error_message);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool StartupHelper::PackExtension(const CommandLine& cmd_line) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cmd_line.HasSwitch(switches::kPackExtension))
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Input Paths.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath src_dir =
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cmd_line.GetSwitchValuePath(switches::kPackExtension);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath private_key_path;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch a job to perform the packing on the file thread.  Ignore warnings
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from the packing process. (e.g. Overwrite any existing crx file.)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pack_job_ = new PackExtensionJob(this, src_dir, private_key_path,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ExtensionCreator::kOverwriteCRX);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pack_job_->set_asynchronous(false);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pack_job_->Start();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pack_job_succeeded_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class ValidateCrxHelper : public SandboxedUnpackerClient {
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ValidateCrxHelper(const base::FilePath& crx_file,
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    const base::FilePath& temp_dir,
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    base::RunLoop* run_loop)
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : crx_file_(crx_file), temp_dir_(temp_dir), run_loop_(run_loop),
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        finished_(false), success_(false) {}
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool finished() { return finished_; }
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool success() { return success_; }
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const base::string16& error() { return error_; }
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void Start() {
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BrowserThread::PostTask(BrowserThread::FILE,
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            FROM_HERE,
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            base::Bind(&ValidateCrxHelper::StartOnFileThread,
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       this));
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected:
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual ~ValidateCrxHelper() {}
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               const base::FilePath& extension_root,
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               const base::DictionaryValue* original_manifest,
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               const Extension* extension,
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               const SkBitmap& install_icon) OVERRIDE {
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    finished_ = true;
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    success_ = true;
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI,
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            FROM_HERE,
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            base::Bind(&ValidateCrxHelper::FinishOnUIThread,
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       this));
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnUnpackFailure(const base::string16& error) OVERRIDE {
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    finished_ = true;
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    success_ = false;
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_ = error;
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI,
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            FROM_HERE,
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            base::Bind(&ValidateCrxHelper::FinishOnUIThread,
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       this));
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void FinishOnUIThread() {
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (run_loop_->running())
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      run_loop_->Quit();
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void StartOnFileThread() {
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> file_thread_proxy =
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_refptr<SandboxedUnpacker> unpacker(
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        new SandboxedUnpacker(crx_file_,
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              Manifest::INTERNAL,
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              0, /* no special creation flags */
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              temp_dir_,
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              file_thread_proxy.get(),
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              this));
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    unpacker->Start();
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The file being validated.
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::FilePath& crx_file_;
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The temporary directory where the sandboxed unpacker will do work.
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::FilePath& temp_dir_;
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Unowned pointer to a runloop, so our consumer can wait for us to finish.
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::RunLoop* run_loop_;
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Whether we're finished unpacking;
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool finished_;
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Whether the unpacking was successful.
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool success_;
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If the unpacking wasn't successful, this contains an error message.
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 error_;
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool StartupHelper::ValidateCrx(const CommandLine& cmd_line,
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                std::string* error) {
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(error);
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath path = cmd_line.GetSwitchValuePath(switches::kValidateCrx);
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (path.empty()) {
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *error = base::StringPrintf("Empty path passed for %s",
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                switches::kValidateCrx);
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ScopedTempDir temp_dir;
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!temp_dir.CreateUniqueTempDir()) {
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *error = std::string("Failed to create temp dir");
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::RunLoop run_loop;
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_refptr<ValidateCrxHelper> helper(
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new ValidateCrxHelper(path, temp_dir.path(), &run_loop));
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  helper->Start();
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!helper->finished())
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    run_loop.Run();
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool success = helper->success();
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!success)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error = base::UTF16ToUTF8(helper->error());
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return success;
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AppInstallHelper {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A callback for when the install process is done.
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef base::Callback<void()> DoneCallback;
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppInstallHelper();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~AppInstallHelper();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success() { return success_; }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& error() { return error_; }
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void BeginInstall(Profile* profile,
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    const std::string& id,
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    bool show_prompt,
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    DoneCallback callback);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebstoreStandaloneInstaller::Callback Callback();
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void OnAppInstallComplete(bool success,
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            const std::string& error,
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            webstore_install::Result result);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoneCallback done_callback_;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These hold on to the result of the app install when it is complete.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success_;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error_;
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<WebstoreStandaloneInstaller> installer_;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppInstallHelper::AppInstallHelper() : success_(false) {}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppInstallHelper::~AppInstallHelper() {}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreStandaloneInstaller::Callback AppInstallHelper::Callback() {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Bind(&AppInstallHelper::OnAppInstallComplete,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::Unretained(this));
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppInstallHelper::BeginInstall(
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Profile* profile,
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& id,
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool show_prompt,
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoneCallback done_callback) {
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  done_callback_ = done_callback;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebstoreStandaloneInstaller::Callback callback =
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&AppInstallHelper::OnAppInstallComplete,
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Unretained(this));
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  installer_ = CreateEphemeralAppInstaller(profile, id, callback);
28934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (installer_.get()) {
29034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    installer_->BeginInstall();
29134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  } else {
29234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    error_ = "Not a supported ephemeral app installation.";
29334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    done_callback_.Run();
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppInstallHelper::OnAppInstallComplete(bool success,
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            const std::string& error,
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            webstore_install::Result result) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  success_ = success;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_= error;
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  done_callback_.Run();
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)bool StartupHelper::InstallEphemeralApp(const CommandLine& cmd_line,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        Profile* profile) {
30934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  std::string id =
31034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      cmd_line.GetSwitchValueASCII(switches::kInstallEphemeralAppFromWebstore);
31103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!crx_file::id_util::IdIsValid(id)) {
31234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    LOG(ERROR) << "Invalid id for "
31334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)        << switches::kInstallEphemeralAppFromWebstore << " : '" << id << "'";
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppInstallHelper helper;
318a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  base::RunLoop run_loop;
319a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  helper.BeginInstall(profile, id, true, run_loop.QuitClosure());
320a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  run_loop.Run();
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!helper.success())
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "InstallFromWebstore failed with error: " << helper.error();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return helper.success();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupHelper::~StartupHelper() {
328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (pack_job_.get())
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pack_job_->ClearClient();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
333