blob: 9fb5aae9bba8b1f82a469e8e804aef7a0e75317c [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]12bfb612013-06-07 19:54:0215#include "base/strings/utf_string_conversions.h"
[email protected]34b99632011-01-01 01:01:0616#include "base/threading/thread.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]19a5c7442011-10-21 20:00:4125#include "content/public/common/common_param_traits.h"
[email protected]993da5e2013-03-23 21:25:1626#include "extensions/common/constants.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]4170d3a2013-05-03 23:02:5731#include "third_party/zlib/google/zip.h"
[email protected]3367f3a2012-09-01 02:40:0632#include "ui/base/l10n/l10n_util.h"
[email protected]902f7cd2009-05-22 19:02:1933#include "webkit/glue/image_decoder.h"
[email protected]1fca1492009-05-15 22:23:4334
[email protected]9428edc2009-11-18 18:02:4735namespace errors = extension_manifest_errors;
36namespace keys = extension_manifest_keys;
[email protected]b0b3abd92010-04-30 17:00:0937namespace filenames = extension_filenames;
[email protected]9428edc2009-11-18 18:02:4738
[email protected]1fca1492009-05-15 22:23:4339namespace {
[email protected]6d377142010-03-17 20:36:0540
[email protected]fcfd12f2009-08-14 22:20:4641// A limit to stop us passing dangerously large canvases to the browser.
42const int kMaxImageCanvas = 4096 * 4096;
43
[email protected]a7329162013-02-07 19:21:4844SkBitmap DecodeImage(const base::FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:1945 // Read the file from disk.
46 std::string file_contents;
47 if (!file_util::PathExists(path) ||
48 !file_util::ReadFileToString(path, &file_contents)) {
49 return SkBitmap();
50 }
51
52 // Decode the image using WebKit's image decoder.
53 const unsigned char* data =
54 reinterpret_cast<const unsigned char*>(file_contents.data());
55 webkit_glue::ImageDecoder decoder;
[email protected]fcfd12f2009-08-14 22:20:4656 SkBitmap bitmap = decoder.Decode(data, file_contents.length());
57 Sk64 bitmap_size = bitmap.getSize64();
58 if (!bitmap_size.is32() || bitmap_size.get32() > kMaxImageCanvas)
59 return SkBitmap();
60 return bitmap;
[email protected]902f7cd2009-05-22 19:02:1961}
62
[email protected]a7329162013-02-07 19:21:4863bool PathContainsParentDirectory(const base::FilePath& path) {
64 const base::FilePath::StringType kSeparators(base::FilePath::kSeparators);
65 const base::FilePath::StringType kParentDirectory(
66 base::FilePath::kParentDirectory);
67 const size_t npos = base::FilePath::StringType::npos;
68 const base::FilePath::StringType& value = path.value();
[email protected]902f7cd2009-05-22 19:02:1969
70 for (size_t i = 0; i < value.length(); ) {
71 i = value.find(kParentDirectory, i);
72 if (i != npos) {
73 if ((i == 0 || kSeparators.find(value[i-1]) == npos) &&
74 (i+1 < value.length() || kSeparators.find(value[i+1]) == npos)) {
75 return true;
76 }
77 ++i;
78 }
79 }
80
81 return false;
[email protected]1fca1492009-05-15 22:23:4382}
83
[email protected]3bb84992010-08-26 17:23:4684} // namespace
85
[email protected]b3fe68d2012-07-16 19:14:3986namespace extensions {
87
[email protected]a7329162013-02-07 19:21:4888Unpacker::Unpacker(const base::FilePath& extension_path,
[email protected]b3fe68d2012-07-16 19:14:3989 const std::string& extension_id,
[email protected]1d5e58b2013-01-31 08:41:4090 Manifest::Location location,
[email protected]b3fe68d2012-07-16 19:14:3991 int creation_flags)
[email protected]f5bf1842012-02-15 02:52:2692 : extension_path_(extension_path),
93 extension_id_(extension_id),
94 location_(location),
[email protected]fc38935a2011-10-31 23:53:2895 creation_flags_(creation_flags) {
[email protected]3bb84992010-08-26 17:23:4696}
97
[email protected]b3fe68d2012-07-16 19:14:3998Unpacker::~Unpacker() {
[email protected]3bb84992010-08-26 17:23:4699}
100
[email protected]b3fe68d2012-07-16 19:14:39101DictionaryValue* Unpacker::ReadManifest() {
[email protected]a7329162013-02-07 19:21:48102 base::FilePath manifest_path =
[email protected]993da5e2013-03-23 21:25:16103 temp_install_dir_.Append(kManifestFilename);
[email protected]902f7cd2009-05-22 19:02:19104 if (!file_util::PathExists(manifest_path)) {
[email protected]9428edc2009-11-18 18:02:47105 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19106 return NULL;
107 }
108
109 JSONFileValueSerializer serializer(manifest_path);
110 std::string error;
[email protected]ba399672010-04-06 15:42:39111 scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
[email protected]902f7cd2009-05-22 19:02:19112 if (!root.get()) {
113 SetError(error);
114 return NULL;
115 }
116
117 if (!root->IsType(Value::TYPE_DICTIONARY)) {
[email protected]9428edc2009-11-18 18:02:47118 SetError(errors::kInvalidManifest);
[email protected]902f7cd2009-05-22 19:02:19119 return NULL;
120 }
121
122 return static_cast<DictionaryValue*>(root.release());
123}
124
[email protected]b3fe68d2012-07-16 19:14:39125bool Unpacker::ReadAllMessageCatalogs(const std::string& default_locale) {
[email protected]a7329162013-02-07 19:21:48126 base::FilePath locales_path =
[email protected]993da5e2013-03-23 21:25:16127 temp_install_dir_.Append(kLocaleFolder);
[email protected]9428edc2009-11-18 18:02:47128
[email protected]1acbb4b62010-03-09 17:52:29129 // Not all folders under _locales have to be valid locales.
[email protected]9e66a9b2013-05-08 05:46:20130 file_util::FileEnumerator locales(locales_path,
131 false,
132 file_util::FileEnumerator::DIRECTORIES);
[email protected]9428edc2009-11-18 18:02:47133
[email protected]1acbb4b62010-03-09 17:52:29134 std::set<std::string> all_locales;
135 extension_l10n_util::GetAllLocales(&all_locales);
[email protected]a7329162013-02-07 19:21:48136 base::FilePath locale_path;
[email protected]1acbb4b62010-03-09 17:52:29137 while (!(locale_path = locales.Next()).empty()) {
138 if (extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
139 all_locales))
[email protected]9428edc2009-11-18 18:02:47140 continue;
141
[email protected]993da5e2013-03-23 21:25:16142 base::FilePath messages_path = locale_path.Append(kMessagesFilename);
[email protected]9428edc2009-11-18 18:02:47143
144 if (!ReadMessageCatalog(messages_path))
145 return false;
[email protected]1acbb4b62010-03-09 17:52:29146 }
[email protected]9428edc2009-11-18 18:02:47147
148 return true;
149}
150
[email protected]b3fe68d2012-07-16 19:14:39151bool Unpacker::Run() {
[email protected]26f025e2011-10-28 22:49:27152 DVLOG(1) << "Installing extension " << extension_path_.value();
[email protected]1fca1492009-05-15 22:23:43153
[email protected]3367f3a2012-09-01 02:40:06154 // <profile>/Extensions/CRX_INSTALL
[email protected]902f7cd2009-05-22 19:02:19155 temp_install_dir_ =
[email protected]3367f3a2012-09-01 02:40:06156 extension_path_.DirName().AppendASCII(filenames::kTempExtensionName);
[email protected]baedfdf2010-06-14 18:50:19157
[email protected]baedfdf2010-06-14 18:50:19158 if (!file_util::CreateDirectory(temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06159 SetUTF16Error(
160 l10n_util::GetStringFUTF16(
161 IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR,
162 base::i18n::GetDisplayStringInLTRDirectionality(
163 temp_install_dir_.LossyDisplayName())));
[email protected]1fca1492009-05-15 22:23:43164 return false;
165 }
166
[email protected]b3eb3dd22011-10-26 06:59:34167 if (!zip::Unzip(extension_path_, temp_install_dir_)) {
[email protected]3367f3a2012-09-01 02:40:06168 SetUTF16Error(l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
[email protected]1fca1492009-05-15 22:23:43169 return false;
170 }
171
[email protected]902f7cd2009-05-22 19:02:19172 // Parse the manifest.
173 parsed_manifest_.reset(ReadManifest());
[email protected]a999d672012-01-23 22:31:40174 if (!parsed_manifest_.get())
[email protected]902f7cd2009-05-22 19:02:19175 return false; // Error was already reported.
[email protected]af1277b2009-07-28 00:47:53176
[email protected]fbcc40302009-06-12 20:45:45177 std::string error;
[email protected]1e0f45a2012-06-13 00:31:06178 scoped_refptr<Extension> extension(Extension::Create(
[email protected]542258c2011-03-04 21:25:31179 temp_install_dir_,
[email protected]fc38935a2011-10-31 23:53:28180 location_,
[email protected]542258c2011-03-04 21:25:31181 *parsed_manifest_,
[email protected]fc38935a2011-10-31 23:53:28182 creation_flags_,
[email protected]f5bf1842012-02-15 02:52:26183 extension_id_,
[email protected]542258c2011-03-04 21:25:31184 &error));
[email protected]66e4eb32010-10-27 20:37:41185 if (!extension.get()) {
[email protected]902f7cd2009-05-22 19:02:19186 SetError(error);
187 return false;
188 }
[email protected]99872e32009-09-25 22:02:49189
[email protected]1d5e58b2013-01-31 08:41:40190 std::vector<InstallWarning> warnings;
[email protected]ab55c2b2012-06-01 23:55:03191 if (!extension_file_util::ValidateExtension(extension.get(),
192 &error, &warnings)) {
[email protected]99872e32009-09-25 22:02:49193 SetError(error);
194 return false;
195 }
[email protected]ab55c2b2012-06-01 23:55:03196 extension->AddInstallWarnings(warnings);
[email protected]99872e32009-09-25 22:02:49197
[email protected]902f7cd2009-05-22 19:02:19198 // Decode any images that the browser needs to display.
[email protected]72b49d42013-04-19 12:47:31199 std::set<base::FilePath> image_paths =
[email protected]5c6ac842013-06-02 23:37:03200 extension_file_util::GetBrowserImagePaths(extension.get());
[email protected]a7329162013-02-07 19:21:48201 for (std::set<base::FilePath>::iterator it = image_paths.begin();
[email protected]5c6ac842013-06-02 23:37:03202 it != image_paths.end();
203 ++it) {
[email protected]facd7a7652009-06-05 23:15:02204 if (!AddDecodedImage(*it))
[email protected]902f7cd2009-05-22 19:02:19205 return false; // Error was already reported.
206 }
207
[email protected]9428edc2009-11-18 18:02:47208 // Parse all message catalogs (if any).
209 parsed_catalogs_.reset(new DictionaryValue);
[email protected]5c6ac842013-06-02 23:37:03210 if (!LocaleInfo::GetDefaultLocale(extension.get()).empty()) {
211 if (!ReadAllMessageCatalogs(LocaleInfo::GetDefaultLocale(extension.get())))
[email protected]9428edc2009-11-18 18:02:47212 return false; // Error was already reported.
213 }
214
[email protected]902f7cd2009-05-22 19:02:19215 return true;
216}
217
[email protected]b3fe68d2012-07-16 19:14:39218bool Unpacker::DumpImagesToFile() {
[email protected]facd7a7652009-06-05 23:15:02219 IPC::Message pickle; // We use a Message so we can use WriteParam.
220 IPC::WriteParam(&pickle, decoded_images_);
221
[email protected]a7329162013-02-07 19:21:48222 base::FilePath path = extension_path_.DirName().AppendASCII(
[email protected]b0b3abd92010-04-30 17:00:09223 filenames::kDecodedImagesFilename);
[email protected]facd7a7652009-06-05 23:15:02224 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
225 pickle.size())) {
226 SetError("Could not write image data to disk.");
227 return false;
228 }
229
230 return true;
231}
232
[email protected]b3fe68d2012-07-16 19:14:39233bool Unpacker::DumpMessageCatalogsToFile() {
[email protected]6d377142010-03-17 20:36:05234 IPC::Message pickle;
235 IPC::WriteParam(&pickle, *parsed_catalogs_.get());
236
[email protected]a7329162013-02-07 19:21:48237 base::FilePath path = extension_path_.DirName().AppendASCII(
[email protected]b0b3abd92010-04-30 17:00:09238 filenames::kDecodedMessageCatalogsFilename);
[email protected]6d377142010-03-17 20:36:05239 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
240 pickle.size())) {
241 SetError("Could not write message catalogs to disk.");
242 return false;
243 }
244
245 return true;
246}
247
[email protected]facd7a7652009-06-05 23:15:02248// static
[email protected]a7329162013-02-07 19:21:48249bool Unpacker::ReadImagesFromFile(const base::FilePath& extension_path,
[email protected]b3fe68d2012-07-16 19:14:39250 DecodedImages* images) {
[email protected]a7329162013-02-07 19:21:48251 base::FilePath path =
252 extension_path.AppendASCII(filenames::kDecodedImagesFilename);
[email protected]facd7a7652009-06-05 23:15:02253 std::string file_str;
254 if (!file_util::ReadFileToString(path, &file_str))
255 return false;
256
257 IPC::Message pickle(file_str.data(), file_str.size());
[email protected]ce208f872012-03-07 20:42:56258 PickleIterator iter(pickle);
[email protected]facd7a7652009-06-05 23:15:02259 return IPC::ReadParam(&pickle, &iter, images);
260}
261
[email protected]6d377142010-03-17 20:36:05262// static
[email protected]a7329162013-02-07 19:21:48263bool Unpacker::ReadMessageCatalogsFromFile(const base::FilePath& extension_path,
[email protected]b3fe68d2012-07-16 19:14:39264 DictionaryValue* catalogs) {
[email protected]a7329162013-02-07 19:21:48265 base::FilePath path = extension_path.AppendASCII(
[email protected]b0b3abd92010-04-30 17:00:09266 filenames::kDecodedMessageCatalogsFilename);
[email protected]6d377142010-03-17 20:36:05267 std::string file_str;
268 if (!file_util::ReadFileToString(path, &file_str))
269 return false;
270
271 IPC::Message pickle(file_str.data(), file_str.size());
[email protected]ce208f872012-03-07 20:42:56272 PickleIterator iter(pickle);
[email protected]6d377142010-03-17 20:36:05273 return IPC::ReadParam(&pickle, &iter, catalogs);
274}
275
[email protected]a7329162013-02-07 19:21:48276bool Unpacker::AddDecodedImage(const base::FilePath& path) {
[email protected]902f7cd2009-05-22 19:02:19277 // Make sure it's not referencing a file outside the extension's subdir.
278 if (path.IsAbsolute() || PathContainsParentDirectory(path)) {
[email protected]3367f3a2012-09-01 02:40:06279 SetUTF16Error(
280 l10n_util::GetStringFUTF16(
281 IDS_EXTENSION_PACKAGE_IMAGE_PATH_ERROR,
282 base::i18n::GetDisplayStringInLTRDirectionality(
283 path.LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19284 return false;
285 }
286
287 SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
288 if (image_bitmap.isNull()) {
[email protected]3367f3a2012-09-01 02:40:06289 SetUTF16Error(
290 l10n_util::GetStringFUTF16(
291 IDS_EXTENSION_PACKAGE_IMAGE_ERROR,
292 base::i18n::GetDisplayStringInLTRDirectionality(
293 path.BaseName().LossyDisplayName())));
[email protected]902f7cd2009-05-22 19:02:19294 return false;
295 }
296
297 decoded_images_.push_back(MakeTuple(image_bitmap, path));
[email protected]1fca1492009-05-15 22:23:43298 return true;
299}
300
[email protected]a7329162013-02-07 19:21:48301bool Unpacker::ReadMessageCatalog(const base::FilePath& message_path) {
[email protected]9428edc2009-11-18 18:02:47302 std::string error;
303 JSONFileValueSerializer serializer(message_path);
[email protected]6d377142010-03-17 20:36:05304 scoped_ptr<DictionaryValue> root(
[email protected]ba399672010-04-06 15:42:39305 static_cast<DictionaryValue*>(serializer.Deserialize(NULL, &error)));
[email protected]6d377142010-03-17 20:36:05306 if (!root.get()) {
[email protected]967d18b2011-03-02 22:22:07307 string16 messages_file = message_path.LossyDisplayName();
[email protected]9428edc2009-11-18 18:02:47308 if (error.empty()) {
309 // If file is missing, Deserialize will fail with empty error.
[email protected]93f10522010-10-31 16:27:48310 SetError(base::StringPrintf("%s %s", errors::kLocalesMessagesFileMissing,
[email protected]967d18b2011-03-02 22:22:07311 UTF16ToUTF8(messages_file).c_str()));
[email protected]9428edc2009-11-18 18:02:47312 } else {
[email protected]967d18b2011-03-02 22:22:07313 SetError(base::StringPrintf("%s: %s",
314 UTF16ToUTF8(messages_file).c_str(),
[email protected]93f10522010-10-31 16:27:48315 error.c_str()));
[email protected]9428edc2009-11-18 18:02:47316 }
317 return false;
318 }
319
[email protected]a7329162013-02-07 19:21:48320 base::FilePath relative_path;
[email protected]9428edc2009-11-18 18:02:47321 // message_path was created from temp_install_dir. This should never fail.
[email protected]967d18b2011-03-02 22:22:07322 if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) {
[email protected]9428edc2009-11-18 18:02:47323 NOTREACHED();
[email protected]967d18b2011-03-02 22:22:07324 return false;
325 }
[email protected]9428edc2009-11-18 18:02:47326
[email protected]967d18b2011-03-02 22:22:07327 std::string dir_name = relative_path.DirName().MaybeAsASCII();
328 if (dir_name.empty()) {
329 NOTREACHED();
330 return false;
331 }
332 parsed_catalogs_->Set(dir_name, root.release());
[email protected]9428edc2009-11-18 18:02:47333
334 return true;
335}
336
[email protected]b3fe68d2012-07-16 19:14:39337void Unpacker::SetError(const std::string &error) {
[email protected]3367f3a2012-09-01 02:40:06338 SetUTF16Error(UTF8ToUTF16(error));
339}
340
341void Unpacker::SetUTF16Error(const string16 &error) {
342 error_message_ = error;
[email protected]1fca1492009-05-15 22:23:43343}
[email protected]b3fe68d2012-07-16 19:14:39344
345} // namespace extensions