blob: 09cb224aa0e2797e3fb15a5fa29a29646ee02aaf [file] [log] [blame]
[email protected]a999d672012-01-23 22:31:401// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]1fca1492009-05-15 22:23:432// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]c34381df2013-07-11 16:14:425#include "chrome/utility/extensions/unpacker.h"
[email protected]1fca1492009-05-15 22:23:436
[email protected]ccea03c2010-12-17 03:31:507#include <set>
8
[email protected]1fca1492009-05-15 22:23:439#include "base/file_util.h"
[email protected]25a4c1c2013-06-08 04:53:3610#include "base/files/file_enumerator.h"
[email protected]ea1a3f62012-11-16 20:34:2311#include "base/files/scoped_temp_dir.h"
[email protected]3367f3a2012-09-01 02:40:0612#include "base/i18n/rtl.h"
[email protected]ffbec692012-02-26 20:26:4213#include "base/json/json_file_value_serializer.h"
[email protected]3b63f8f42011-03-28 01:54:1514#include "base/memory/scoped_handle.h"
[email protected]3c8a6b02013-06-11 00:49:4915#include "base/strings/string_util.h"
[email protected]12bfb612013-06-07 19:54:0216#include "base/strings/utf_string_conversions.h"
[email protected]34b99632011-01-01 01:01:0617#include "base/threading/thread.h"
[email protected]1fca1492009-05-15 22:23:4318#include "base/values.h"
[email protected]43c05d902013-07-10 21:27:0019#include "chrome/common/chrome_utility_messages.h"
[email protected]0273969d2013-01-30 22:16:3120#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
[email protected]5b1a0e22009-05-26 19:00:5821#include "chrome/common/extensions/extension.h"
[email protected]7c927b62010-02-24 09:54:1322#include "chrome/common/extensions/extension_file_util.h"
[email protected]1acbb4b62010-03-09 17:52:2923#include "chrome/common/extensions/extension_l10n_util.h"
[email protected]ea1a3f62012-11-16 20:34:2324#include "chrome/common/extensions/extension_manifest_constants.h"
[email protected]e689cf252013-06-26 18:21:1425#include "content/public/child/image_decoder_utils.h"
[email protected]19a5c7442011-10-21 20:00:4126#include "content/public/common/common_param_traits.h"
[email protected]993da5e2013-03-23 21:25:1627#include "extensions/common/constants.h"
[email protected]d42c1112013-08-22 19:36:3228#include "extensions/common/manifest.h"
[email protected]3367f3a2012-09-01 02:40:0629#include "grit/generated_resources.h"
[email protected]946d1b22009-07-22 23:57:2130#include "ipc/ipc_message_utils.h"
[email protected]e0785902011-05-19 23:34:1731#include "net/base/file_stream.h"
[email protected]902f7cd2009-05-22 19:02:1932#include "third_party/skia/include/core/SkBitmap.h"
[email protected]4170d3a2013-05-03 23:02:5733#include "third_party/zlib/google/zip.h"
[email protected]3367f3a2012-09-01 02:40:0634#include "ui/base/l10n/l10n_util.h"
[email protected]e689cf252013-06-26 18:21:1435#include "ui/gfx/size.h"
[email protected]1fca1492009-05-15 22:23:4336
[email protected]9428edc2009-11-18 18:02:4737namespace errors = extension_manifest_errors;
[email protected]6bf90612013-08-15 00:36:2738namespace keys = extensions::manifest_keys;
[email protected]9428edc2009-11-18 18:02:4739
[email protected]1fca1492009-05-15 22:23:4340namespace {
[email protected]6d377142010-03-17 20:36:0541
[email protected]fcfd12f2009-08-14 22:20:4642// A limit to stop us passing dangerously large canvases to the browser.
43const int kMaxImageCanvas = 4096 * 4096;
44
[email protected]a7329162013-02-07 19:21:4845SkBitmap DecodeImage(const base::FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:1946 // Read the file from disk.
47 std::string file_contents;
[email protected]7567484142013-07-11 17:36:0748 if (!base::PathExists(path) ||
[email protected]82f84b92013-08-30 18:23:5049 !base::ReadFileToString(path, &file_contents)) {
[email protected]902f7cd2009-05-22 19:02:1950 return SkBitmap();
51 }
52
53 // Decode the image using WebKit's image decoder.
54 const unsigned char* data =
55 reinterpret_cast<const unsigned char*>(file_contents.data());
[email protected]e689cf252013-06-26 18:21:1456 SkBitmap bitmap = content::DecodeImage(data,
57 gfx::Size(),
58 file_contents.length());
[email protected]fcfd12f2009-08-14 22:20:4659 Sk64 bitmap_size = bitmap.getSize64();
60 if (!bitmap_size.is32() || bitmap_size.get32() > kMaxImageCanvas)
61 return SkBitmap();
62 return bitmap;
[email protected]902f7cd2009-05-22 19:02:1963}
64
[email protected]a7329162013-02-07 19:21:4865bool PathContainsParentDirectory(const base::FilePath& path) {
66 const base::FilePath::StringType kSeparators(base::FilePath::kSeparators);
67 const base::FilePath::StringType kParentDirectory(
68 base::FilePath::kParentDirectory);
69 const size_t npos = base::FilePath::StringType::npos;
70 const base::FilePath::StringType& value = path.value();
[email protected]902f7cd2009-05-22 19:02:1971
72 for (size_t i = 0; i < value.length(); ) {
73 i = value.find(kParentDirectory, i);
74 if (i != npos) {
75 if ((i == 0 || kSeparators.find(value[i-1]) == npos) &&
76 (i+1 < value.length() || kSeparators.find(value[i+1]) == npos)) {
77 return true;
78 }
79 ++i;
80 }
81 }
82
83 return false;
[email protected]1fca1492009-05-15 22:23:4384}
85
[email protected]3bb84992010-08-26 17:23:4686} // namespace
87
[email protected]b3fe68d2012-07-16 19:14:3988namespace extensions {
89
[email protected]43c05d902013-07-10 21:27:0090struct Unpacker::InternalData {
91 DecodedImages decoded_images;
92};
93
[email protected]a7329162013-02-07 19:21:4894Unpacker::Unpacker(const base::FilePath& extension_path,
[email protected]b3fe68d2012-07-16 19:14:3995 const std::string& extension_id,
[email protected]1d5e58b2013-01-31 08:41:4096 Manifest::Location location,
[email protected]b3fe68d2012-07-16 19:14:3997 int creation_flags)
[email protected]f5bf1842012-02-15 02:52:2698 : extension_path_(extension_path),
99 extension_id_(extension_id),
100 location_(location),
[email protected]fc38935a2011-10-31 23:53:28101 creation_flags_(creation_flags) {
[email protected]43c05d902013-07-10 21:27:00102 internal_data_.reset(new InternalData());
[email protected]3bb84992010-08-26 17:23:46103}
104
[email protected]b3fe68d2012-07-16 19:14:39105Unpacker::~Unpacker() {
[email protected]3bb84992010-08-26 17:23:46106}
107
[email protected]a371b4b2013-06-18 20:29:27108base::DictionaryValue* Unpacker::ReadManifest() {
[email protected]a7329162013-02-07 19:21:48109 base::FilePath manifest_path =
[email protected]993da5e2013-03-23 21:25:16110 temp_install_dir_.Append(kManifestFilename);
[email protected]7567484142013-07-11 17:36:07111 if (!base::PathExists(manifest_path)) {
[email protected]9428edc2009-11-18 18:02:47112 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19113 return NULL;
114 }
115
116 JSONFileValueSerializer serializer(manifest_path);
117 std::string error;
[email protected]a371b4b2013-06-18 20:29:27118 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
[email protected]902f7cd2009-05-22 19:02:19119 if (!root.get()) {
120 SetError(error);
121 return NULL;
122 }
123
[email protected]a371b4b2013-06-18 20:29:27124 if (!root->IsType(base::Value::TYPE_DICTIONARY)) {
[email protected]9428edc2009-11-18 18:02:47125 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19126 return NULL;
127 }
128
[email protected]a371b4b2013-06-18 20:29:27129 return static_cast<base::DictionaryValue*>(root.release());
[email protected]902f7cd2009-05-22 19:02:19130}
131
[email protected]b3fe68d2012-07-16 19:14:39132bool Unpacker::ReadAllMessageCatalogs(const std::string& default_locale) {
[email protected]a7329162013-02-07 19:21:48133 base::FilePath locales_path =
[email protected]993da5e2013-03-23 21:25:16134 temp_install_dir_.Append(kLocaleFolder);
[email protected]9428edc2009-11-18 18:02:47135
[email protected]1acbb4b62010-03-09 17:52:29136 // Not all folders under _locales have to be valid locales.
[email protected]25a4c1c2013-06-08 04:53:36137 base::FileEnumerator locales(locales_path,
138 false,
139 base::FileEnumerator::DIRECTORIES);
[email protected]9428edc2009-11-18 18:02:47140
[email protected]1acbb4b62010-03-09 17:52:29141 std::set<std::string> all_locales;
142 extension_l10n_util::GetAllLocales(&all_locales);
[email protected]a7329162013-02-07 19:21:48143 base::FilePath locale_path;
[email protected]1acbb4b62010-03-09 17:52:29144 while (!(locale_path = locales.Next()).empty()) {
145 if (extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
146 all_locales))
[email protected]9428edc2009-11-18 18:02:47147 continue;
148
[email protected]993da5e2013-03-23 21:25:16149 base::FilePath messages_path = locale_path.Append(kMessagesFilename);
[email protected]9428edc2009-11-18 18:02:47150
151 if (!ReadMessageCatalog(messages_path))
152 return false;
[email protected]1acbb4b62010-03-09 17:52:29153 }
[email protected]9428edc2009-11-18 18:02:47154
155 return true;
156}
157
[email protected]b3fe68d2012-07-16 19:14:39158bool Unpacker::Run() {
[email protected]26f025e2011-10-28 22:49:27159 DVLOG(1) << "Installing extension " << extension_path_.value();
[email protected]1fca1492009-05-15 22:23:43160
[email protected]3367f3a2012-09-01 02:40:06161 // <profile>/Extensions/CRX_INSTALL
[email protected]902f7cd2009-05-22 19:02:19162 temp_install_dir_ =
[email protected]b22c8af62013-07-23 23:17:02163 extension_path_.DirName().AppendASCII(kTempExtensionName);
[email protected]baedfdf2010-06-14 18:50:19164
[email protected]baedfdf2010-06-14 18:50:19165 if (!file_util::CreateDirectory(temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06166 SetUTF16Error(
167 l10n_util::GetStringFUTF16(
168 IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR,
169 base::i18n::GetDisplayStringInLTRDirectionality(
170 temp_install_dir_.LossyDisplayName())));
[email protected]1fca1492009-05-15 22:23:43171 return false;
172 }
173
[email protected]b3eb3dd22011-10-26 06:59:34174 if (!zip::Unzip(extension_path_, temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06175 SetUTF16Error(l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
[email protected]1fca1492009-05-15 22:23:43176 return false;
177 }
178
[email protected]902f7cd2009-05-22 19:02:19179 // Parse the manifest.
180 parsed_manifest_.reset(ReadManifest());
[email protected]a999d672012-01-23 22:31:40181 if (!parsed_manifest_.get())
[email protected]902f7cd2009-05-22 19:02:19182 return false; // Error was already reported.
[email protected]af1277b2009-07-28 00:47:53183
[email protected]fbcc40302009-06-12 20:45:45184 std::string error;
[email protected]1e0f45a2012-06-13 00:31:06185 scoped_refptr<Extension> extension(Extension::Create(
[email protected]542258c2011-03-04 21:25:31186 temp_install_dir_,
[email protected]fc38935a2011-10-31 23:53:28187 location_,
[email protected]542258c2011-03-04 21:25:31188 *parsed_manifest_,
[email protected]fc38935a2011-10-31 23:53:28189 creation_flags_,
[email protected]f5bf1842012-02-15 02:52:26190 extension_id_,
[email protected]542258c2011-03-04 21:25:31191 &error));
[email protected]66e4eb32010-10-27 20:37:41192 if (!extension.get()) {
[email protected]902f7cd2009-05-22 19:02:19193 SetError(error);
194 return false;
195 }
[email protected]99872e32009-09-25 22:02:49196
[email protected]1d5e58b2013-01-31 08:41:40197 std::vector<InstallWarning> warnings;
[email protected]ab55c2b2012-06-01 23:55:03198 if (!extension_file_util::ValidateExtension(extension.get(),
199 &error, &warnings)) {
[email protected]99872e32009-09-25 22:02:49200 SetError(error);
201 return false;
202 }
[email protected]ab55c2b2012-06-01 23:55:03203 extension->AddInstallWarnings(warnings);
[email protected]99872e32009-09-25 22:02:49204
[email protected]902f7cd2009-05-22 19:02:19205 // Decode any images that the browser needs to display.
[email protected]72b49d42013-04-19 12:47:31206 std::set<base::FilePath> image_paths =
[email protected]5c6ac842013-06-02 23:37:03207 extension_file_util::GetBrowserImagePaths(extension.get());
[email protected]a7329162013-02-07 19:21:48208 for (std::set<base::FilePath>::iterator it = image_paths.begin();
[email protected]5c6ac842013-06-02 23:37:03209 it != image_paths.end();
210 ++it) {
[email protected]facd7a7652009-06-05 23:15:02211 if (!AddDecodedImage(*it))
[email protected]902f7cd2009-05-22 19:02:19212 return false; // Error was already reported.
213 }
214
[email protected]9428edc2009-11-18 18:02:47215 // Parse all message catalogs (if any).
[email protected]a371b4b2013-06-18 20:29:27216 parsed_catalogs_.reset(new base::DictionaryValue);
[email protected]5c6ac842013-06-02 23:37:03217 if (!LocaleInfo::GetDefaultLocale(extension.get()).empty()) {
218 if (!ReadAllMessageCatalogs(LocaleInfo::GetDefaultLocale(extension.get())))
[email protected]9428edc2009-11-18 18:02:47219 return false; // Error was already reported.
220 }
221
[email protected]902f7cd2009-05-22 19:02:19222 return true;
223}
224
[email protected]b3fe68d2012-07-16 19:14:39225bool Unpacker::DumpImagesToFile() {
[email protected]facd7a7652009-06-05 23:15:02226 IPC::Message pickle; // We use a Message so we can use WriteParam.
[email protected]43c05d902013-07-10 21:27:00227 IPC::WriteParam(&pickle, internal_data_->decoded_images);
[email protected]facd7a7652009-06-05 23:15:02228
[email protected]a7329162013-02-07 19:21:48229 base::FilePath path = extension_path_.DirName().AppendASCII(
[email protected]b22c8af62013-07-23 23:17:02230 kDecodedImagesFilename);
[email protected]facd7a7652009-06-05 23:15:02231 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
232 pickle.size())) {
233 SetError("Could not write image data to disk.");
234 return false;
235 }
236
237 return true;
238}
239
[email protected]b3fe68d2012-07-16 19:14:39240bool Unpacker::DumpMessageCatalogsToFile() {
[email protected]6d377142010-03-17 20:36:05241 IPC::Message pickle;
242 IPC::WriteParam(&pickle, *parsed_catalogs_.get());
243
[email protected]a7329162013-02-07 19:21:48244 base::FilePath path = extension_path_.DirName().AppendASCII(
[email protected]b22c8af62013-07-23 23:17:02245 kDecodedMessageCatalogsFilename);
[email protected]6d377142010-03-17 20:36:05246 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
247 pickle.size())) {
248 SetError("Could not write message catalogs to disk.");
249 return false;
250 }
251
252 return true;
253}
254
[email protected]a7329162013-02-07 19:21:48255bool Unpacker::AddDecodedImage(const base::FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:19256 // Make sure it's not referencing a file outside the extension's subdir.
257 if (path.IsAbsolute() || PathContainsParentDirectory(path)) {
[email protected]3367f3a2012-09-01 02:40:06258 SetUTF16Error(
259 l10n_util::GetStringFUTF16(
260 IDS_EXTENSION_PACKAGE_IMAGE_PATH_ERROR,
261 base::i18n::GetDisplayStringInLTRDirectionality(
262 path.LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19263 return false;
264 }
265
266 SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
267 if (image_bitmap.isNull()) {
[email protected]3367f3a2012-09-01 02:40:06268 SetUTF16Error(
269 l10n_util::GetStringFUTF16(
270 IDS_EXTENSION_PACKAGE_IMAGE_ERROR,
271 base::i18n::GetDisplayStringInLTRDirectionality(
272 path.BaseName().LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19273 return false;
274 }
275
[email protected]43c05d902013-07-10 21:27:00276 internal_data_->decoded_images.push_back(MakeTuple(image_bitmap, path));
[email protected]1fca1492009-05-15 22:23:43277 return true;
278}
279
[email protected]a7329162013-02-07 19:21:48280bool Unpacker::ReadMessageCatalog(const base::FilePath& message_path) {
[email protected]9428edc2009-11-18 18:02:47281 std::string error;
282 JSONFileValueSerializer serializer(message_path);
[email protected]a371b4b2013-06-18 20:29:27283 scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>(
284 serializer.Deserialize(NULL, &error)));
[email protected]6d377142010-03-17 20:36:05285 if (!root.get()) {
[email protected]967d18b2011-03-02 22:22:07286 string16 messages_file = message_path.LossyDisplayName();
[email protected]9428edc2009-11-18 18:02:47287 if (error.empty()) {
288 // If file is missing, Deserialize will fail with empty error.
[email protected]93f10522010-10-31 16:27:48289 SetError(base::StringPrintf("%s %s", errors::kLocalesMessagesFileMissing,
[email protected]967d18b2011-03-02 22:22:07290 UTF16ToUTF8(messages_file).c_str()));
[email protected]9428edc2009-11-18 18:02:47291 } else {
[email protected]967d18b2011-03-02 22:22:07292 SetError(base::StringPrintf("%s: %s",
293 UTF16ToUTF8(messages_file).c_str(),
[email protected]93f10522010-10-31 16:27:48294 error.c_str()));
[email protected]9428edc2009-11-18 18:02:47295 }
296 return false;
297 }
298
[email protected]a7329162013-02-07 19:21:48299 base::FilePath relative_path;
[email protected]9428edc2009-11-18 18:02:47300 // message_path was created from temp_install_dir. This should never fail.
[email protected]967d18b2011-03-02 22:22:07301 if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) {
[email protected]9428edc2009-11-18 18:02:47302 NOTREACHED();
[email protected]967d18b2011-03-02 22:22:07303 return false;
304 }
[email protected]9428edc2009-11-18 18:02:47305
[email protected]967d18b2011-03-02 22:22:07306 std::string dir_name = relative_path.DirName().MaybeAsASCII();
307 if (dir_name.empty()) {
308 NOTREACHED();
309 return false;
310 }
311 parsed_catalogs_->Set(dir_name, root.release());
[email protected]9428edc2009-11-18 18:02:47312
313 return true;
314}
315
[email protected]b3fe68d2012-07-16 19:14:39316void Unpacker::SetError(const std::string &error) {
[email protected]3367f3a2012-09-01 02:40:06317 SetUTF16Error(UTF8ToUTF16(error));
318}
319
320void Unpacker::SetUTF16Error(const string16 &error) {
321 error_message_ = error;
[email protected]1fca1492009-05-15 22:23:43322}
[email protected]b3fe68d2012-07-16 19:14:39323
324} // namespace extensions