| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/sandboxed_extension_unpacker.h" | 5 #include "chrome/browser/extensions/sandboxed_extension_unpacker.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "app/l10n_util.h" |
| 9 #include "base/base64.h" | 10 #include "base/base64.h" |
| 10 #include "base/crypto/signature_verifier.h" | 11 #include "base/crypto/signature_verifier.h" |
| 11 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 12 #include "base/file_util_proxy.h" | 13 #include "base/file_util_proxy.h" |
| 13 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 14 #include "base/scoped_handle.h" | 15 #include "base/scoped_handle.h" |
| 15 #include "base/task.h" | 16 #include "base/task.h" |
| 16 #include "base/utf_string_conversions.h" // TODO(viettrungluu): delete me. | 17 #include "base/utf_string_conversions.h" // TODO(viettrungluu): delete me. |
| 17 #include "chrome/browser/browser_thread.h" | 18 #include "chrome/browser/browser_thread.h" |
| 18 #include "chrome/browser/extensions/extension_service.h" | 19 #include "chrome/browser/extensions/extension_service.h" |
| 19 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" | 20 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" |
| 20 #include "chrome/common/chrome_switches.h" | 21 #include "chrome/common/chrome_switches.h" |
| 21 #include "chrome/common/extensions/extension.h" | 22 #include "chrome/common/extensions/extension.h" |
| 22 #include "chrome/common/extensions/extension_constants.h" | 23 #include "chrome/common/extensions/extension_constants.h" |
| 23 #include "chrome/common/extensions/extension_file_util.h" | 24 #include "chrome/common/extensions/extension_file_util.h" |
| 24 #include "chrome/common/extensions/extension_l10n_util.h" | 25 #include "chrome/common/extensions/extension_l10n_util.h" |
| 25 #include "chrome/common/extensions/extension_unpacker.h" | 26 #include "chrome/common/extensions/extension_unpacker.h" |
| 26 #include "chrome/common/json_value_serializer.h" | 27 #include "chrome/common/json_value_serializer.h" |
| 27 #include "gfx/codec/png_codec.h" | 28 #include "gfx/codec/png_codec.h" |
| 29 #include "grit/generated_resources.h" |
| 28 #include "third_party/skia/include/core/SkBitmap.h" | 30 #include "third_party/skia/include/core/SkBitmap.h" |
| 29 | 31 |
| 30 const char SandboxedExtensionUnpacker::kExtensionHeaderMagic[] = "Cr24"; | 32 const char SandboxedExtensionUnpacker::kExtensionHeaderMagic[] = "Cr24"; |
| 31 | 33 |
| 32 SandboxedExtensionUnpacker::SandboxedExtensionUnpacker( | 34 SandboxedExtensionUnpacker::SandboxedExtensionUnpacker( |
| 33 const FilePath& crx_path, | 35 const FilePath& crx_path, |
| 34 const FilePath& temp_path, | 36 const FilePath& temp_path, |
| 35 ResourceDispatcherHost* rdh, | 37 ResourceDispatcherHost* rdh, |
| 36 SandboxedExtensionUnpackerClient* client) | 38 SandboxedExtensionUnpackerClient* client) |
| 37 : crx_path_(crx_path), temp_path_(temp_path), | 39 : crx_path_(crx_path), temp_path_(temp_path), |
| 38 thread_identifier_(BrowserThread::ID_COUNT), | 40 thread_identifier_(BrowserThread::ID_COUNT), |
| 39 rdh_(rdh), client_(client), got_response_(false) { | 41 rdh_(rdh), client_(client), got_response_(false) { |
| 40 } | 42 } |
| 41 | 43 |
| 42 void SandboxedExtensionUnpacker::Start() { | 44 void SandboxedExtensionUnpacker::Start() { |
| 43 // We assume that we are started on the thread that the client wants us to do | 45 // We assume that we are started on the thread that the client wants us to do |
| 44 // file IO on. | 46 // file IO on. |
| 45 CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_identifier_)); | 47 CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_identifier_)); |
| 46 | 48 |
| 47 // Create a temporary directory to work in. | 49 // Create a temporary directory to work in. |
| 48 if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_)) { | 50 if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_)) { |
| 49 ReportFailure("Could not create temporary directory."); | 51 // Could not create temporary directory. |
| 52 ReportFailure(l10n_util::GetStringFUTF8( |
| 53 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 54 ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); |
| 50 return; | 55 return; |
| 51 } | 56 } |
| 52 | 57 |
| 53 // Initialize the path that will eventually contain the unpacked extension. | 58 // Initialize the path that will eventually contain the unpacked extension. |
| 54 extension_root_ = temp_dir_.path().AppendASCII( | 59 extension_root_ = temp_dir_.path().AppendASCII( |
| 55 extension_filenames::kTempExtensionName); | 60 extension_filenames::kTempExtensionName); |
| 56 | 61 |
| 57 // Extract the public key and validate the package. | 62 // Extract the public key and validate the package. |
| 58 if (!ValidateSignature()) | 63 if (!ValidateSignature()) |
| 59 return; // ValidateSignature() already reported the error. | 64 return; // ValidateSignature() already reported the error. |
| 60 | 65 |
| 61 // Copy the crx file into our working directory. | 66 // Copy the crx file into our working directory. |
| 62 FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName()); | 67 FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName()); |
| 63 if (!file_util::CopyFile(crx_path_, temp_crx_path)) { | 68 if (!file_util::CopyFile(crx_path_, temp_crx_path)) { |
| 64 ReportFailure("Failed to copy extension file to temporary directory."); | 69 // Failed to copy extension file to temporary directory. |
| 70 ReportFailure(l10n_util::GetStringFUTF8( |
| 71 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 72 ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY"))); |
| 65 return; | 73 return; |
| 66 } | 74 } |
| 67 | 75 |
| 68 // If we are supposed to use a subprocess, kick off the subprocess. | 76 // If we are supposed to use a subprocess, kick off the subprocess. |
| 69 // | 77 // |
| 70 // TODO(asargent) we shouldn't need to do this branch here - instead | 78 // TODO(asargent) we shouldn't need to do this branch here - instead |
| 71 // UtilityProcessHost should handle it for us. (http://crbug.com/19192) | 79 // UtilityProcessHost should handle it for us. (http://crbug.com/19192) |
| 72 bool use_utility_process = rdh_ && | 80 bool use_utility_process = rdh_ && |
| 73 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); | 81 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); |
| 74 if (use_utility_process) { | 82 if (use_utility_process) { |
| 75 // The utility process will have access to the directory passed to | 83 // The utility process will have access to the directory passed to |
| 76 // SandboxedExtensionUnpacker. That directory should not contain a | 84 // SandboxedExtensionUnpacker. That directory should not contain a |
| 77 // symlink or NTFS reparse point. When the path is used, following | 85 // symlink or NTFS reparse point. When the path is used, following |
| 78 // the link/reparse point will cause file system access outside the | 86 // the link/reparse point will cause file system access outside the |
| 79 // sandbox path, and the sandbox will deny the operation. | 87 // sandbox path, and the sandbox will deny the operation. |
| 80 FilePath link_free_crx_path; | 88 FilePath link_free_crx_path; |
| 81 if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { | 89 if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { |
| 82 LOG(ERROR) << "Could not get the normalized path of " | 90 LOG(ERROR) << "Could not get the normalized path of " |
| 83 << temp_crx_path.value(); | 91 << temp_crx_path.value(); |
| 84 #if defined (OS_WIN) | 92 ReportFailure(l10n_util::GetStringUTF8(IDS_EXTENSION_UNPACK_FAILED)); |
| 85 // On windows, it is possible to mount a disk without the root of that | |
| 86 // disk having a drive letter. The sandbox does not support this. | |
| 87 // See crbug/49530 . | |
| 88 ReportFailure( | |
| 89 "Can not unpack extension. To safely unpack an extension, " | |
| 90 "there must be a path to your profile directory that starts " | |
| 91 "with a drive letter and does not contain a junction, mount " | |
| 92 "point, or symlink. No such path exists for your profile."); | |
| 93 #else | |
| 94 ReportFailure( | |
| 95 "Can not unpack extension. To safely unpack an extension, " | |
| 96 "there must be a path to your profile directory that does " | |
| 97 "not contain a symlink. No such path exists for your profile."); | |
| 98 #endif | |
| 99 return; | 93 return; |
| 100 } | 94 } |
| 101 | 95 |
| 102 BrowserThread::PostTask( | 96 BrowserThread::PostTask( |
| 103 BrowserThread::IO, FROM_HERE, | 97 BrowserThread::IO, FROM_HERE, |
| 104 NewRunnableMethod( | 98 NewRunnableMethod( |
| 105 this, | 99 this, |
| 106 &SandboxedExtensionUnpacker::StartProcessOnIOThread, | 100 &SandboxedExtensionUnpacker::StartProcessOnIOThread, |
| 107 link_free_crx_path)); | 101 link_free_crx_path)); |
| 108 } else { | 102 } else { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 // Create an extension object that refers to the temporary location the | 140 // Create an extension object that refers to the temporary location the |
| 147 // extension was unpacked to. We use this until the extension is finally | 141 // extension was unpacked to. We use this until the extension is finally |
| 148 // installed. For example, the install UI shows images from inside the | 142 // installed. For example, the install UI shows images from inside the |
| 149 // extension. | 143 // extension. |
| 150 | 144 |
| 151 // Localize manifest now, so confirm UI gets correct extension name. | 145 // Localize manifest now, so confirm UI gets correct extension name. |
| 152 std::string error; | 146 std::string error; |
| 153 if (!extension_l10n_util::LocalizeExtension(extension_root_, | 147 if (!extension_l10n_util::LocalizeExtension(extension_root_, |
| 154 final_manifest.get(), | 148 final_manifest.get(), |
| 155 &error)) { | 149 &error)) { |
| 156 ReportFailure(error); | 150 ReportFailure(l10n_util::GetStringFUTF8( |
| 151 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, |
| 152 ASCIIToUTF16(error))); |
| 157 return; | 153 return; |
| 158 } | 154 } |
| 159 | 155 |
| 160 extension_ = Extension::Create( | 156 extension_ = Extension::Create( |
| 161 extension_root_, Extension::INTERNAL, *final_manifest, true, &error); | 157 extension_root_, Extension::INTERNAL, *final_manifest, true, &error); |
| 162 | 158 |
| 163 if (!extension_.get()) { | 159 if (!extension_.get()) { |
| 164 ReportFailure(std::string("Manifest is invalid: ") + error); | 160 ReportFailure(std::string("Manifest is invalid: ") + error); |
| 165 return; | 161 return; |
| 166 } | 162 } |
| 167 | 163 |
| 168 if (!RewriteImageFiles()) | 164 if (!RewriteImageFiles()) |
| 169 return; | 165 return; |
| 170 | 166 |
| 171 if (!RewriteCatalogFiles()) | 167 if (!RewriteCatalogFiles()) |
| 172 return; | 168 return; |
| 173 | 169 |
| 174 ReportSuccess(); | 170 ReportSuccess(); |
| 175 } | 171 } |
| 176 | 172 |
| 177 void SandboxedExtensionUnpacker::OnUnpackExtensionFailed( | 173 void SandboxedExtensionUnpacker::OnUnpackExtensionFailed( |
| 178 const std::string& error) { | 174 const std::string& error) { |
| 179 DCHECK(BrowserThread::CurrentlyOn(thread_identifier_)); | 175 DCHECK(BrowserThread::CurrentlyOn(thread_identifier_)); |
| 180 got_response_ = true; | 176 got_response_ = true; |
| 181 ReportFailure(error); | 177 ReportFailure(l10n_util::GetStringFUTF8( |
| 178 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, |
| 179 ASCIIToUTF16(error))); |
| 182 } | 180 } |
| 183 | 181 |
| 184 void SandboxedExtensionUnpacker::OnProcessCrashed(int exit_code) { | 182 void SandboxedExtensionUnpacker::OnProcessCrashed(int exit_code) { |
| 185 // Don't report crashes if they happen after we got a response. | 183 // Don't report crashes if they happen after we got a response. |
| 186 if (got_response_) | 184 if (got_response_) |
| 187 return; | 185 return; |
| 188 | 186 |
| 189 ReportFailure("Utility process crashed while trying to install."); | 187 // Utility process crashed while trying to install. |
| 188 ReportFailure(l10n_util::GetStringFUTF8( |
| 189 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 190 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL"))); |
| 190 } | 191 } |
| 191 | 192 |
| 192 bool SandboxedExtensionUnpacker::ValidateSignature() { | 193 bool SandboxedExtensionUnpacker::ValidateSignature() { |
| 193 ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb")); | 194 ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb")); |
| 194 if (!file.get()) { | 195 if (!file.get()) { |
| 195 ReportFailure("Could not open crx file for reading"); | 196 // Could not open crx file for reading |
| 197 ReportFailure(l10n_util::GetStringFUTF8( |
| 198 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 199 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); |
| 196 return false; | 200 return false; |
| 197 } | 201 } |
| 198 | 202 |
| 199 // Read and verify the header. | 203 // Read and verify the header. |
| 200 ExtensionHeader header; | 204 ExtensionHeader header; |
| 201 size_t len; | 205 size_t len; |
| 202 | 206 |
| 203 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it | 207 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it |
| 204 // appears that we don't have any endian/alignment aware serialization | 208 // appears that we don't have any endian/alignment aware serialization |
| 205 // code in the code base. So for now, this assumes that we're running | 209 // code in the code base. So for now, this assumes that we're running |
| 206 // on a little endian machine with 4 byte alignment. | 210 // on a little endian machine with 4 byte alignment. |
| 207 len = fread(&header, 1, sizeof(ExtensionHeader), | 211 len = fread(&header, 1, sizeof(ExtensionHeader), |
| 208 file.get()); | 212 file.get()); |
| 209 if (len < sizeof(ExtensionHeader)) { | 213 if (len < sizeof(ExtensionHeader)) { |
| 210 ReportFailure("Invalid crx header"); | 214 // Invalid crx header |
| 215 ReportFailure(l10n_util::GetStringFUTF8( |
| 216 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 217 ASCIIToUTF16("CRX_HEADER_INVALID"))); |
| 211 return false; | 218 return false; |
| 212 } | 219 } |
| 213 if (strncmp(kExtensionHeaderMagic, header.magic, | 220 if (strncmp(kExtensionHeaderMagic, header.magic, |
| 214 sizeof(header.magic))) { | 221 sizeof(header.magic))) { |
| 215 ReportFailure("Bad magic number"); | 222 // Bad magic number |
| 223 ReportFailure(l10n_util::GetStringFUTF8( |
| 224 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 225 ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID"))); |
| 216 return false; | 226 return false; |
| 217 } | 227 } |
| 218 if (header.version != kCurrentVersion) { | 228 if (header.version != kCurrentVersion) { |
| 219 ReportFailure("Bad version number"); | 229 // Bad version numer |
| 230 ReportFailure(l10n_util::GetStringFUTF8( |
| 231 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 232 ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID"))); |
| 220 return false; | 233 return false; |
| 221 } | 234 } |
| 222 if (header.key_size > kMaxPublicKeySize || | 235 if (header.key_size > kMaxPublicKeySize || |
| 223 header.signature_size > kMaxSignatureSize) { | 236 header.signature_size > kMaxSignatureSize) { |
| 224 ReportFailure("Excessively large key or signature"); | 237 // Excessively large key or signature |
| 238 ReportFailure(l10n_util::GetStringFUTF8( |
| 239 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 240 ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE"))); |
| 225 return false; | 241 return false; |
| 226 } | 242 } |
| 227 if (header.key_size == 0) { | 243 if (header.key_size == 0) { |
| 228 ReportFailure("Key length is zero"); | 244 // Key length is zero |
| 245 ReportFailure(l10n_util::GetStringFUTF8( |
| 246 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 247 ASCIIToUTF16("CRX_ZERO_KEY_LENGTH"))); |
| 229 return false; | 248 return false; |
| 230 } | 249 } |
| 231 if (header.signature_size == 0) { | 250 if (header.signature_size == 0) { |
| 232 ReportFailure("Signature length is zero"); | 251 // Signature length is zero |
| 252 ReportFailure(l10n_util::GetStringFUTF8( |
| 253 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 254 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); |
| 233 return false; | 255 return false; |
| 234 } | 256 } |
| 235 | 257 |
| 236 std::vector<uint8> key; | 258 std::vector<uint8> key; |
| 237 key.resize(header.key_size); | 259 key.resize(header.key_size); |
| 238 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); | 260 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); |
| 239 if (len < header.key_size) { | 261 if (len < header.key_size) { |
| 240 ReportFailure("Invalid public key"); | 262 // Invalid public key |
| 263 ReportFailure(l10n_util::GetStringFUTF8( |
| 264 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 265 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); |
| 241 return false; | 266 return false; |
| 242 } | 267 } |
| 243 | 268 |
| 244 std::vector<uint8> signature; | 269 std::vector<uint8> signature; |
| 245 signature.resize(header.signature_size); | 270 signature.resize(header.signature_size); |
| 246 len = fread(&signature.front(), sizeof(uint8), header.signature_size, | 271 len = fread(&signature.front(), sizeof(uint8), header.signature_size, |
| 247 file.get()); | 272 file.get()); |
| 248 if (len < header.signature_size) { | 273 if (len < header.signature_size) { |
| 249 ReportFailure("Invalid signature"); | 274 // Invalid signature |
| 275 ReportFailure(l10n_util::GetStringFUTF8( |
| 276 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 277 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); |
| 250 return false; | 278 return false; |
| 251 } | 279 } |
| 252 | 280 |
| 253 base::SignatureVerifier verifier; | 281 base::SignatureVerifier verifier; |
| 254 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm, | 282 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm, |
| 255 sizeof(extension_misc::kSignatureAlgorithm), | 283 sizeof(extension_misc::kSignatureAlgorithm), |
| 256 &signature.front(), | 284 &signature.front(), |
| 257 signature.size(), | 285 signature.size(), |
| 258 &key.front(), | 286 &key.front(), |
| 259 key.size())) { | 287 key.size())) { |
| 260 ReportFailure("Signature verification initialization failed. " | 288 // Signature verification initialization failed. This is most likely |
| 261 "This is most likely caused by a public key in " | 289 // caused by a public key in the wrong format (should encode algorithm). |
| 262 "the wrong format (should encode algorithm)."); | 290 ReportFailure(l10n_util::GetStringFUTF8( |
| 291 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 292 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); |
| 263 return false; | 293 return false; |
| 264 } | 294 } |
| 265 | 295 |
| 266 unsigned char buf[1 << 12]; | 296 unsigned char buf[1 << 12]; |
| 267 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) | 297 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) |
| 268 verifier.VerifyUpdate(buf, len); | 298 verifier.VerifyUpdate(buf, len); |
| 269 | 299 |
| 270 if (!verifier.VerifyFinal()) { | 300 if (!verifier.VerifyFinal()) { |
| 271 ReportFailure("Signature verification failed"); | 301 // Signature verification failed |
| 302 ReportFailure(l10n_util::GetStringFUTF8( |
| 303 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 304 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); |
| 272 return false; | 305 return false; |
| 273 } | 306 } |
| 274 | 307 |
| 275 base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), | 308 base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), |
| 276 key.size()), &public_key_); | 309 key.size()), &public_key_); |
| 277 return true; | 310 return true; |
| 278 } | 311 } |
| 279 | 312 |
| 280 void SandboxedExtensionUnpacker::ReportFailure(const std::string& error) { | 313 void SandboxedExtensionUnpacker::ReportFailure(const std::string& error) { |
| 281 client_->OnUnpackFailure(error); | 314 client_->OnUnpackFailure(error); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 293 // the original manifest. We do this to ensure the manifest doesn't contain an | 326 // the original manifest. We do this to ensure the manifest doesn't contain an |
| 294 // exploitable bug that could be used to compromise the browser. | 327 // exploitable bug that could be used to compromise the browser. |
| 295 scoped_ptr<DictionaryValue> final_manifest( | 328 scoped_ptr<DictionaryValue> final_manifest( |
| 296 static_cast<DictionaryValue*>(manifest.DeepCopy())); | 329 static_cast<DictionaryValue*>(manifest.DeepCopy())); |
| 297 final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); | 330 final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); |
| 298 | 331 |
| 299 std::string manifest_json; | 332 std::string manifest_json; |
| 300 JSONStringValueSerializer serializer(&manifest_json); | 333 JSONStringValueSerializer serializer(&manifest_json); |
| 301 serializer.set_pretty_print(true); | 334 serializer.set_pretty_print(true); |
| 302 if (!serializer.Serialize(*final_manifest)) { | 335 if (!serializer.Serialize(*final_manifest)) { |
| 303 ReportFailure("Error serializing manifest.json."); | 336 // Error serializing manifest.json. |
| 337 ReportFailure(l10n_util::GetStringFUTF8( |
| 338 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 339 ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); |
| 304 return NULL; | 340 return NULL; |
| 305 } | 341 } |
| 306 | 342 |
| 307 FilePath manifest_path = | 343 FilePath manifest_path = |
| 308 extension_root_.Append(Extension::kManifestFilename); | 344 extension_root_.Append(Extension::kManifestFilename); |
| 309 if (!file_util::WriteFile(manifest_path, | 345 if (!file_util::WriteFile(manifest_path, |
| 310 manifest_json.data(), manifest_json.size())) { | 346 manifest_json.data(), manifest_json.size())) { |
| 311 ReportFailure("Error saving manifest.json."); | 347 // Error saving manifest.json. |
| 348 ReportFailure(l10n_util::GetStringFUTF8( |
| 349 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 350 ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); |
| 312 return NULL; | 351 return NULL; |
| 313 } | 352 } |
| 314 | 353 |
| 315 return final_manifest.release(); | 354 return final_manifest.release(); |
| 316 } | 355 } |
| 317 | 356 |
| 318 bool SandboxedExtensionUnpacker::RewriteImageFiles() { | 357 bool SandboxedExtensionUnpacker::RewriteImageFiles() { |
| 319 ExtensionUnpacker::DecodedImages images; | 358 ExtensionUnpacker::DecodedImages images; |
| 320 if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { | 359 if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { |
| 321 ReportFailure("Couldn't read image data from disk."); | 360 // Couldn't read image data from disk. |
| 361 ReportFailure(l10n_util::GetStringFUTF8( |
| 362 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 363 ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK"))); |
| 322 return false; | 364 return false; |
| 323 } | 365 } |
| 324 | 366 |
| 325 // Delete any images that may be used by the browser. We're going to write | 367 // Delete any images that may be used by the browser. We're going to write |
| 326 // out our own versions of the parsed images, and we want to make sure the | 368 // out our own versions of the parsed images, and we want to make sure the |
| 327 // originals are gone for good. | 369 // originals are gone for good. |
| 328 std::set<FilePath> image_paths = extension_->GetBrowserImages(); | 370 std::set<FilePath> image_paths = extension_->GetBrowserImages(); |
| 329 if (image_paths.size() != images.size()) { | 371 if (image_paths.size() != images.size()) { |
| 330 ReportFailure("Decoded images don't match what's in the manifest."); | 372 // Decoded images don't match what's in the manifest. |
| 373 ReportFailure(l10n_util::GetStringFUTF8( |
| 374 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 375 ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST"))); |
| 331 return false; | 376 return false; |
| 332 } | 377 } |
| 333 | 378 |
| 334 for (std::set<FilePath>::iterator it = image_paths.begin(); | 379 for (std::set<FilePath>::iterator it = image_paths.begin(); |
| 335 it != image_paths.end(); ++it) { | 380 it != image_paths.end(); ++it) { |
| 336 FilePath path = *it; | 381 FilePath path = *it; |
| 337 if (path.IsAbsolute() || path.ReferencesParent()) { | 382 if (path.IsAbsolute() || path.ReferencesParent()) { |
| 338 ReportFailure("Invalid path for browser image."); | 383 // Invalid path for browser image. |
| 384 ReportFailure(l10n_util::GetStringFUTF8( |
| 385 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 386 ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); |
| 339 return false; | 387 return false; |
| 340 } | 388 } |
| 341 if (!file_util::Delete(extension_root_.Append(path), false)) { | 389 if (!file_util::Delete(extension_root_.Append(path), false)) { |
| 342 ReportFailure("Error removing old image file."); | 390 // Error removing old image file. |
| 391 ReportFailure(l10n_util::GetStringFUTF8( |
| 392 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 393 ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE"))); |
| 343 return false; | 394 return false; |
| 344 } | 395 } |
| 345 } | 396 } |
| 346 | 397 |
| 347 // Write our parsed images back to disk as well. | 398 // Write our parsed images back to disk as well. |
| 348 for (size_t i = 0; i < images.size(); ++i) { | 399 for (size_t i = 0; i < images.size(); ++i) { |
| 349 const SkBitmap& image = images[i].a; | 400 const SkBitmap& image = images[i].a; |
| 350 FilePath path_suffix = images[i].b; | 401 FilePath path_suffix = images[i].b; |
| 351 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { | 402 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { |
| 352 ReportFailure("Invalid path for bitmap image."); | 403 // Invalid path for bitmap image. |
| 404 ReportFailure(l10n_util::GetStringFUTF8( |
| 405 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 406 ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"))); |
| 353 return false; | 407 return false; |
| 354 } | 408 } |
| 355 FilePath path = extension_root_.Append(path_suffix); | 409 FilePath path = extension_root_.Append(path_suffix); |
| 356 | 410 |
| 357 std::vector<unsigned char> image_data; | 411 std::vector<unsigned char> image_data; |
| 358 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even | 412 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even |
| 359 // though they may originally be .jpg, etc. Figure something out. | 413 // though they may originally be .jpg, etc. Figure something out. |
| 360 // http://code.google.com/p/chromium/issues/detail?id=12459 | 414 // http://code.google.com/p/chromium/issues/detail?id=12459 |
| 361 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { | 415 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { |
| 362 ReportFailure("Error re-encoding theme image."); | 416 // Error re-encoding theme image. |
| 417 ReportFailure(l10n_util::GetStringFUTF8( |
| 418 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 419 ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE"))); |
| 363 return false; | 420 return false; |
| 364 } | 421 } |
| 365 | 422 |
| 366 // Note: we're overwriting existing files that the utility process wrote, | 423 // Note: we're overwriting existing files that the utility process wrote, |
| 367 // so we can be sure the directory exists. | 424 // so we can be sure the directory exists. |
| 368 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); | 425 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); |
| 369 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { | 426 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { |
| 370 ReportFailure("Error saving theme image."); | 427 // Error saving theme image. |
| 428 ReportFailure(l10n_util::GetStringFUTF8( |
| 429 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 430 ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE"))); |
| 371 return false; | 431 return false; |
| 372 } | 432 } |
| 373 } | 433 } |
| 374 | 434 |
| 375 return true; | 435 return true; |
| 376 } | 436 } |
| 377 | 437 |
| 378 bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { | 438 bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { |
| 379 DictionaryValue catalogs; | 439 DictionaryValue catalogs; |
| 380 if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(), | 440 if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(), |
| 381 &catalogs)) { | 441 &catalogs)) { |
| 382 ReportFailure("Could not read catalog data from disk."); | 442 // Could not read catalog data from disk. |
| 443 ReportFailure(l10n_util::GetStringFUTF8( |
| 444 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 445 ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK"))); |
| 383 return false; | 446 return false; |
| 384 } | 447 } |
| 385 | 448 |
| 386 // Write our parsed catalogs back to disk. | 449 // Write our parsed catalogs back to disk. |
| 387 for (DictionaryValue::key_iterator key_it = catalogs.begin_keys(); | 450 for (DictionaryValue::key_iterator key_it = catalogs.begin_keys(); |
| 388 key_it != catalogs.end_keys(); ++key_it) { | 451 key_it != catalogs.end_keys(); ++key_it) { |
| 389 DictionaryValue* catalog; | 452 DictionaryValue* catalog; |
| 390 if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) { | 453 if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) { |
| 391 ReportFailure("Invalid catalog data."); | 454 // Invalid catalog data. |
| 455 ReportFailure(l10n_util::GetStringFUTF8( |
| 456 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 457 ASCIIToUTF16("INVALID_CATALOG_DATA"))); |
| 392 return false; | 458 return false; |
| 393 } | 459 } |
| 394 | 460 |
| 395 // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())| | 461 // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())| |
| 396 // hack and remove the corresponding #include. | 462 // hack and remove the corresponding #include. |
| 397 FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it)); | 463 FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it)); |
| 398 relative_path = relative_path.Append(Extension::kMessagesFilename); | 464 relative_path = relative_path.Append(Extension::kMessagesFilename); |
| 399 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { | 465 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { |
| 400 ReportFailure("Invalid path for catalog."); | 466 // Invalid path for catalog. |
| 467 ReportFailure(l10n_util::GetStringFUTF8( |
| 468 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 469 ASCIIToUTF16("INVALID_PATH_FOR_CATALOG"))); |
| 401 return false; | 470 return false; |
| 402 } | 471 } |
| 403 FilePath path = extension_root_.Append(relative_path); | 472 FilePath path = extension_root_.Append(relative_path); |
| 404 | 473 |
| 405 std::string catalog_json; | 474 std::string catalog_json; |
| 406 JSONStringValueSerializer serializer(&catalog_json); | 475 JSONStringValueSerializer serializer(&catalog_json); |
| 407 serializer.set_pretty_print(true); | 476 serializer.set_pretty_print(true); |
| 408 if (!serializer.Serialize(*catalog)) { | 477 if (!serializer.Serialize(*catalog)) { |
| 409 ReportFailure("Error serializing catalog."); | 478 // Error serializing catalog. |
| 479 ReportFailure(l10n_util::GetStringFUTF8( |
| 480 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 481 ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"))); |
| 410 return false; | 482 return false; |
| 411 } | 483 } |
| 412 | 484 |
| 413 // Note: we're overwriting existing files that the utility process read, | 485 // Note: we're overwriting existing files that the utility process read, |
| 414 // so we can be sure the directory exists. | 486 // so we can be sure the directory exists. |
| 415 if (!file_util::WriteFile(path, | 487 if (!file_util::WriteFile(path, |
| 416 catalog_json.c_str(), | 488 catalog_json.c_str(), |
| 417 catalog_json.size())) { | 489 catalog_json.size())) { |
| 418 ReportFailure("Error saving catalog."); | 490 // Error saving catalog. |
| 491 ReportFailure(l10n_util::GetStringFUTF8( |
| 492 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 493 ASCIIToUTF16("ERROR_SAVING_CATALOG"))); |
| 419 return false; | 494 return false; |
| 420 } | 495 } |
| 421 } | 496 } |
| 422 | 497 |
| 423 return true; | 498 return true; |
| 424 } | 499 } |
| OLD | NEW |