diff options
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r-- | chrome/browser/extensions/startup_helper.cc | 125 | ||||
-rw-r--r-- | chrome/browser/extensions/startup_helper.h | 6 | ||||
-rw-r--r-- | chrome/browser/extensions/startup_helper_browsertest.cc | 63 |
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(); + } + } +} |