diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-11 20:46:20 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-11 20:46:20 +0000 |
commit | 77384a34070c268779dcf9d6aff3d1e80c6a4d25 (patch) | |
tree | 3e27e87c7eda146a32a98bd371a5932d2bc7351a /chrome/common/extensions/extension_unpacker.cc | |
parent | 733251c42033fed1828bfdb38a84e66162b82c33 (diff) | |
download | chromium_src-77384a34070c268779dcf9d6aff3d1e80c6a4d25.zip chromium_src-77384a34070c268779dcf9d6aff3d1e80c6a4d25.tar.gz chromium_src-77384a34070c268779dcf9d6aff3d1e80c6a4d25.tar.bz2 |
Revert "BUG=12114"
This reverts commit r18189.
TBR=rafaelw
Review URL: http://codereview.chromium.org/125004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18193 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/extensions/extension_unpacker.cc')
-rw-r--r-- | chrome/common/extensions/extension_unpacker.cc | 136 |
1 files changed, 118 insertions, 18 deletions
diff --git a/chrome/common/extensions/extension_unpacker.cc b/chrome/common/extensions/extension_unpacker.cc index bae5a7d..b5bc919 100644 --- a/chrome/common/extensions/extension_unpacker.cc +++ b/chrome/common/extensions/extension_unpacker.cc @@ -8,6 +8,8 @@ #include "base/scoped_handle.h" #include "base/scoped_temp_dir.h" #include "base/string_util.h" +#include "base/third_party/nss/blapi.h" +#include "base/third_party/nss/sha256.h" #include "base/thread.h" #include "base/values.h" #include "net/base/file_stream.h" @@ -21,6 +23,8 @@ #include "webkit/glue/image_decoder.h" namespace { +const char kCurrentVersionFileName[] = "Current Version"; + // The name of a temporary directory to install an extension into for // validation before finalizing install. const char kTempExtensionName[] = "TEMP_INSTALL"; @@ -28,14 +32,27 @@ const char kTempExtensionName[] = "TEMP_INSTALL"; // The file to write our decoded images to, relative to the extension_path. const char kDecodedImagesFilename[] = "DECODED_IMAGES"; -// Errors -const char* kCouldNotCreateDirectoryError = - "Could not create directory for unzipping."; -const char* kCouldNotDecodeImageError = "Could not decode theme image."; -const char* kCouldNotUnzipExtension = "Could not unzip extension."; -const char* kPathNamesMustBeAbsoluteOrLocalError = - "Path names must not be absolute or contain '..'."; +// Chromium Extension magic number +// TODO(aa): This should use the one in ExtensionCreator once we transition this +// to ouptut the same format. +const char kExtensionFileMagic[] = "Cr24"; + +struct ExtensionHeader { + char magic[sizeof(kExtensionFileMagic) - 1]; + uint32 version; + size_t header_size; + size_t manifest_size; +}; + +const size_t kZipHashBytes = 32; // SHA-256 +const size_t kZipHashHexBytes = kZipHashBytes * 2; // Hex string is 2x size. +// A marker file to indicate that an extension was installed from an external +// source. +const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; + +// The version of the extension package that this code understands. +const uint32 kExpectedVersion = 1; } // namespace static SkBitmap DecodeImage(const FilePath& path) { @@ -73,6 +90,74 @@ static bool PathContainsParentDirectory(const FilePath& path) { 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::ReadPackageHeader() { + ScopedStdioHandle file(file_util::OpenFile(extension_path_, "rb")); + if (!file.get()) { + SetError("no such extension file"); + return NULL; + } + + // Read and verify the header. + ExtensionHeader header; + size_t len; + + // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it + // appears that we don't have any endian/alignment aware serialization + // code in the code base. So for now, this assumes that we're running + // on a little endian machine with 4 byte alignment. + len = fread(&header, 1, sizeof(ExtensionHeader), file.get()); + if (len < sizeof(ExtensionHeader)) { + SetError("invalid extension header"); + return NULL; + } + if (strncmp(kExtensionFileMagic, header.magic, sizeof(header.magic))) { + SetError("bad magic number"); + return NULL; + } + if (header.version != kExpectedVersion) { + SetError("bad version number"); + return NULL; + } + if (header.header_size > sizeof(ExtensionHeader)) + fseek(file.get(), header.header_size - sizeof(ExtensionHeader), SEEK_CUR); + + char buf[1 << 16]; + std::string manifest_str; + size_t read_size = std::min(sizeof(buf), header.manifest_size); + size_t remainder = header.manifest_size; + while ((len = fread(buf, 1, read_size, file.get())) > 0) { + manifest_str.append(buf, len); + if (len <= remainder) + break; + remainder -= len; + read_size = std::min(sizeof(buf), remainder); + } + + // Verify the JSON + JSONStringValueSerializer json(manifest_str); + std::string error; + scoped_ptr<Value> val(json.Deserialize(&error)); + if (!val.get()) { + SetError(error); + return NULL; + } + if (!val->IsType(Value::TYPE_DICTIONARY)) { + SetError("manifest isn't a JSON dictionary"); + return NULL; + } + DictionaryValue* manifest = static_cast<DictionaryValue*>(val.get()); + + // TODO(erikkay): The manifest will also contain a signature of the hash + // (or perhaps the whole manifest) for authentication purposes. + + // The caller owns val (now cast to manifest). + val.release(); + return manifest; +} + DictionaryValue* ExtensionUnpacker::ReadManifest() { FilePath manifest_path = temp_install_dir_.AppendASCII(Extension::kManifestFilename); @@ -100,16 +185,34 @@ DictionaryValue* ExtensionUnpacker::ReadManifest() { bool ExtensionUnpacker::Run() { LOG(INFO) << "Installing extension " << extension_path_.value(); + // Read and verify the extension. + scoped_ptr<DictionaryValue> header_manifest(ReadPackageHeader()); + if (!header_manifest.get()) { + // ReadPackageHeader has already reported the extension error. + return false; + } + + // 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 (!header_extension.InitFromValue(*header_manifest, + true, // require ID + &error)) { + SetError(error); + return false; + } + // <profile>/Extensions/INSTALL_TEMP/<version> temp_install_dir_ = extension_path_.DirName().AppendASCII(kTempExtensionName); if (!file_util::CreateDirectory(temp_install_dir_)) { - SetError(kCouldNotCreateDirectoryError); + SetError("Couldn't create directory for unzipping."); return false; } if (!Unzip(extension_path_, temp_install_dir_)) { - SetError(kCouldNotUnzipExtension); + SetError("Couldn't unzip extension."); return false; } @@ -117,19 +220,16 @@ bool ExtensionUnpacker::Run() { parsed_manifest_.reset(ReadManifest()); if (!parsed_manifest_.get()) return false; // Error was already reported. - - // NOTE: Since the Unpacker doesn't have the extension's public_id, the - // InitFromValue is allowed to generate a temporary id for the extension. - // ANY CODE THAT FOLLOWS SHOULD NOT DEPEND ON THE CORRECT ID OF THIS - // EXTENSION. + + // Re-read the actual manifest into our extension struct. Extension extension; - std::string error; if (!extension.InitFromValue(*parsed_manifest_, - false, + true, // require ID &error)) { SetError(error); return false; } + // Decode any images that the browser needs to display. std::set<FilePath> image_paths = extension.GetBrowserImages(); for (std::set<FilePath>::iterator it = image_paths.begin(); @@ -171,13 +271,13 @@ bool ExtensionUnpacker::ReadImagesFromFile(const FilePath& extension_path, 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(kPathNamesMustBeAbsoluteOrLocalError); + 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(kCouldNotDecodeImageError); + SetError("Could not decode theme image."); return false; } |