Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8268)

Unified Diff: chrome/common/extensions/extension_unpacker.cc

Issue 115595: Have the browser process rewrite manifest.json and theme images that the... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/common/extensions/extension_unpacker.h ('k') | chrome/common/render_messages.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/common/extensions/extension_unpacker.cc
===================================================================
--- chrome/common/extensions/extension_unpacker.cc (revision 16736)
+++ chrome/common/extensions/extension_unpacker.cc (working copy)
@@ -19,6 +19,8 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/unzip.h"
#include "chrome/common/url_constants.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "webkit/glue/image_decoder.h"
namespace {
const char kCurrentVersionFileName[] = "Current Version";
@@ -59,12 +61,47 @@
// The version of the extension package that this code understands.
const uint32 kExpectedVersion = 1;
+} // namespace
+
+static SkBitmap DecodeImage(const FilePath& path) {
+ // Read the file from disk.
+ std::string file_contents;
+ if (!file_util::PathExists(path) ||
+ !file_util::ReadFileToString(path, &file_contents)) {
+ return SkBitmap();
+ }
+
+ // Decode the image using WebKit's image decoder.
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(file_contents.data());
+ webkit_glue::ImageDecoder decoder;
+ return decoder.Decode(data, file_contents.length());
}
+static bool PathContainsParentDirectory(const FilePath& path) {
+ const FilePath::StringType kSeparators(FilePath::kSeparators);
+ const FilePath::StringType kParentDirectory(FilePath::kParentDirectory);
+ const size_t npos = FilePath::StringType::npos;
+ const FilePath::StringType& value = path.value();
+
+ for (size_t i = 0; i < value.length(); ) {
+ i = value.find(kParentDirectory, i);
+ if (i != npos) {
+ if ((i == 0 || kSeparators.find(value[i-1]) == npos) &&
+ (i+1 < value.length() || kSeparators.find(value[i+1]) == npos)) {
+ return true;
+ }
+ ++i;
+ }
+ }
+
+ return false;
+}
+
// The extension file format is a header, followed by the manifest, followed
// by the zip file. The header is a magic number, a version, the size of the
// header, and the size of the manifest. These ints are 4 byte little endian.
-DictionaryValue* ExtensionUnpacker::ReadManifest() {
+DictionaryValue* ExtensionUnpacker::ReadPackageHeader() {
ScopedStdioHandle file(file_util::OpenFile(extension_path_, "rb"));
if (!file.get()) {
SetError("no such extension file");
@@ -166,47 +203,117 @@
return manifest;
}
+DictionaryValue* ExtensionUnpacker::ReadManifest() {
+ FilePath manifest_path =
+ temp_install_dir_.AppendASCII(Extension::kManifestFilename);
+ if (!file_util::PathExists(manifest_path)) {
+ SetError(Extension::kInvalidManifestError);
+ return NULL;
+ }
+
+ JSONFileValueSerializer serializer(manifest_path);
+ std::string error;
+ scoped_ptr<Value> root(serializer.Deserialize(&error));
+ if (!root.get()) {
+ SetError(error);
+ return NULL;
+ }
+
+ if (!root->IsType(Value::TYPE_DICTIONARY)) {
+ SetError(Extension::kInvalidManifestError);
+ return NULL;
+ }
+
+ return static_cast<DictionaryValue*>(root.release());
+}
+
bool ExtensionUnpacker::Run() {
LOG(INFO) << "Installing extension " << extension_path_.value();
// Read and verify the extension.
- scoped_ptr<DictionaryValue> manifest(ReadManifest());
- if (!manifest.get()) {
- // ReadManifest has already reported the extension error.
+ scoped_ptr<DictionaryValue> header_manifest(ReadPackageHeader());
+ if (!header_manifest.get()) {
+ // ReadPackageHeader has already reported the extension error.
return false;
}
- Extension extension;
+
+ // TODO(mpcomplete): it looks like this isn't actually necessary. We don't
+ // use header_extension, and we check that the unzipped manifest is valid.
+ Extension header_extension;
std::string error;
- if (!extension.InitFromValue(*manifest,
- true, // require ID
- &error)) {
- SetError("Invalid extension manifest.");
+ if (!header_extension.InitFromValue(*header_manifest,
+ true, // require ID
+ &error)) {
+ SetError(error);
return false;
}
- // ID is required for installed extensions.
- if (extension.id().empty()) {
- SetError("Required value 'id' is missing.");
- return false;
- }
-
// <profile>/Extensions/INSTALL_TEMP/<version>
- std::string version = extension.VersionString();
- FilePath temp_install =
+ temp_install_dir_ =
extension_path_.DirName().AppendASCII(kTempExtensionName);
- if (!file_util::CreateDirectory(temp_install)) {
+ if (!file_util::CreateDirectory(temp_install_dir_)) {
SetError("Couldn't create directory for unzipping.");
return false;
}
- if (!Unzip(extension_path_, temp_install, NULL)) {
+ if (!Unzip(extension_path_, temp_install_dir_, NULL)) {
SetError("Couldn't unzip extension.");
return false;
}
+ // Parse the manifest.
+ parsed_manifest_.reset(ReadManifest());
+ if (!parsed_manifest_.get())
+ return false; // Error was already reported.
+
+ // Re-read the actual manifest into our extension struct.
+ Extension extension;
+ if (!extension.InitFromValue(*parsed_manifest_,
+ true, // require ID
+ &error)) {
+ SetError(error);
+ return false;
+ }
+
+ // Decode any images that the browser needs to display.
+ DictionaryValue* images = extension.GetThemeImages();
+ if (images) {
+ for (DictionaryValue::key_iterator it = images->begin_keys();
+ it != images->end_keys(); ++it) {
+ std::wstring val;
+ if (images->GetString(*it, &val)) {
+ if (!AddDecodedImage(FilePath::FromWStringHack(val)))
+ return false; // Error was already reported.
+ }
+ }
+ }
+
+ for (PageActionMap::const_iterator it = extension.page_actions().begin();
+ it != extension.page_actions().end(); ++it) {
+ if (!AddDecodedImage(it->second->icon_path()))
+ return false; // Error was already reported.
+ }
+
return true;
}
+bool ExtensionUnpacker::AddDecodedImage(const FilePath& path) {
+ // Make sure it's not referencing a file outside the extension's subdir.
+ if (path.IsAbsolute() || PathContainsParentDirectory(path)) {
+ SetError("Path names must not be absolute or contain '..'.");
+ return false;
+ }
+
+ SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
+ if (image_bitmap.isNull()) {
+ SetError("Could not decode theme image.");
+ return false;
+ }
+
+ decoded_images_.push_back(MakeTuple(image_bitmap, path));
+ return true;
+}
+
void ExtensionUnpacker::SetError(const std::string &error) {
error_message_ = error;
}
« no previous file with comments | « chrome/common/extensions/extension_unpacker.h ('k') | chrome/common/render_messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698