blob: bb450dfc66e24982467f03fa1b9b33d3562f1fca [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]b3fe68d2012-07-16 19:14:395#include "chrome/common/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]0273969d2013-01-30 22:16:3119#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
[email protected]5b1a0e22009-05-26 19:00:5820#include "chrome/common/extensions/extension.h"
[email protected]7c927b62010-02-24 09:54:1321#include "chrome/common/extensions/extension_file_util.h"
[email protected]1acbb4b62010-03-09 17:52:2922#include "chrome/common/extensions/extension_l10n_util.h"
[email protected]ea1a3f62012-11-16 20:34:2323#include "chrome/common/extensions/extension_manifest_constants.h"
[email protected]1d5e58b2013-01-31 08:41:4024#include "chrome/common/extensions/manifest.h"
[email protected]1fca1492009-05-15 22:23:4325#include "chrome/common/url_constants.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]3367f3a2012-09-01 02:40:0628#include "grit/generated_resources.h"
[email protected]946d1b22009-07-22 23:57:2129#include "ipc/ipc_message_utils.h"
[email protected]e0785902011-05-19 23:34:1730#include "net/base/file_stream.h"
[email protected]902f7cd2009-05-22 19:02:1931#include "third_party/skia/include/core/SkBitmap.h"
[email protected]4170d3a2013-05-03 23:02:5732#include "third_party/zlib/google/zip.h"
[email protected]3367f3a2012-09-01 02:40:0633#include "ui/base/l10n/l10n_util.h"
[email protected]902f7cd2009-05-22 19:02:1934#include "webkit/glue/image_decoder.h"
[email protected]1fca1492009-05-15 22:23:4335
[email protected]9428edc2009-11-18 18:02:4736namespace errors = extension_manifest_errors;
37namespace keys = extension_manifest_keys;
[email protected]b0b3abd92010-04-30 17:00:0938namespace filenames = extension_filenames;
[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;
48 if (!file_util::PathExists(path) ||
49 !file_util::ReadFileToString(path, &file_contents)) {
50 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());
56 webkit_glue::ImageDecoder decoder;
[email protected]fcfd12f2009-08-14 22:20:4657 SkBitmap bitmap = decoder.Decode(data, file_contents.length());
58 Sk64 bitmap_size = bitmap.getSize64();
59 if (!bitmap_size.is32() || bitmap_size.get32() > kMaxImageCanvas)
60 return SkBitmap();
61 return bitmap;
[email protected]902f7cd2009-05-22 19:02:1962}
63
[email protected]a7329162013-02-07 19:21:4864bool PathContainsParentDirectory(const base::FilePath& path) {
65 const base::FilePath::StringType kSeparators(base::FilePath::kSeparators);
66 const base::FilePath::StringType kParentDirectory(
67 base::FilePath::kParentDirectory);
68 const size_t npos = base::FilePath::StringType::npos;
69 const base::FilePath::StringType& value = path.value();
[email protected]902f7cd2009-05-22 19:02:1970
71 for (size_t i = 0; i < value.length(); ) {
72 i = value.find(kParentDirectory, i);
73 if (i != npos) {
74 if ((i == 0 || kSeparators.find(value[i-1]) == npos) &&
75 (i+1 < value.length() || kSeparators.find(value[i+1]) == npos)) {
76 return true;
77 }
78 ++i;
79 }
80 }
81
82 return false;
[email protected]1fca1492009-05-15 22:23:4383}
84
[email protected]3bb84992010-08-26 17:23:4685} // namespace
86
[email protected]b3fe68d2012-07-16 19:14:3987namespace extensions {
88
[email protected]a7329162013-02-07 19:21:4889Unpacker::Unpacker(const base::FilePath& extension_path,
[email protected]b3fe68d2012-07-16 19:14:3990 const std::string& extension_id,
[email protected]1d5e58b2013-01-31 08:41:4091 Manifest::Location location,
[email protected]b3fe68d2012-07-16 19:14:3992 int creation_flags)
[email protected]f5bf1842012-02-15 02:52:2693 : extension_path_(extension_path),
94 extension_id_(extension_id),
95 location_(location),
[email protected]fc38935a2011-10-31 23:53:2896 creation_flags_(creation_flags) {
[email protected]3bb84992010-08-26 17:23:4697}
98
[email protected]b3fe68d2012-07-16 19:14:3999Unpacker::~Unpacker() {
[email protected]3bb84992010-08-26 17:23:46100}
101
[email protected]b3fe68d2012-07-16 19:14:39102DictionaryValue* Unpacker::ReadManifest() {
[email protected]a7329162013-02-07 19:21:48103 base::FilePath manifest_path =
[email protected]993da5e2013-03-23 21:25:16104 temp_install_dir_.Append(kManifestFilename);
[email protected]902f7cd2009-05-22 19:02:19105 if (!file_util::PathExists(manifest_path)) {
[email protected]9428edc2009-11-18 18:02:47106 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19107 return NULL;
108 }
109
110 JSONFileValueSerializer serializer(manifest_path);
111 std::string error;
[email protected]ba399672010-04-06 15:42:39112 scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
[email protected]902f7cd2009-05-22 19:02:19113 if (!root.get()) {
114 SetError(error);
115 return NULL;
116 }
117
118 if (!root->IsType(Value::TYPE_DICTIONARY)) {
[email protected]9428edc2009-11-18 18:02:47119 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19120 return NULL;
121 }
122
123 return static_cast<DictionaryValue*>(root.release());
124}
125
[email protected]b3fe68d2012-07-16 19:14:39126bool Unpacker::ReadAllMessageCatalogs(const std::string& default_locale) {
[email protected]a7329162013-02-07 19:21:48127 base::FilePath locales_path =
[email protected]993da5e2013-03-23 21:25:16128 temp_install_dir_.Append(kLocaleFolder);
[email protected]9428edc2009-11-18 18:02:47129
[email protected]1acbb4b62010-03-09 17:52:29130 // Not all folders under _locales have to be valid locales.
[email protected]25a4c1c2013-06-08 04:53:36131 base::FileEnumerator locales(locales_path,
132 false,
133 base::FileEnumerator::DIRECTORIES);
[email protected]9428edc2009-11-18 18:02:47134
[email protected]1acbb4b62010-03-09 17:52:29135 std::set<std::string> all_locales;
136 extension_l10n_util::GetAllLocales(&all_locales);
[email protected]a7329162013-02-07 19:21:48137 base::FilePath locale_path;
[email protected]1acbb4b62010-03-09 17:52:29138 while (!(locale_path = locales.Next()).empty()) {
139 if (extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
140 all_locales))
[email protected]9428edc2009-11-18 18:02:47141 continue;
142
[email protected]993da5e2013-03-23 21:25:16143 base::FilePath messages_path = locale_path.Append(kMessagesFilename);
[email protected]9428edc2009-11-18 18:02:47144
145 if (!ReadMessageCatalog(messages_path))
146 return false;
[email protected]1acbb4b62010-03-09 17:52:29147 }
[email protected]9428edc2009-11-18 18:02:47148
149 return true;
150}
151
[email protected]b3fe68d2012-07-16 19:14:39152bool Unpacker::Run() {
[email protected]26f025e2011-10-28 22:49:27153 DVLOG(1) << "Installing extension " << extension_path_.value();
[email protected]1fca1492009-05-15 22:23:43154
[email protected]3367f3a2012-09-01 02:40:06155 // <profile>/Extensions/CRX_INSTALL
[email protected]902f7cd2009-05-22 19:02:19156 temp_install_dir_ =
[email protected]3367f3a2012-09-01 02:40:06157 extension_path_.DirName().AppendASCII(filenames::kTempExtensionName);
[email protected]baedfdf2010-06-14 18:50:19158
[email protected]baedfdf2010-06-14 18:50:19159 if (!file_util::CreateDirectory(temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06160 SetUTF16Error(
161 l10n_util::GetStringFUTF16(
162 IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR,
163 base::i18n::GetDisplayStringInLTRDirectionality(
164 temp_install_dir_.LossyDisplayName())));
[email protected]1fca1492009-05-15 22:23:43165 return false;
166 }
167
[email protected]b3eb3dd22011-10-26 06:59:34168 if (!zip::Unzip(extension_path_, temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06169 SetUTF16Error(l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
[email protected]1fca1492009-05-15 22:23:43170 return false;
171 }
172
[email protected]902f7cd2009-05-22 19:02:19173 // Parse the manifest.
174 parsed_manifest_.reset(ReadManifest());
[email protected]a999d672012-01-23 22:31:40175 if (!parsed_manifest_.get())
[email protected]902f7cd2009-05-22 19:02:19176 return false; // Error was already reported.
[email protected]af1277b2009-07-28 00:47:53177
[email protected]fbcc40302009-06-12 20:45:45178 std::string error;
[email protected]1e0f45a2012-06-13 00:31:06179 scoped_refptr<Extension> extension(Extension::Create(
[email protected]542258c2011-03-04 21:25:31180 temp_install_dir_,
[email protected]fc38935a2011-10-31 23:53:28181 location_,
[email protected]542258c2011-03-04 21:25:31182 *parsed_manifest_,
[email protected]fc38935a2011-10-31 23:53:28183 creation_flags_,
[email protected]f5bf1842012-02-15 02:52:26184 extension_id_,
[email protected]542258c2011-03-04 21:25:31185 &error));
[email protected]66e4eb32010-10-27 20:37:41186 if (!extension.get()) {
[email protected]902f7cd2009-05-22 19:02:19187 SetError(error);
188 return false;
189 }
[email protected]99872e32009-09-25 22:02:49190
[email protected]1d5e58b2013-01-31 08:41:40191 std::vector<InstallWarning> warnings;
[email protected]ab55c2b2012-06-01 23:55:03192 if (!extension_file_util::ValidateExtension(extension.get(),
193 &error, &warnings)) {
[email protected]99872e32009-09-25 22:02:49194 SetError(error);
195 return false;
196 }
[email protected]ab55c2b2012-06-01 23:55:03197 extension->AddInstallWarnings(warnings);
[email protected]99872e32009-09-25 22:02:49198
[email protected]902f7cd2009-05-22 19:02:19199 // Decode any images that the browser needs to display.
[email protected]72b49d42013-04-19 12:47:31200 std::set<base::FilePath> image_paths =
[email protected]5c6ac842013-06-02 23:37:03201 extension_file_util::GetBrowserImagePaths(extension.get());
[email protected]a7329162013-02-07 19:21:48202 for (std::set<base::FilePath>::iterator it = image_paths.begin();
[email protected]5c6ac842013-06-02 23:37:03203 it != image_paths.end();
204 ++it) {
[email protected]facd7a7652009-06-05 23:15:02205 if (!AddDecodedImage(*it))
[email protected]902f7cd2009-05-22 19:02:19206 return false; // Error was already reported.
207 }
208
[email protected]9428edc2009-11-18 18:02:47209 // Parse all message catalogs (if any).
210 parsed_catalogs_.reset(new DictionaryValue);
[email protected]5c6ac842013-06-02 23:37:03211 if (!LocaleInfo::GetDefaultLocale(extension.get()).empty()) {
212 if (!ReadAllMessageCatalogs(LocaleInfo::GetDefaultLocale(extension.get())))
[email protected]9428edc2009-11-18 18:02:47213 return false; // Error was already reported.
214 }
215
[email protected]902f7cd2009-05-22 19:02:19216 return true;
217}
218
[email protected]b3fe68d2012-07-16 19:14:39219bool Unpacker::DumpImagesToFile() {
[email protected]facd7a7652009-06-05 23:15:02220 IPC::Message pickle; // We use a Message so we can use WriteParam.
221 IPC::WriteParam(&pickle, decoded_images_);
222
[email protected]a7329162013-02-07 19:21:48223 base::FilePath path = extension_path_.DirName().AppendASCII(
[email protected]b0b3abd92010-04-30 17:00:09224 filenames::kDecodedImagesFilename);
[email protected]facd7a7652009-06-05 23:15:02225 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
226 pickle.size())) {
227 SetError("Could not write image data to disk.");
228 return false;
229 }
230
231 return true;
232}
233
[email protected]b3fe68d2012-07-16 19:14:39234bool Unpacker::DumpMessageCatalogsToFile() {
[email protected]6d377142010-03-17 20:36:05235 IPC::Message pickle;
236 IPC::WriteParam(&pickle, *parsed_catalogs_.get());
237
[email protected]a7329162013-02-07 19:21:48238 base::FilePath path = extension_path_.DirName().AppendASCII(
[email protected]b0b3abd92010-04-30 17:00:09239 filenames::kDecodedMessageCatalogsFilename);
[email protected]6d377142010-03-17 20:36:05240 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
241 pickle.size())) {
242 SetError("Could not write message catalogs to disk.");
243 return false;
244 }
245
246 return true;
247}
248
[email protected]facd7a7652009-06-05 23:15:02249// static
[email protected]a7329162013-02-07 19:21:48250bool Unpacker::ReadImagesFromFile(const base::FilePath& extension_path,
[email protected]b3fe68d2012-07-16 19:14:39251 DecodedImages* images) {
[email protected]a7329162013-02-07 19:21:48252 base::FilePath path =
253 extension_path.AppendASCII(filenames::kDecodedImagesFilename);
[email protected]facd7a7652009-06-05 23:15:02254 std::string file_str;
255 if (!file_util::ReadFileToString(path, &file_str))
256 return false;
257
258 IPC::Message pickle(file_str.data(), file_str.size());
[email protected]ce208f872012-03-07 20:42:56259 PickleIterator iter(pickle);
[email protected]facd7a7652009-06-05 23:15:02260 return IPC::ReadParam(&pickle, &iter, images);
261}
262
[email protected]6d377142010-03-17 20:36:05263// static
[email protected]a7329162013-02-07 19:21:48264bool Unpacker::ReadMessageCatalogsFromFile(const base::FilePath& extension_path,
[email protected]b3fe68d2012-07-16 19:14:39265 DictionaryValue* catalogs) {
[email protected]a7329162013-02-07 19:21:48266 base::FilePath path = extension_path.AppendASCII(
[email protected]b0b3abd92010-04-30 17:00:09267 filenames::kDecodedMessageCatalogsFilename);
[email protected]6d377142010-03-17 20:36:05268 std::string file_str;
269 if (!file_util::ReadFileToString(path, &file_str))
270 return false;
271
272 IPC::Message pickle(file_str.data(), file_str.size());
[email protected]ce208f872012-03-07 20:42:56273 PickleIterator iter(pickle);
[email protected]6d377142010-03-17 20:36:05274 return IPC::ReadParam(&pickle, &iter, catalogs);
275}
276
[email protected]a7329162013-02-07 19:21:48277bool Unpacker::AddDecodedImage(const base::FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:19278 // Make sure it's not referencing a file outside the extension's subdir.
279 if (path.IsAbsolute() || PathContainsParentDirectory(path)) {
[email protected]3367f3a2012-09-01 02:40:06280 SetUTF16Error(
281 l10n_util::GetStringFUTF16(
282 IDS_EXTENSION_PACKAGE_IMAGE_PATH_ERROR,
283 base::i18n::GetDisplayStringInLTRDirectionality(
284 path.LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19285 return false;
286 }
287
288 SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
289 if (image_bitmap.isNull()) {
[email protected]3367f3a2012-09-01 02:40:06290 SetUTF16Error(
291 l10n_util::GetStringFUTF16(
292 IDS_EXTENSION_PACKAGE_IMAGE_ERROR,
293 base::i18n::GetDisplayStringInLTRDirectionality(
294 path.BaseName().LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19295 return false;
296 }
297
298 decoded_images_.push_back(MakeTuple(image_bitmap, path));
[email protected]1fca1492009-05-15 22:23:43299 return true;
300}
301
[email protected]a7329162013-02-07 19:21:48302bool Unpacker::ReadMessageCatalog(const base::FilePath& message_path) {
[email protected]9428edc2009-11-18 18:02:47303 std::string error;
304 JSONFileValueSerializer serializer(message_path);
[email protected]6d377142010-03-17 20:36:05305 scoped_ptr<DictionaryValue> root(
[email protected]ba399672010-04-06 15:42:39306 static_cast<DictionaryValue*>(serializer.Deserialize(NULL, &error)));
[email protected]6d377142010-03-17 20:36:05307 if (!root.get()) {
[email protected]967d18b2011-03-02 22:22:07308 string16 messages_file = message_path.LossyDisplayName();
[email protected]9428edc2009-11-18 18:02:47309 if (error.empty()) {
310 // If file is missing, Deserialize will fail with empty error.
[email protected]93f10522010-10-31 16:27:48311 SetError(base::StringPrintf("%s %s", errors::kLocalesMessagesFileMissing,
[email protected]967d18b2011-03-02 22:22:07312 UTF16ToUTF8(messages_file).c_str()));
[email protected]9428edc2009-11-18 18:02:47313 } else {
[email protected]967d18b2011-03-02 22:22:07314 SetError(base::StringPrintf("%s: %s",
315 UTF16ToUTF8(messages_file).c_str(),
[email protected]93f10522010-10-31 16:27:48316 error.c_str()));
[email protected]9428edc2009-11-18 18:02:47317 }
318 return false;
319 }
320
[email protected]a7329162013-02-07 19:21:48321 base::FilePath relative_path;
[email protected]9428edc2009-11-18 18:02:47322 // message_path was created from temp_install_dir. This should never fail.
[email protected]967d18b2011-03-02 22:22:07323 if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) {
[email protected]9428edc2009-11-18 18:02:47324 NOTREACHED();
[email protected]967d18b2011-03-02 22:22:07325 return false;
326 }
[email protected]9428edc2009-11-18 18:02:47327
[email protected]967d18b2011-03-02 22:22:07328 std::string dir_name = relative_path.DirName().MaybeAsASCII();
329 if (dir_name.empty()) {
330 NOTREACHED();
331 return false;
332 }
333 parsed_catalogs_->Set(dir_name, root.release());
[email protected]9428edc2009-11-18 18:02:47334
335 return true;
336}
337
[email protected]b3fe68d2012-07-16 19:14:39338void Unpacker::SetError(const std::string &error) {
[email protected]3367f3a2012-09-01 02:40:06339 SetUTF16Error(UTF8ToUTF16(error));
340}
341
342void Unpacker::SetUTF16Error(const string16 &error) {
343 error_message_ = error;
[email protected]1fca1492009-05-15 22:23:43344}
[email protected]b3fe68d2012-07-16 19:14:39345
346} // namespace extensions