blob: 41bf772d985e186b737688a776deaa19775632fe [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]ea1a3f62012-11-16 20:34:2310#include "base/files/scoped_temp_dir.h"
[email protected]3367f3a2012-09-01 02:40:0611#include "base/i18n/rtl.h"
[email protected]ffbec692012-02-26 20:26:4212#include "base/json/json_file_value_serializer.h"
[email protected]3b63f8f42011-03-28 01:54:1513#include "base/memory/scoped_handle.h"
[email protected]1fca1492009-05-15 22:23:4314#include "base/string_util.h"
[email protected]34b99632011-01-01 01:01:0615#include "base/threading/thread.h"
[email protected]99922662010-08-17 16:24:2516#include "base/utf_string_conversions.h"
[email protected]1fca1492009-05-15 22:23:4317#include "base/values.h"
[email protected]0273969d2013-01-30 22:16:3118#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
[email protected]5b1a0e22009-05-26 19:00:5819#include "chrome/common/extensions/extension.h"
[email protected]7c927b62010-02-24 09:54:1320#include "chrome/common/extensions/extension_file_util.h"
[email protected]1acbb4b62010-03-09 17:52:2921#include "chrome/common/extensions/extension_l10n_util.h"
[email protected]ea1a3f62012-11-16 20:34:2322#include "chrome/common/extensions/extension_manifest_constants.h"
[email protected]1d5e58b2013-01-31 08:41:4023#include "chrome/common/extensions/manifest.h"
[email protected]1fca1492009-05-15 22:23:4324#include "chrome/common/url_constants.h"
[email protected]facd7a7652009-06-05 23:15:0225#include "chrome/common/zip.h"
[email protected]19a5c7442011-10-21 20:00:4126#include "content/public/common/common_param_traits.h"
[email protected]3367f3a2012-09-01 02:40:0627#include "grit/generated_resources.h"
[email protected]946d1b22009-07-22 23:57:2128#include "ipc/ipc_message_utils.h"
[email protected]e0785902011-05-19 23:34:1729#include "net/base/file_stream.h"
[email protected]902f7cd2009-05-22 19:02:1930#include "third_party/skia/include/core/SkBitmap.h"
[email protected]3367f3a2012-09-01 02:40:0631#include "ui/base/l10n/l10n_util.h"
[email protected]902f7cd2009-05-22 19:02:1932#include "webkit/glue/image_decoder.h"
[email protected]1fca1492009-05-15 22:23:4333
[email protected]9428edc2009-11-18 18:02:4734namespace errors = extension_manifest_errors;
35namespace keys = extension_manifest_keys;
[email protected]b0b3abd92010-04-30 17:00:0936namespace filenames = extension_filenames;
[email protected]9428edc2009-11-18 18:02:4737
[email protected]1fca1492009-05-15 22:23:4338namespace {
[email protected]6d377142010-03-17 20:36:0539
[email protected]fcfd12f2009-08-14 22:20:4640// A limit to stop us passing dangerously large canvases to the browser.
41const int kMaxImageCanvas = 4096 * 4096;
42
[email protected]3bb84992010-08-26 17:23:4643SkBitmap DecodeImage(const FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:1944 // Read the file from disk.
45 std::string file_contents;
46 if (!file_util::PathExists(path) ||
47 !file_util::ReadFileToString(path, &file_contents)) {
48 return SkBitmap();
49 }
50
51 // Decode the image using WebKit's image decoder.
52 const unsigned char* data =
53 reinterpret_cast<const unsigned char*>(file_contents.data());
54 webkit_glue::ImageDecoder decoder;
[email protected]fcfd12f2009-08-14 22:20:4655 SkBitmap bitmap = decoder.Decode(data, file_contents.length());
56 Sk64 bitmap_size = bitmap.getSize64();
57 if (!bitmap_size.is32() || bitmap_size.get32() > kMaxImageCanvas)
58 return SkBitmap();
59 return bitmap;
[email protected]902f7cd2009-05-22 19:02:1960}
61
[email protected]3bb84992010-08-26 17:23:4662bool PathContainsParentDirectory(const FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:1963 const FilePath::StringType kSeparators(FilePath::kSeparators);
64 const FilePath::StringType kParentDirectory(FilePath::kParentDirectory);
65 const size_t npos = FilePath::StringType::npos;
66 const FilePath::StringType& value = path.value();
67
68 for (size_t i = 0; i < value.length(); ) {
69 i = value.find(kParentDirectory, i);
70 if (i != npos) {
71 if ((i == 0 || kSeparators.find(value[i-1]) == npos) &&
72 (i+1 < value.length() || kSeparators.find(value[i+1]) == npos)) {
73 return true;
74 }
75 ++i;
76 }
77 }
78
79 return false;
[email protected]1fca1492009-05-15 22:23:4380}
81
[email protected]3bb84992010-08-26 17:23:4682} // namespace
83
[email protected]b3fe68d2012-07-16 19:14:3984namespace extensions {
85
86Unpacker::Unpacker(const FilePath& extension_path,
87 const std::string& extension_id,
[email protected]1d5e58b2013-01-31 08:41:4088 Manifest::Location location,
[email protected]b3fe68d2012-07-16 19:14:3989 int creation_flags)
[email protected]f5bf1842012-02-15 02:52:2690 : extension_path_(extension_path),
91 extension_id_(extension_id),
92 location_(location),
[email protected]fc38935a2011-10-31 23:53:2893 creation_flags_(creation_flags) {
[email protected]3bb84992010-08-26 17:23:4694}
95
[email protected]b3fe68d2012-07-16 19:14:3996Unpacker::~Unpacker() {
[email protected]3bb84992010-08-26 17:23:4697}
98
[email protected]b3fe68d2012-07-16 19:14:3999DictionaryValue* Unpacker::ReadManifest() {
[email protected]902f7cd2009-05-22 19:02:19100 FilePath manifest_path =
[email protected]1e0f45a2012-06-13 00:31:06101 temp_install_dir_.Append(Extension::kManifestFilename);
[email protected]902f7cd2009-05-22 19:02:19102 if (!file_util::PathExists(manifest_path)) {
[email protected]9428edc2009-11-18 18:02:47103 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19104 return NULL;
105 }
106
107 JSONFileValueSerializer serializer(manifest_path);
108 std::string error;
[email protected]ba399672010-04-06 15:42:39109 scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
[email protected]902f7cd2009-05-22 19:02:19110 if (!root.get()) {
111 SetError(error);
112 return NULL;
113 }
114
115 if (!root->IsType(Value::TYPE_DICTIONARY)) {
[email protected]9428edc2009-11-18 18:02:47116 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19117 return NULL;
118 }
119
120 return static_cast<DictionaryValue*>(root.release());
121}
122
[email protected]b3fe68d2012-07-16 19:14:39123bool Unpacker::ReadAllMessageCatalogs(const std::string& default_locale) {
[email protected]9428edc2009-11-18 18:02:47124 FilePath locales_path =
[email protected]1e0f45a2012-06-13 00:31:06125 temp_install_dir_.Append(Extension::kLocaleFolder);
[email protected]9428edc2009-11-18 18:02:47126
[email protected]1acbb4b62010-03-09 17:52:29127 // Not all folders under _locales have to be valid locales.
[email protected]9428edc2009-11-18 18:02:47128 file_util::FileEnumerator locales(locales_path,
129 false,
130 file_util::FileEnumerator::DIRECTORIES);
131
[email protected]1acbb4b62010-03-09 17:52:29132 std::set<std::string> all_locales;
133 extension_l10n_util::GetAllLocales(&all_locales);
134 FilePath locale_path;
135 while (!(locale_path = locales.Next()).empty()) {
136 if (extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
137 all_locales))
[email protected]9428edc2009-11-18 18:02:47138 continue;
139
140 FilePath messages_path =
[email protected]1e0f45a2012-06-13 00:31:06141 locale_path.Append(Extension::kMessagesFilename);
[email protected]9428edc2009-11-18 18:02:47142
143 if (!ReadMessageCatalog(messages_path))
144 return false;
[email protected]1acbb4b62010-03-09 17:52:29145 }
[email protected]9428edc2009-11-18 18:02:47146
147 return true;
148}
149
[email protected]b3fe68d2012-07-16 19:14:39150bool Unpacker::Run() {
[email protected]26f025e2011-10-28 22:49:27151 DVLOG(1) << "Installing extension " << extension_path_.value();
[email protected]1fca1492009-05-15 22:23:43152
[email protected]3367f3a2012-09-01 02:40:06153 // <profile>/Extensions/CRX_INSTALL
[email protected]902f7cd2009-05-22 19:02:19154 temp_install_dir_ =
[email protected]3367f3a2012-09-01 02:40:06155 extension_path_.DirName().AppendASCII(filenames::kTempExtensionName);
[email protected]baedfdf2010-06-14 18:50:19156
[email protected]baedfdf2010-06-14 18:50:19157 if (!file_util::CreateDirectory(temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06158 SetUTF16Error(
159 l10n_util::GetStringFUTF16(
160 IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR,
161 base::i18n::GetDisplayStringInLTRDirectionality(
162 temp_install_dir_.LossyDisplayName())));
[email protected]1fca1492009-05-15 22:23:43163 return false;
164 }
165
[email protected]b3eb3dd22011-10-26 06:59:34166 if (!zip::Unzip(extension_path_, temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06167 SetUTF16Error(l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
[email protected]1fca1492009-05-15 22:23:43168 return false;
169 }
170
[email protected]902f7cd2009-05-22 19:02:19171 // Parse the manifest.
172 parsed_manifest_.reset(ReadManifest());
[email protected]a999d672012-01-23 22:31:40173 if (!parsed_manifest_.get())
[email protected]902f7cd2009-05-22 19:02:19174 return false; // Error was already reported.
[email protected]af1277b2009-07-28 00:47:53175
[email protected]fbcc40302009-06-12 20:45:45176 std::string error;
[email protected]1e0f45a2012-06-13 00:31:06177 scoped_refptr<Extension> extension(Extension::Create(
[email protected]542258c2011-03-04 21:25:31178 temp_install_dir_,
[email protected]fc38935a2011-10-31 23:53:28179 location_,
[email protected]542258c2011-03-04 21:25:31180 *parsed_manifest_,
[email protected]fc38935a2011-10-31 23:53:28181 creation_flags_,
[email protected]f5bf1842012-02-15 02:52:26182 extension_id_,
[email protected]542258c2011-03-04 21:25:31183 &error));
[email protected]66e4eb32010-10-27 20:37:41184 if (!extension.get()) {
[email protected]902f7cd2009-05-22 19:02:19185 SetError(error);
186 return false;
187 }
[email protected]99872e32009-09-25 22:02:49188
[email protected]1d5e58b2013-01-31 08:41:40189 std::vector<InstallWarning> warnings;
[email protected]ab55c2b2012-06-01 23:55:03190 if (!extension_file_util::ValidateExtension(extension.get(),
191 &error, &warnings)) {
[email protected]99872e32009-09-25 22:02:49192 SetError(error);
193 return false;
194 }
[email protected]ab55c2b2012-06-01 23:55:03195 extension->AddInstallWarnings(warnings);
[email protected]99872e32009-09-25 22:02:49196
[email protected]902f7cd2009-05-22 19:02:19197 // Decode any images that the browser needs to display.
[email protected]66e4eb32010-10-27 20:37:41198 std::set<FilePath> image_paths = extension->GetBrowserImages();
[email protected]facd7a7652009-06-05 23:15:02199 for (std::set<FilePath>::iterator it = image_paths.begin();
200 it != image_paths.end(); ++it) {
201 if (!AddDecodedImage(*it))
[email protected]902f7cd2009-05-22 19:02:19202 return false; // Error was already reported.
203 }
204
[email protected]9428edc2009-11-18 18:02:47205 // Parse all message catalogs (if any).
206 parsed_catalogs_.reset(new DictionaryValue);
[email protected]0273969d2013-01-30 22:16:31207 if (!LocaleInfo::GetDefaultLocale(extension).empty()) {
208 if (!ReadAllMessageCatalogs(LocaleInfo::GetDefaultLocale(extension)))
[email protected]9428edc2009-11-18 18:02:47209 return false; // Error was already reported.
210 }
211
[email protected]902f7cd2009-05-22 19:02:19212 return true;
213}
214
[email protected]b3fe68d2012-07-16 19:14:39215bool Unpacker::DumpImagesToFile() {
[email protected]facd7a7652009-06-05 23:15:02216 IPC::Message pickle; // We use a Message so we can use WriteParam.
217 IPC::WriteParam(&pickle, decoded_images_);
218
[email protected]b0b3abd92010-04-30 17:00:09219 FilePath path = extension_path_.DirName().AppendASCII(
220 filenames::kDecodedImagesFilename);
[email protected]facd7a7652009-06-05 23:15:02221 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
222 pickle.size())) {
223 SetError("Could not write image data to disk.");
224 return false;
225 }
226
227 return true;
228}
229
[email protected]b3fe68d2012-07-16 19:14:39230bool Unpacker::DumpMessageCatalogsToFile() {
[email protected]6d377142010-03-17 20:36:05231 IPC::Message pickle;
232 IPC::WriteParam(&pickle, *parsed_catalogs_.get());
233
234 FilePath path = extension_path_.DirName().AppendASCII(
[email protected]b0b3abd92010-04-30 17:00:09235 filenames::kDecodedMessageCatalogsFilename);
[email protected]6d377142010-03-17 20:36:05236 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
237 pickle.size())) {
238 SetError("Could not write message catalogs to disk.");
239 return false;
240 }
241
242 return true;
243}
244
[email protected]facd7a7652009-06-05 23:15:02245// static
[email protected]b3fe68d2012-07-16 19:14:39246bool Unpacker::ReadImagesFromFile(const FilePath& extension_path,
247 DecodedImages* images) {
[email protected]b0b3abd92010-04-30 17:00:09248 FilePath path = extension_path.AppendASCII(filenames::kDecodedImagesFilename);
[email protected]facd7a7652009-06-05 23:15:02249 std::string file_str;
250 if (!file_util::ReadFileToString(path, &file_str))
251 return false;
252
253 IPC::Message pickle(file_str.data(), file_str.size());
[email protected]ce208f872012-03-07 20:42:56254 PickleIterator iter(pickle);
[email protected]facd7a7652009-06-05 23:15:02255 return IPC::ReadParam(&pickle, &iter, images);
256}
257
[email protected]6d377142010-03-17 20:36:05258// static
[email protected]b3fe68d2012-07-16 19:14:39259bool Unpacker::ReadMessageCatalogsFromFile(const FilePath& extension_path,
260 DictionaryValue* catalogs) {
[email protected]b0b3abd92010-04-30 17:00:09261 FilePath path = extension_path.AppendASCII(
262 filenames::kDecodedMessageCatalogsFilename);
[email protected]6d377142010-03-17 20:36:05263 std::string file_str;
264 if (!file_util::ReadFileToString(path, &file_str))
265 return false;
266
267 IPC::Message pickle(file_str.data(), file_str.size());
[email protected]ce208f872012-03-07 20:42:56268 PickleIterator iter(pickle);
[email protected]6d377142010-03-17 20:36:05269 return IPC::ReadParam(&pickle, &iter, catalogs);
270}
271
[email protected]b3fe68d2012-07-16 19:14:39272bool Unpacker::AddDecodedImage(const FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:19273 // Make sure it's not referencing a file outside the extension's subdir.
274 if (path.IsAbsolute() || PathContainsParentDirectory(path)) {
[email protected]3367f3a2012-09-01 02:40:06275 SetUTF16Error(
276 l10n_util::GetStringFUTF16(
277 IDS_EXTENSION_PACKAGE_IMAGE_PATH_ERROR,
278 base::i18n::GetDisplayStringInLTRDirectionality(
279 path.LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19280 return false;
281 }
282
283 SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
284 if (image_bitmap.isNull()) {
[email protected]3367f3a2012-09-01 02:40:06285 SetUTF16Error(
286 l10n_util::GetStringFUTF16(
287 IDS_EXTENSION_PACKAGE_IMAGE_ERROR,
288 base::i18n::GetDisplayStringInLTRDirectionality(
289 path.BaseName().LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19290 return false;
291 }
292
293 decoded_images_.push_back(MakeTuple(image_bitmap, path));
[email protected]1fca1492009-05-15 22:23:43294 return true;
295}
296
[email protected]b3fe68d2012-07-16 19:14:39297bool Unpacker::ReadMessageCatalog(const FilePath& message_path) {
[email protected]9428edc2009-11-18 18:02:47298 std::string error;
299 JSONFileValueSerializer serializer(message_path);
[email protected]6d377142010-03-17 20:36:05300 scoped_ptr<DictionaryValue> root(
[email protected]ba399672010-04-06 15:42:39301 static_cast<DictionaryValue*>(serializer.Deserialize(NULL, &error)));
[email protected]6d377142010-03-17 20:36:05302 if (!root.get()) {
[email protected]967d18b2011-03-02 22:22:07303 string16 messages_file = message_path.LossyDisplayName();
[email protected]9428edc2009-11-18 18:02:47304 if (error.empty()) {
305 // If file is missing, Deserialize will fail with empty error.
[email protected]93f10522010-10-31 16:27:48306 SetError(base::StringPrintf("%s %s", errors::kLocalesMessagesFileMissing,
[email protected]967d18b2011-03-02 22:22:07307 UTF16ToUTF8(messages_file).c_str()));
[email protected]9428edc2009-11-18 18:02:47308 } else {
[email protected]967d18b2011-03-02 22:22:07309 SetError(base::StringPrintf("%s: %s",
310 UTF16ToUTF8(messages_file).c_str(),
[email protected]93f10522010-10-31 16:27:48311 error.c_str()));
[email protected]9428edc2009-11-18 18:02:47312 }
313 return false;
314 }
315
316 FilePath relative_path;
317 // message_path was created from temp_install_dir. This should never fail.
[email protected]967d18b2011-03-02 22:22:07318 if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) {
[email protected]9428edc2009-11-18 18:02:47319 NOTREACHED();
[email protected]967d18b2011-03-02 22:22:07320 return false;
321 }
[email protected]9428edc2009-11-18 18:02:47322
[email protected]967d18b2011-03-02 22:22:07323 std::string dir_name = relative_path.DirName().MaybeAsASCII();
324 if (dir_name.empty()) {
325 NOTREACHED();
326 return false;
327 }
328 parsed_catalogs_->Set(dir_name, root.release());
[email protected]9428edc2009-11-18 18:02:47329
330 return true;
331}
332
[email protected]b3fe68d2012-07-16 19:14:39333void Unpacker::SetError(const std::string &error) {
[email protected]3367f3a2012-09-01 02:40:06334 SetUTF16Error(UTF8ToUTF16(error));
335}
336
337void Unpacker::SetUTF16Error(const string16 &error) {
338 error_message_ = error;
[email protected]1fca1492009-05-15 22:23:43339}
[email protected]b3fe68d2012-07-16 19:14:39340
341} // namespace extensions