• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "extensions/common/extension.h"
25 #include "ipc/ipc_message.h"
26 
27 using content::BrowserThread;
28 
29 namespace {
30 
PrintPackExtensionMessage(const std::string & message)31 void PrintPackExtensionMessage(const std::string& message) {
32   printf("%s\n", message.c_str());
33 }
34 
35 }  // namespace
36 
37 namespace extensions {
38 
StartupHelper()39 StartupHelper::StartupHelper() : pack_job_succeeded_(false) {
40   ExtensionsClient::Set(ChromeExtensionsClient::GetInstance());
41 }
42 
OnPackSuccess(const base::FilePath & crx_path,const base::FilePath & output_private_key_path)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       base::UTF16ToUTF8(
49           PackExtensionJob::StandardSuccessMessage(crx_path,
50                                                    output_private_key_path)));
51 }
52 
OnPackFailure(const std::string & error_message,ExtensionCreator::ErrorType type)53 void StartupHelper::OnPackFailure(const std::string& error_message,
54                                   ExtensionCreator::ErrorType type) {
55   PrintPackExtensionMessage(error_message);
56 }
57 
PackExtension(const CommandLine & cmd_line)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:
ValidateCrxHelper(const base::FilePath & crx_file,const base::FilePath & temp_dir,base::RunLoop * run_loop)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 
finished()90   bool finished() { return finished_; }
success()91   bool success() { return success_; }
error()92   const base::string16& error() { return error_; }
93 
Start()94   void Start() {
95     BrowserThread::PostTask(BrowserThread::FILE,
96                             FROM_HERE,
97                             base::Bind(&ValidateCrxHelper::StartOnFileThread,
98                                        this));
99   }
100 
101  protected:
~ValidateCrxHelper()102   virtual ~ValidateCrxHelper() {}
103 
OnUnpackSuccess(const base::FilePath & temp_dir,const base::FilePath & extension_root,const base::DictionaryValue * original_manifest,const Extension * extension,const SkBitmap & install_icon)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 
OnUnpackFailure(const base::string16 & error)117   virtual void OnUnpackFailure(const base::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 
FinishOnUIThread()127   void FinishOnUIThread() {
128     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
129     if (run_loop_->running())
130       run_loop_->Quit();
131   }
132 
StartOnFileThread()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   base::string16 error_;
165 };
166 
167 }  // namespace
168 
ValidateCrx(const CommandLine & cmd_line,std::string * error)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 = base::UTF16ToUTF8(helper->error());
195   return success;
196 }
197 
198 namespace {
199 
200 class AppInstallHelper {
201  public:
202   // A callback for when the install process is done.
203   typedef base::Callback<void()> DoneCallback;
204 
205   AppInstallHelper();
206   virtual ~AppInstallHelper();
success()207   bool success() { return success_; }
error()208   const std::string& error() { return error_; }
209   void BeginInstall(Profile* profile,
210                     const std::string& id,
211                     bool show_prompt,
212                     DoneCallback callback);
213 
214  private:
215   WebstoreStandaloneInstaller::Callback Callback();
216   void OnAppInstallComplete(bool success, const std::string& error);
217 
218   DoneCallback done_callback_;
219 
220   // These hold on to the result of the app install when it is complete.
221   bool success_;
222   std::string error_;
223 
224   scoped_refptr<WebstoreStandaloneInstaller> installer_;
225 };
226 
AppInstallHelper()227 AppInstallHelper::AppInstallHelper() : success_(false) {}
228 
~AppInstallHelper()229 AppInstallHelper::~AppInstallHelper() {}
230 
Callback()231 WebstoreStandaloneInstaller::Callback AppInstallHelper::Callback() {
232   return base::Bind(&AppInstallHelper::OnAppInstallComplete,
233                     base::Unretained(this));
234 }
235 
BeginInstall(Profile * profile,const std::string & id,bool show_prompt,DoneCallback done_callback)236 void AppInstallHelper::BeginInstall(
237     Profile* profile,
238     const std::string& id,
239     bool show_prompt,
240     DoneCallback done_callback) {
241   done_callback_ = done_callback;
242 
243   WebstoreStandaloneInstaller::Callback callback =
244       base::Bind(&AppInstallHelper::OnAppInstallComplete,
245                  base::Unretained(this));
246   installer_ = new WebstoreStartupInstaller(
247       id,
248       profile,
249       show_prompt,
250       callback);
251   installer_->BeginInstall();
252 }
253 
OnAppInstallComplete(bool success,const std::string & error)254 void AppInstallHelper::OnAppInstallComplete(bool success,
255                                             const std::string& error) {
256   success_ = success;
257   error_= error;
258   done_callback_.Run();
259 }
260 
DeleteHelperAndRunCallback(AppInstallHelper * helper,base::Callback<void ()> callback)261 void DeleteHelperAndRunCallback(AppInstallHelper* helper,
262                                 base::Callback<void()> callback) {
263   delete helper;
264   callback.Run();
265 }
266 
267 }  // namespace
268 
InstallFromWebstore(const CommandLine & cmd_line,Profile * profile)269 bool StartupHelper::InstallFromWebstore(const CommandLine& cmd_line,
270                                         Profile* profile) {
271   std::string id = cmd_line.GetSwitchValueASCII(switches::kInstallFromWebstore);
272   if (!Extension::IdIsValid(id)) {
273     LOG(ERROR) << "Invalid id for " << switches::kInstallFromWebstore
274                << " : '" << id << "'";
275     return false;
276   }
277 
278   AppInstallHelper helper;
279   base::RunLoop run_loop;
280   helper.BeginInstall(profile, id, true, run_loop.QuitClosure());
281   run_loop.Run();
282 
283   if (!helper.success())
284     LOG(ERROR) << "InstallFromWebstore failed with error: " << helper.error();
285   return helper.success();
286 }
287 
LimitedInstallFromWebstore(const CommandLine & cmd_line,Profile * profile,base::Callback<void ()> done_callback)288 void StartupHelper::LimitedInstallFromWebstore(
289     const CommandLine& cmd_line,
290     Profile* profile,
291     base::Callback<void()> done_callback) {
292   std::string id = WebStoreIdFromLimitedInstallCmdLine(cmd_line);
293   if (!Extension::IdIsValid(id)) {
294     LOG(ERROR) << "Invalid index for " << switches::kLimitedInstallFromWebstore;
295     done_callback.Run();
296     return;
297   }
298 
299   AppInstallHelper* helper = new AppInstallHelper();
300   helper->BeginInstall(profile, id, false /*show_prompt*/,
301                        base::Bind(&DeleteHelperAndRunCallback,
302                                   helper, done_callback));
303 }
304 
WebStoreIdFromLimitedInstallCmdLine(const CommandLine & cmd_line)305 std::string StartupHelper::WebStoreIdFromLimitedInstallCmdLine(
306     const CommandLine& cmd_line) {
307   std::string index = cmd_line.GetSwitchValueASCII(
308       switches::kLimitedInstallFromWebstore);
309   std::string id;
310   if (index == "1") {
311     id = "nckgahadagoaajjgafhacjanaoiihapd";
312   } else if (index == "2") {
313     id = "ecglahbcnmdpdciemllbhojghbkagdje";
314   }
315   return id;
316 }
317 
~StartupHelper()318 StartupHelper::~StartupHelper() {
319   if (pack_job_.get())
320     pack_job_->ClearClient();
321 }
322 
323 }  // namespace extensions
324