summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/startup_helper.cc125
-rw-r--r--chrome/browser/extensions/startup_helper.h6
-rw-r--r--chrome/browser/extensions/startup_helper_browsertest.cc63
3 files changed, 194 insertions, 0 deletions
diff --git a/chrome/browser/extensions/startup_helper.cc b/chrome/browser/extensions/startup_helper.cc
index e274d44..1c1f18b 100644
--- a/chrome/browser/extensions/startup_helper.cc
+++ b/chrome/browser/extensions/startup_helper.cc
@@ -7,19 +7,26 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
+#include "base/files/file_path.h"
#include "base/message_loop.h"
+#include "base/run_loop.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/sandboxed_unpacker.h"
#include "chrome/browser/extensions/webstore_startup_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
#include "chrome/common/extensions/background_info.h"
#include "chrome/common/extensions/extension.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message.h"
+using content::BrowserThread;
+
namespace {
void PrintPackExtensionMessage(const std::string& message) {
@@ -72,6 +79,124 @@ bool StartupHelper::PackExtension(const CommandLine& cmd_line) {
return pack_job_succeeded_;
}
+namespace {
+
+class ValidateCrxHelper : public SandboxedUnpackerClient {
+ public:
+ ValidateCrxHelper(const base::FilePath& crx_file,
+ const base::FilePath& temp_dir,
+ base::RunLoop* run_loop)
+ : crx_file_(crx_file), temp_dir_(temp_dir), run_loop_(run_loop),
+ finished_(false), success_(false) {}
+
+ bool finished() { return finished_; }
+ bool success() { return success_; }
+ const string16& error() { return error_; }
+
+ void Start() {
+ BrowserThread::PostTask(BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&ValidateCrxHelper::StartOnFileThread,
+ this));
+ }
+
+ protected:
+ virtual ~ValidateCrxHelper() {}
+
+ virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
+ const base::FilePath& extension_root,
+ const base::DictionaryValue* original_manifest,
+ const Extension* extension) {
+ finished_ = true;
+ success_ = true;
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ValidateCrxHelper::FinishOnUIThread,
+ this));
+ }
+
+ virtual void OnUnpackFailure(const string16& error) {
+ finished_ = true;
+ success_ = false;
+ error_ = error;
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ValidateCrxHelper::FinishOnUIThread,
+ this));
+ }
+
+ void FinishOnUIThread() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (run_loop_->running())
+ run_loop_->Quit();
+ }
+
+ void StartOnFileThread() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ scoped_refptr<base::MessageLoopProxy> file_thread_proxy =
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
+
+ scoped_refptr<SandboxedUnpacker> unpacker(
+ new SandboxedUnpacker(crx_file_,
+ true /* out of process */,
+ Manifest::INTERNAL,
+ 0, /* no special creation flags */
+ temp_dir_,
+ file_thread_proxy,
+ this));
+ unpacker->Start();
+ }
+
+ // The file being validated.
+ const base::FilePath& crx_file_;
+
+ // The temporary directory where the sandboxed unpacker will do work.
+ const base::FilePath& temp_dir_;
+
+ // Unowned pointer to a runloop, so our consumer can wait for us to finish.
+ base::RunLoop* run_loop_;
+
+ // Whether we're finished unpacking;
+ bool finished_;
+
+ // Whether the unpacking was successful.
+ bool success_;
+
+ // If the unpacking wasn't successful, this contains an error message.
+ string16 error_;
+};
+
+} // namespace
+
+bool StartupHelper::ValidateCrx(const CommandLine& cmd_line,
+ std::string* error) {
+ CHECK(error);
+ base::FilePath path = cmd_line.GetSwitchValuePath(switches::kValidateCrx);
+ if (path.empty()) {
+ *error = base::StringPrintf("Empty path passed for %s",
+ switches::kValidateCrx);
+ return false;
+ }
+ base::ScopedTempDir temp_dir;
+
+ if (!temp_dir.CreateUniqueTempDir()) {
+ *error = std::string("Failed to create temp dir");
+ return false;
+ }
+
+ base::RunLoop run_loop;
+ scoped_refptr<ValidateCrxHelper> helper(
+ new ValidateCrxHelper(path, temp_dir.path(), &run_loop));
+ helper->Start();
+ if (!helper->finished())
+ run_loop.Run();
+
+ bool success = helper->success();
+ if (!success)
+ *error = UTF16ToUTF8(helper->error());
+ return success;
+}
+
bool StartupHelper::UninstallExtension(const CommandLine& cmd_line,
Profile* profile) {
DCHECK(profile);
diff --git a/chrome/browser/extensions/startup_helper.h b/chrome/browser/extensions/startup_helper.h
index 01ccfa6..6844194 100644
--- a/chrome/browser/extensions/startup_helper.h
+++ b/chrome/browser/extensions/startup_helper.h
@@ -29,6 +29,12 @@ class StartupHelper : public PackExtensionJob::Client {
// extension. Returns false if the pack job failed.
bool PackExtension(const CommandLine& cmd_line);
+ // Validates a crx at the path given by the --validate-extension flag - can
+ // it be installed? Returns true if the crx is valid, or false otherwise.
+ // If the return value is false, a description of the problem may be written
+ // into |error|.
+ bool ValidateCrx(const CommandLine& cmd_line, std::string* error);
+
// Handle --uninstall-extension flag from the |cmd_line| by uninstalling the
// specified extension from |profile|. Returns false if the uninstall job
// could not be started.
diff --git a/chrome/browser/extensions/startup_helper_browsertest.cc b/chrome/browser/extensions/startup_helper_browsertest.cc
new file mode 100644
index 0000000..4d1d129
--- /dev/null
+++ b/chrome/browser/extensions/startup_helper_browsertest.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/browser/extensions/startup_helper.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+
+class StartupHelperBrowserTest : public InProcessBrowserTest {
+ public:
+ StartupHelperBrowserTest() {}
+ virtual ~StartupHelperBrowserTest() {}
+
+ virtual void SetUpCommandLine(CommandLine* command_line) {
+ command_line->AppendSwitch(switches::kNoStartupWindow);
+ PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
+ test_data_dir_ = test_data_dir_.AppendASCII("extensions");
+ }
+
+ protected:
+ base::FilePath test_data_dir_;
+};
+
+IN_PROC_BROWSER_TEST_F(StartupHelperBrowserTest, ValidateCrx) {
+ // A list of crx file paths along with an expected result of valid (true) or
+ // invalid (false).
+ std::vector<std::pair<base::FilePath, bool> > expectations;
+ expectations.push_back(
+ std::make_pair(test_data_dir_.AppendASCII("good.crx"), true));
+ expectations.push_back(
+ std::make_pair(test_data_dir_.AppendASCII("good2.crx"), true));
+ expectations.push_back(
+ std::make_pair(test_data_dir_.AppendASCII("bad_magic.crx"), false));
+ expectations.push_back(
+ std::make_pair(test_data_dir_.AppendASCII("bad_underscore.crx"), false));
+
+ for (std::vector<std::pair<base::FilePath, bool> >::iterator i =
+ expectations.begin();
+ i != expectations.end(); ++i) {
+ CommandLine command_line(CommandLine::NO_PROGRAM);
+ const base::FilePath& path = i->first;
+ command_line.AppendSwitchPath(switches::kValidateCrx, path);
+
+ std::string error;
+ extensions::StartupHelper helper;
+ bool result = helper.ValidateCrx(command_line, &error);
+ if (i->second) {
+ EXPECT_TRUE(result) << path.LossyDisplayName()
+ << " expected to be valid but wasn't";
+ } else {
+ EXPECT_FALSE(result) << path.LossyDisplayName()
+ << " expected to be invalid but wasn't";
+ EXPECT_FALSE(error.empty()) << "Error message wasn't set for "
+ << path.LossyDisplayName();
+ }
+ }
+}