blob: 4b8e4ac3c7fcbb45b29e93ed737c78a054f766d3 [file] [log] [blame]
// Copyright 2014 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 "extensions/utility/utility_handler.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "content/public/utility/utility_thread.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/extension_unpacker.mojom.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_parser.mojom.h"
#include "extensions/common/update_manifest.h"
#include "extensions/strings/grit/extensions_strings.h"
#include "extensions/utility/unpacker.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/service_manager/public/cpp/interface_registry.h"
#include "third_party/zlib/google/zip.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_switches.h"
namespace extensions {
namespace {
class ExtensionUnpackerImpl : public extensions::mojom::ExtensionUnpacker {
public:
ExtensionUnpackerImpl() = default;
~ExtensionUnpackerImpl() override = default;
static void Create(extensions::mojom::ExtensionUnpackerRequest request) {
mojo::MakeStrongBinding(base::MakeUnique<ExtensionUnpackerImpl>(),
std::move(request));
}
private:
// extensions::mojom::ExtensionUnpacker:
void Unzip(const base::FilePath& file,
const base::FilePath& path,
const UnzipCallback& callback) override {
std::unique_ptr<base::DictionaryValue> manifest;
if (UnzipFileManifestIntoPath(file, path, &manifest)) {
callback.Run(UnzipFileIntoPath(file, path, std::move(manifest)));
} else {
callback.Run(false);
}
}
void Unpack(const base::FilePath& path,
const std::string& extension_id,
Manifest::Location location,
int32_t creation_flags,
const UnpackCallback& callback) override {
CHECK_GT(location, Manifest::INVALID_LOCATION);
CHECK_LT(location, Manifest::NUM_LOCATIONS);
DCHECK(ExtensionsClient::Get());
content::UtilityThread::Get()->EnsureBlinkInitialized();
Unpacker unpacker(path.DirName(), path, extension_id, location,
creation_flags);
if (unpacker.Run()) {
callback.Run(base::string16(), unpacker.TakeParsedManifest());
} else {
callback.Run(unpacker.error_message(), nullptr);
}
}
static bool UnzipFileManifestIntoPath(
const base::FilePath& file,
const base::FilePath& path,
std::unique_ptr<base::DictionaryValue>* manifest) {
if (zip::UnzipWithFilterCallback(
file, path, base::Bind(&Unpacker::IsManifestFile), false)) {
std::string error;
*manifest = Unpacker::ReadManifest(path, &error);
return error.empty() && manifest->get();
}
return false;
}
static bool UnzipFileIntoPath(
const base::FilePath& file,
const base::FilePath& path,
std::unique_ptr<base::DictionaryValue> manifest) {
Manifest internal(Manifest::INTERNAL, std::move(manifest));
// TODO(crbug.com/645263): This silently ignores blocked file types.
// Add install warnings.
return zip::UnzipWithFilterCallback(
file, path,
base::Bind(&Unpacker::ShouldExtractFile, internal.is_theme()),
true /* log_skipped_files */);
}
DISALLOW_COPY_AND_ASSIGN(ExtensionUnpackerImpl);
};
class ManifestParserImpl : public extensions::mojom::ManifestParser {
public:
ManifestParserImpl() = default;
~ManifestParserImpl() override = default;
static void Create(extensions::mojom::ManifestParserRequest request) {
mojo::MakeStrongBinding(base::MakeUnique<ManifestParserImpl>(),
std::move(request));
}
private:
void Parse(const std::string& xml, const ParseCallback& callback) override {
UpdateManifest manifest;
if (manifest.Parse(xml)) {
callback.Run(manifest.results());
} else {
LOG(WARNING) << "Error parsing update manifest:\n" << manifest.errors();
callback.Run(base::nullopt);
}
}
DISALLOW_COPY_AND_ASSIGN(ManifestParserImpl);
};
} // namespace
namespace utility_handler {
void UtilityThreadStarted() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
std::string lang = command_line->GetSwitchValueASCII(switches::kLang);
if (!lang.empty())
extension_l10n_util::SetProcessLocale(lang);
}
void ExposeInterfacesToBrowser(service_manager::InterfaceRegistry* registry,
bool running_elevated) {
// If our process runs with elevated privileges, only add elevated Mojo
// interfaces to the interface registry.
if (running_elevated)
return;
registry->AddInterface(base::Bind(&ExtensionUnpackerImpl::Create));
registry->AddInterface(base::Bind(&ManifestParserImpl::Create));
}
} // namespace utility_handler
} // namespace extensions