| 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/extensions_service.h" | 19 #include "chrome/browser/extensions/extensions_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" |
| 28 #include "third_party/skia/include/core/SkBitmap.h" | 29 #include "third_party/skia/include/core/SkBitmap.h" |
| 30 #include "grit/generated_resources.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 |
| 178 ReportFailure(l10n_util::GetStringFUTF8( |
| 179 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, |
| 180 ASCIIToUTF16(error))); |
| 182 } | 181 } |
| 183 | 182 |
| 184 void SandboxedExtensionUnpacker::OnProcessCrashed() { | 183 void SandboxedExtensionUnpacker::OnProcessCrashed() { |
| 185 // Don't report crashes if they happen after we got a response. | 184 // Don't report crashes if they happen after we got a response. |
| 186 if (got_response_) | 185 if (got_response_) |
| 187 return; | 186 return; |
| 188 | 187 |
| 189 ReportFailure("Utility process crashed while trying to install."); | 188 // Utility process crashed while trying to install. |
| 189 ReportFailure(l10n_util::GetStringFUTF8( |
| 190 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 191 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL"))); |
| 190 } | 192 } |
| 191 | 193 |
| 192 bool SandboxedExtensionUnpacker::ValidateSignature() { | 194 bool SandboxedExtensionUnpacker::ValidateSignature() { |
| 193 ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb")); | 195 ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb")); |
| 194 if (!file.get()) { | 196 if (!file.get()) { |
| 195 ReportFailure("Could not open crx file for reading"); | 197 // Could not open crx file for reading |
| 198 ReportFailure(l10n_util::GetStringFUTF8( |
| 199 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 200 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); |
| 196 return false; | 201 return false; |
| 197 } | 202 } |
| 198 | 203 |
| 199 // Read and verify the header. | 204 // Read and verify the header. |
| 200 ExtensionHeader header; | 205 ExtensionHeader header; |
| 201 size_t len; | 206 size_t len; |
| 202 | 207 |
| 203 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it | 208 // 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 | 209 // 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 | 210 // code in the code base. So for now, this assumes that we're running |
| 206 // on a little endian machine with 4 byte alignment. | 211 // on a little endian machine with 4 byte alignment. |
| 207 len = fread(&header, 1, sizeof(ExtensionHeader), | 212 len = fread(&header, 1, sizeof(ExtensionHeader), |
| 208 file.get()); | 213 file.get()); |
| 209 if (len < sizeof(ExtensionHeader)) { | 214 if (len < sizeof(ExtensionHeader)) { |
| 210 ReportFailure("Invalid crx header"); | 215 // Invalid crx header |
| 216 ReportFailure(l10n_util::GetStringFUTF8( |
| 217 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 218 ASCIIToUTF16("CRX_HEADER_INVALID"))); |
| 211 return false; | 219 return false; |
| 212 } | 220 } |
| 213 if (strncmp(kExtensionHeaderMagic, header.magic, | 221 if (strncmp(kExtensionHeaderMagic, header.magic, |
| 214 sizeof(header.magic))) { | 222 sizeof(header.magic))) { |
| 215 ReportFailure("Bad magic number"); | 223 // Bad magic number |
| 224 ReportFailure(l10n_util::GetStringFUTF8( |
| 225 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 226 ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID"))); |
| 216 return false; | 227 return false; |
| 217 } | 228 } |
| 218 if (header.version != kCurrentVersion) { | 229 if (header.version != kCurrentVersion) { |
| 219 ReportFailure("Bad version number"); | 230 // Bad version numer |
| 231 ReportFailure(l10n_util::GetStringFUTF8( |
| 232 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 233 ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID"))); |
| 220 return false; | 234 return false; |
| 221 } | 235 } |
| 222 if (header.key_size > kMaxPublicKeySize || | 236 if (header.key_size > kMaxPublicKeySize || |
| 223 header.signature_size > kMaxSignatureSize) { | 237 header.signature_size > kMaxSignatureSize) { |
| 224 ReportFailure("Excessively large key or signature"); | 238 // Excessively large key or signature |
| 239 ReportFailure(l10n_util::GetStringFUTF8( |
| 240 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 241 ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE"))); |
| 225 return false; | 242 return false; |
| 226 } | 243 } |
| 227 if (header.key_size == 0) { | 244 if (header.key_size == 0) { |
| 228 ReportFailure("Key length is zero"); | 245 // Key length is zero |
| 246 ReportFailure(l10n_util::GetStringFUTF8( |
| 247 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 248 ASCIIToUTF16("CRX_ZERO_KEY_LENGTH"))); |
| 229 return false; | 249 return false; |
| 230 } | 250 } |
| 231 if (header.signature_size == 0) { | 251 if (header.signature_size == 0) { |
| 232 ReportFailure("Signature length is zero"); | 252 // Signature length is zero |
| 253 ReportFailure(l10n_util::GetStringFUTF8( |
| 254 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 255 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); |
| 233 return false; | 256 return false; |
| 234 } | 257 } |
| 235 | 258 |
| 236 std::vector<uint8> key; | 259 std::vector<uint8> key; |
| 237 key.resize(header.key_size); | 260 key.resize(header.key_size); |
| 238 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); | 261 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); |
| 239 if (len < header.key_size) { | 262 if (len < header.key_size) { |
| 240 ReportFailure("Invalid public key"); | 263 // Invalid public key |
| 264 ReportFailure(l10n_util::GetStringFUTF8( |
| 265 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 266 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); |
| 241 return false; | 267 return false; |
| 242 } | 268 } |
| 243 | 269 |
| 244 std::vector<uint8> signature; | 270 std::vector<uint8> signature; |
| 245 signature.resize(header.signature_size); | 271 signature.resize(header.signature_size); |
| 246 len = fread(&signature.front(), sizeof(uint8), header.signature_size, | 272 len = fread(&signature.front(), sizeof(uint8), header.signature_size, |
| 247 file.get()); | 273 file.get()); |
| 248 if (len < header.signature_size) { | 274 if (len < header.signature_size) { |
| 249 ReportFailure("Invalid signature"); | 275 // Invalid signature |
| 276 ReportFailure(l10n_util::GetStringFUTF8( |
| 277 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 278 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); |
| 250 return false; | 279 return false; |
| 251 } | 280 } |
| 252 | 281 |
| 253 base::SignatureVerifier verifier; | 282 base::SignatureVerifier verifier; |
| 254 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm, | 283 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm, |
| 255 sizeof(extension_misc::kSignatureAlgorithm), | 284 sizeof(extension_misc::kSignatureAlgorithm), |
| 256 &signature.front(), | 285 &signature.front(), |
| 257 signature.size(), | 286 signature.size(), |
| 258 &key.front(), | 287 &key.front(), |
| 259 key.size())) { | 288 key.size())) { |
| 260 ReportFailure("Signature verification initialization failed. " | 289 // Signature verification initialization failed. This is most likely |
| 261 "This is most likely caused by a public key in " | 290 // caused by a public key in the wrong format (should encode algorithm). |
| 262 "the wrong format (should encode algorithm)."); | 291 ReportFailure(l10n_util::GetStringFUTF8( |
| 292 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 293 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); |
| 263 return false; | 294 return false; |
| 264 } | 295 } |
| 265 | 296 |
| 266 unsigned char buf[1 << 12]; | 297 unsigned char buf[1 << 12]; |
| 267 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) | 298 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) |
| 268 verifier.VerifyUpdate(buf, len); | 299 verifier.VerifyUpdate(buf, len); |
| 269 | 300 |
| 270 if (!verifier.VerifyFinal()) { | 301 if (!verifier.VerifyFinal()) { |
| 271 ReportFailure("Signature verification failed"); | 302 // Signature verification failed |
| 303 ReportFailure(l10n_util::GetStringFUTF8( |
| 304 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 305 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); |
| 272 return false; | 306 return false; |
| 273 } | 307 } |
| 274 | 308 |
| 275 base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), | 309 base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), |
| 276 key.size()), &public_key_); | 310 key.size()), &public_key_); |
| 277 return true; | 311 return true; |
| 278 } | 312 } |
| 279 | 313 |
| 280 void SandboxedExtensionUnpacker::ReportFailure(const std::string& error) { | 314 void SandboxedExtensionUnpacker::ReportFailure(const std::string& error) { |
| 281 client_->OnUnpackFailure(error); | 315 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 | 327 // 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. | 328 // exploitable bug that could be used to compromise the browser. |
| 295 scoped_ptr<DictionaryValue> final_manifest( | 329 scoped_ptr<DictionaryValue> final_manifest( |
| 296 static_cast<DictionaryValue*>(manifest.DeepCopy())); | 330 static_cast<DictionaryValue*>(manifest.DeepCopy())); |
| 297 final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); | 331 final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); |
| 298 | 332 |
| 299 std::string manifest_json; | 333 std::string manifest_json; |
| 300 JSONStringValueSerializer serializer(&manifest_json); | 334 JSONStringValueSerializer serializer(&manifest_json); |
| 301 serializer.set_pretty_print(true); | 335 serializer.set_pretty_print(true); |
| 302 if (!serializer.Serialize(*final_manifest)) { | 336 if (!serializer.Serialize(*final_manifest)) { |
| 303 ReportFailure("Error serializing manifest.json."); | 337 // Error serializing manifest.json. |
| 338 ReportFailure(l10n_util::GetStringFUTF8( |
| 339 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 340 ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); |
| 304 return NULL; | 341 return NULL; |
| 305 } | 342 } |
| 306 | 343 |
| 307 FilePath manifest_path = | 344 FilePath manifest_path = |
| 308 extension_root_.Append(Extension::kManifestFilename); | 345 extension_root_.Append(Extension::kManifestFilename); |
| 309 if (!file_util::WriteFile(manifest_path, | 346 if (!file_util::WriteFile(manifest_path, |
| 310 manifest_json.data(), manifest_json.size())) { | 347 manifest_json.data(), manifest_json.size())) { |
| 311 ReportFailure("Error saving manifest.json."); | 348 // Error saving manifest.json. |
| 349 ReportFailure(l10n_util::GetStringFUTF8( |
| 350 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 351 ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); |
| 312 return NULL; | 352 return NULL; |
| 313 } | 353 } |
| 314 | 354 |
| 315 return final_manifest.release(); | 355 return final_manifest.release(); |
| 316 } | 356 } |
| 317 | 357 |
| 318 bool SandboxedExtensionUnpacker::RewriteImageFiles() { | 358 bool SandboxedExtensionUnpacker::RewriteImageFiles() { |
| 319 ExtensionUnpacker::DecodedImages images; | 359 ExtensionUnpacker::DecodedImages images; |
| 320 if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { | 360 if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { |
| 321 ReportFailure("Couldn't read image data from disk."); | 361 // Couldn't read image data from disk. |
| 362 ReportFailure(l10n_util::GetStringFUTF8( |
| 363 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 364 ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK"))); |
| 322 return false; | 365 return false; |
| 323 } | 366 } |
| 324 | 367 |
| 325 // Delete any images that may be used by the browser. We're going to write | 368 // 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 | 369 // out our own versions of the parsed images, and we want to make sure the |
| 327 // originals are gone for good. | 370 // originals are gone for good. |
| 328 std::set<FilePath> image_paths = extension_->GetBrowserImages(); | 371 std::set<FilePath> image_paths = extension_->GetBrowserImages(); |
| 329 if (image_paths.size() != images.size()) { | 372 if (image_paths.size() != images.size()) { |
| 330 ReportFailure("Decoded images don't match what's in the manifest."); | 373 // Decoded images don't match what's in the manifest. |
| 374 ReportFailure(l10n_util::GetStringFUTF8( |
| 375 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 376 ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST"))); |
| 331 return false; | 377 return false; |
| 332 } | 378 } |
| 333 | 379 |
| 334 for (std::set<FilePath>::iterator it = image_paths.begin(); | 380 for (std::set<FilePath>::iterator it = image_paths.begin(); |
| 335 it != image_paths.end(); ++it) { | 381 it != image_paths.end(); ++it) { |
| 336 FilePath path = *it; | 382 FilePath path = *it; |
| 337 if (path.IsAbsolute() || path.ReferencesParent()) { | 383 if (path.IsAbsolute() || path.ReferencesParent()) { |
| 338 ReportFailure("Invalid path for browser image."); | 384 // Invalid path for browser image. |
| 385 ReportFailure(l10n_util::GetStringFUTF8( |
| 386 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 387 ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); |
| 339 return false; | 388 return false; |
| 340 } | 389 } |
| 341 if (!file_util::Delete(extension_root_.Append(path), false)) { | 390 if (!file_util::Delete(extension_root_.Append(path), false)) { |
| 342 ReportFailure("Error removing old image file."); | 391 // Error removing old image file. |
| 392 ReportFailure(l10n_util::GetStringFUTF8( |
| 393 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 394 ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE"))); |
| 343 return false; | 395 return false; |
| 344 } | 396 } |
| 345 } | 397 } |
| 346 | 398 |
| 347 // Write our parsed images back to disk as well. | 399 // Write our parsed images back to disk as well. |
| 348 for (size_t i = 0; i < images.size(); ++i) { | 400 for (size_t i = 0; i < images.size(); ++i) { |
| 349 const SkBitmap& image = images[i].a; | 401 const SkBitmap& image = images[i].a; |
| 350 FilePath path_suffix = images[i].b; | 402 FilePath path_suffix = images[i].b; |
| 351 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { | 403 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { |
| 352 ReportFailure("Invalid path for bitmap image."); | 404 // Invalid path for bitmap image. |
| 405 ReportFailure(l10n_util::GetStringFUTF8( |
| 406 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 407 ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"))); |
| 353 return false; | 408 return false; |
| 354 } | 409 } |
| 355 FilePath path = extension_root_.Append(path_suffix); | 410 FilePath path = extension_root_.Append(path_suffix); |
| 356 | 411 |
| 357 std::vector<unsigned char> image_data; | 412 std::vector<unsigned char> image_data; |
| 358 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even | 413 // 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. | 414 // though they may originally be .jpg, etc. Figure something out. |
| 360 // http://code.google.com/p/chromium/issues/detail?id=12459 | 415 // http://code.google.com/p/chromium/issues/detail?id=12459 |
| 361 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { | 416 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { |
| 362 ReportFailure("Error re-encoding theme image."); | 417 // Error re-encoding theme image. |
| 418 ReportFailure(l10n_util::GetStringFUTF8( |
| 419 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 420 ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE"))); |
| 363 return false; | 421 return false; |
| 364 } | 422 } |
| 365 | 423 |
| 366 // Note: we're overwriting existing files that the utility process wrote, | 424 // Note: we're overwriting existing files that the utility process wrote, |
| 367 // so we can be sure the directory exists. | 425 // so we can be sure the directory exists. |
| 368 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); | 426 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); |
| 369 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { | 427 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { |
| 370 ReportFailure("Error saving theme image."); | 428 // Error saving theme image. |
| 429 ReportFailure(l10n_util::GetStringFUTF8( |
| 430 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 431 ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE"))); |
| 371 return false; | 432 return false; |
| 372 } | 433 } |
| 373 } | 434 } |
| 374 | 435 |
| 375 return true; | 436 return true; |
| 376 } | 437 } |
| 377 | 438 |
| 378 bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { | 439 bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { |
| 379 DictionaryValue catalogs; | 440 DictionaryValue catalogs; |
| 380 if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(), | 441 if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(), |
| 381 &catalogs)) { | 442 &catalogs)) { |
| 382 ReportFailure("Could not read catalog data from disk."); | 443 // Could not read catalog data from disk. |
| 444 ReportFailure(l10n_util::GetStringFUTF8( |
| 445 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 446 ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK"))); |
| 383 return false; | 447 return false; |
| 384 } | 448 } |
| 385 | 449 |
| 386 // Write our parsed catalogs back to disk. | 450 // Write our parsed catalogs back to disk. |
| 387 for (DictionaryValue::key_iterator key_it = catalogs.begin_keys(); | 451 for (DictionaryValue::key_iterator key_it = catalogs.begin_keys(); |
| 388 key_it != catalogs.end_keys(); ++key_it) { | 452 key_it != catalogs.end_keys(); ++key_it) { |
| 389 DictionaryValue* catalog; | 453 DictionaryValue* catalog; |
| 390 if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) { | 454 if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) { |
| 391 ReportFailure("Invalid catalog data."); | 455 // Invalid catalog data. |
| 456 ReportFailure(l10n_util::GetStringFUTF8( |
| 457 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 458 ASCIIToUTF16("INVALID_CATALOG_DATA"))); |
| 392 return false; | 459 return false; |
| 393 } | 460 } |
| 394 | 461 |
| 395 // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())| | 462 // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())| |
| 396 // hack and remove the corresponding #include. | 463 // hack and remove the corresponding #include. |
| 397 FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it)); | 464 FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it)); |
| 398 relative_path = relative_path.Append(Extension::kMessagesFilename); | 465 relative_path = relative_path.Append(Extension::kMessagesFilename); |
| 399 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { | 466 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { |
| 400 ReportFailure("Invalid path for catalog."); | 467 // Invalid path for catalog. |
| 468 ReportFailure(l10n_util::GetStringFUTF8( |
| 469 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 470 ASCIIToUTF16("INVALID_PATH_FOR_CATALOG"))); |
| 401 return false; | 471 return false; |
| 402 } | 472 } |
| 403 FilePath path = extension_root_.Append(relative_path); | 473 FilePath path = extension_root_.Append(relative_path); |
| 404 | 474 |
| 405 std::string catalog_json; | 475 std::string catalog_json; |
| 406 JSONStringValueSerializer serializer(&catalog_json); | 476 JSONStringValueSerializer serializer(&catalog_json); |
| 407 serializer.set_pretty_print(true); | 477 serializer.set_pretty_print(true); |
| 408 if (!serializer.Serialize(*catalog)) { | 478 if (!serializer.Serialize(*catalog)) { |
| 409 ReportFailure("Error serializing catalog."); | 479 // Error serializing catalog. |
| 480 ReportFailure(l10n_util::GetStringFUTF8( |
| 481 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 482 ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"))); |
| 410 return false; | 483 return false; |
| 411 } | 484 } |
| 412 | 485 |
| 413 // Note: we're overwriting existing files that the utility process read, | 486 // Note: we're overwriting existing files that the utility process read, |
| 414 // so we can be sure the directory exists. | 487 // so we can be sure the directory exists. |
| 415 if (!file_util::WriteFile(path, | 488 if (!file_util::WriteFile(path, |
| 416 catalog_json.c_str(), | 489 catalog_json.c_str(), |
| 417 catalog_json.size())) { | 490 catalog_json.size())) { |
| 418 ReportFailure("Error saving catalog."); | 491 // Error saving catalog. |
| 492 ReportFailure(l10n_util::GetStringFUTF8( |
| 493 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 494 ASCIIToUTF16("ERROR_SAVING_CATALOG"))); |
| 419 return false; | 495 return false; |
| 420 } | 496 } |
| 421 } | 497 } |
| 422 | 498 |
| 423 return true; | 499 return true; |
| 424 } | 500 } |
| OLD | NEW |