| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 location_(location), creation_flags_(creation_flags) { | 122 location_(location), creation_flags_(creation_flags) { |
| 123 } | 123 } |
| 124 | 124 |
| 125 bool SandboxedExtensionUnpacker::CreateTempDirectory() { | 125 bool SandboxedExtensionUnpacker::CreateTempDirectory() { |
| 126 CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_identifier_)); | 126 CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_identifier_)); |
| 127 | 127 |
| 128 FilePath user_data_temp_dir = extension_file_util::GetUserDataTempDir(); | 128 FilePath user_data_temp_dir = extension_file_util::GetUserDataTempDir(); |
| 129 if (user_data_temp_dir.empty()) { | 129 if (user_data_temp_dir.empty()) { |
| 130 ReportFailure( | 130 ReportFailure( |
| 131 COULD_NOT_GET_TEMP_DIRECTORY, | 131 COULD_NOT_GET_TEMP_DIRECTORY, |
| 132 l10n_util::GetStringFUTF8( | 132 l10n_util::GetStringFUTF16( |
| 133 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 133 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 134 ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"))); | 134 ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"))); |
| 135 return false; | 135 return false; |
| 136 } | 136 } |
| 137 | 137 |
| 138 if (!temp_dir_.CreateUniqueTempDirUnderPath(user_data_temp_dir)) { | 138 if (!temp_dir_.CreateUniqueTempDirUnderPath(user_data_temp_dir)) { |
| 139 ReportFailure( | 139 ReportFailure( |
| 140 COULD_NOT_CREATE_TEMP_DIRECTORY, | 140 COULD_NOT_CREATE_TEMP_DIRECTORY, |
| 141 l10n_util::GetStringFUTF8( | 141 l10n_util::GetStringFUTF16( |
| 142 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 142 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 143 ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); | 143 ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); |
| 144 return false; | 144 return false; |
| 145 } | 145 } |
| 146 | 146 |
| 147 return true; | 147 return true; |
| 148 } | 148 } |
| 149 | 149 |
| 150 void SandboxedExtensionUnpacker::Start() { | 150 void SandboxedExtensionUnpacker::Start() { |
| 151 // We assume that we are started on the thread that the client wants us to do | 151 // We assume that we are started on the thread that the client wants us to do |
| (...skipping 19 matching lines...) Expand all Loading... |
| 171 | 171 |
| 172 // Copy the crx file into our working directory. | 172 // Copy the crx file into our working directory. |
| 173 FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName()); | 173 FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName()); |
| 174 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackTempCrxPathLength", | 174 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackTempCrxPathLength", |
| 175 temp_crx_path); | 175 temp_crx_path); |
| 176 | 176 |
| 177 if (!file_util::CopyFile(crx_path_, temp_crx_path)) { | 177 if (!file_util::CopyFile(crx_path_, temp_crx_path)) { |
| 178 // Failed to copy extension file to temporary directory. | 178 // Failed to copy extension file to temporary directory. |
| 179 ReportFailure( | 179 ReportFailure( |
| 180 FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY, | 180 FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY, |
| 181 l10n_util::GetStringFUTF8( | 181 l10n_util::GetStringFUTF16( |
| 182 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 182 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 183 ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY"))); | 183 ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY"))); |
| 184 return; | 184 return; |
| 185 } | 185 } |
| 186 | 186 |
| 187 // If we are supposed to use a subprocess, kick off the subprocess. | 187 // If we are supposed to use a subprocess, kick off the subprocess. |
| 188 // | 188 // |
| 189 // TODO(asargent) we shouldn't need to do this branch here - instead | 189 // TODO(asargent) we shouldn't need to do this branch here - instead |
| 190 // UtilityProcessHost should handle it for us. (http://crbug.com/19192) | 190 // UtilityProcessHost should handle it for us. (http://crbug.com/19192) |
| 191 bool use_utility_process = rdh_ && | 191 bool use_utility_process = rdh_ && |
| 192 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); | 192 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); |
| 193 if (use_utility_process) { | 193 if (use_utility_process) { |
| 194 // The utility process will have access to the directory passed to | 194 // The utility process will have access to the directory passed to |
| 195 // SandboxedExtensionUnpacker. That directory should not contain a | 195 // SandboxedExtensionUnpacker. That directory should not contain a |
| 196 // symlink or NTFS reparse point. When the path is used, following | 196 // symlink or NTFS reparse point. When the path is used, following |
| 197 // the link/reparse point will cause file system access outside the | 197 // the link/reparse point will cause file system access outside the |
| 198 // sandbox path, and the sandbox will deny the operation. | 198 // sandbox path, and the sandbox will deny the operation. |
| 199 FilePath link_free_crx_path; | 199 FilePath link_free_crx_path; |
| 200 if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { | 200 if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { |
| 201 LOG(ERROR) << "Could not get the normalized path of " | 201 LOG(ERROR) << "Could not get the normalized path of " |
| 202 << temp_crx_path.value(); | 202 << temp_crx_path.value(); |
| 203 ReportFailure( | 203 ReportFailure( |
| 204 COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, | 204 COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, |
| 205 l10n_util::GetStringUTF8(IDS_EXTENSION_UNPACK_FAILED)); | 205 l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED)); |
| 206 return; | 206 return; |
| 207 } | 207 } |
| 208 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength", | 208 PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength", |
| 209 link_free_crx_path); | 209 link_free_crx_path); |
| 210 | 210 |
| 211 BrowserThread::PostTask( | 211 BrowserThread::PostTask( |
| 212 BrowserThread::IO, FROM_HERE, | 212 BrowserThread::IO, FROM_HERE, |
| 213 base::Bind( | 213 base::Bind( |
| 214 &SandboxedExtensionUnpacker::StartProcessOnIOThread, | 214 &SandboxedExtensionUnpacker::StartProcessOnIOThread, |
| 215 this, | 215 this, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 246 } | 246 } |
| 247 | 247 |
| 248 void SandboxedExtensionUnpacker::OnProcessCrashed(int exit_code) { | 248 void SandboxedExtensionUnpacker::OnProcessCrashed(int exit_code) { |
| 249 // Don't report crashes if they happen after we got a response. | 249 // Don't report crashes if they happen after we got a response. |
| 250 if (got_response_) | 250 if (got_response_) |
| 251 return; | 251 return; |
| 252 | 252 |
| 253 // Utility process crashed while trying to install. | 253 // Utility process crashed while trying to install. |
| 254 ReportFailure( | 254 ReportFailure( |
| 255 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, | 255 UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, |
| 256 l10n_util::GetStringFUTF8( | 256 l10n_util::GetStringFUTF16( |
| 257 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 257 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 258 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL"))); | 258 ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL"))); |
| 259 } | 259 } |
| 260 | 260 |
| 261 void SandboxedExtensionUnpacker::StartProcessOnIOThread( | 261 void SandboxedExtensionUnpacker::StartProcessOnIOThread( |
| 262 const FilePath& temp_crx_path) { | 262 const FilePath& temp_crx_path) { |
| 263 UtilityProcessHost* host = new UtilityProcessHost(this, thread_identifier_); | 263 UtilityProcessHost* host = new UtilityProcessHost(this, thread_identifier_); |
| 264 // Grant the subprocess access to the entire subdir the extension file is | 264 // Grant the subprocess access to the entire subdir the extension file is |
| 265 // in, so that it can unpack to that dir. | 265 // in, so that it can unpack to that dir. |
| 266 host->set_exposed_dir(temp_crx_path.DirName()); | 266 host->set_exposed_dir(temp_crx_path.DirName()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 279 scoped_ptr<DictionaryValue> final_manifest(RewriteManifestFile(manifest)); | 279 scoped_ptr<DictionaryValue> final_manifest(RewriteManifestFile(manifest)); |
| 280 if (!final_manifest.get()) | 280 if (!final_manifest.get()) |
| 281 return; | 281 return; |
| 282 | 282 |
| 283 // Create an extension object that refers to the temporary location the | 283 // Create an extension object that refers to the temporary location the |
| 284 // extension was unpacked to. We use this until the extension is finally | 284 // extension was unpacked to. We use this until the extension is finally |
| 285 // installed. For example, the install UI shows images from inside the | 285 // installed. For example, the install UI shows images from inside the |
| 286 // extension. | 286 // extension. |
| 287 | 287 |
| 288 // Localize manifest now, so confirm UI gets correct extension name. | 288 // Localize manifest now, so confirm UI gets correct extension name. |
| 289 std::string error; | 289 |
| 290 // TODO(si): Continue removing std::string errors and replacing with string16 |
| 291 std::string std_error; |
| 290 if (!extension_l10n_util::LocalizeExtension(extension_root_, | 292 if (!extension_l10n_util::LocalizeExtension(extension_root_, |
| 291 final_manifest.get(), | 293 final_manifest.get(), |
| 292 &error)) { | 294 &std_error)) { |
| 293 ReportFailure( | 295 ReportFailure( |
| 294 COULD_NOT_LOCALIZE_EXTENSION, | 296 COULD_NOT_LOCALIZE_EXTENSION, |
| 295 l10n_util::GetStringFUTF8( | 297 l10n_util::GetStringFUTF16( |
| 296 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, | 298 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, |
| 297 ASCIIToUTF16(error))); | 299 UTF8ToUTF16(std_error))); |
| 298 return; | 300 return; |
| 299 } | 301 } |
| 300 | 302 |
| 301 extension_ = Extension::Create( | 303 extension_ = Extension::Create( |
| 302 extension_root_, | 304 extension_root_, |
| 303 location_, | 305 location_, |
| 304 *final_manifest, | 306 *final_manifest, |
| 305 Extension::REQUIRE_KEY | creation_flags_, | 307 Extension::REQUIRE_KEY | creation_flags_, |
| 306 &error); | 308 &std_error); |
| 309 |
| 307 | 310 |
| 308 if (!extension_.get()) { | 311 if (!extension_.get()) { |
| 309 ReportFailure( | 312 ReportFailure( |
| 310 INVALID_MANIFEST, | 313 INVALID_MANIFEST, |
| 311 std::string("Manifest is invalid: ") + error); | 314 ASCIIToUTF16("Manifest is invalid: " + std_error)); |
| 312 return; | 315 return; |
| 313 } | 316 } |
| 314 | 317 |
| 315 if (!RewriteImageFiles()) | 318 if (!RewriteImageFiles()) |
| 316 return; | 319 return; |
| 317 | 320 |
| 318 if (!RewriteCatalogFiles()) | 321 if (!RewriteCatalogFiles()) |
| 319 return; | 322 return; |
| 320 | 323 |
| 321 ReportSuccess(manifest); | 324 ReportSuccess(manifest); |
| 322 } | 325 } |
| 323 | 326 |
| 324 void SandboxedExtensionUnpacker::OnUnpackExtensionFailed( | 327 void SandboxedExtensionUnpacker::OnUnpackExtensionFailed( |
| 325 const std::string& error) { | 328 const string16& error) { |
| 326 CHECK(BrowserThread::CurrentlyOn(thread_identifier_)); | 329 CHECK(BrowserThread::CurrentlyOn(thread_identifier_)); |
| 327 got_response_ = true; | 330 got_response_ = true; |
| 328 ReportFailure( | 331 ReportFailure( |
| 329 UNPACKER_CLIENT_FAILED, | 332 UNPACKER_CLIENT_FAILED, |
| 330 l10n_util::GetStringFUTF8( | 333 l10n_util::GetStringFUTF16( |
| 331 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, | 334 IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, |
| 332 ASCIIToUTF16(error))); | 335 error)); |
| 333 } | 336 } |
| 334 | 337 |
| 335 bool SandboxedExtensionUnpacker::ValidateSignature() { | 338 bool SandboxedExtensionUnpacker::ValidateSignature() { |
| 336 ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb")); | 339 ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb")); |
| 337 | 340 |
| 338 if (!file.get()) { | 341 if (!file.get()) { |
| 339 // Could not open crx file for reading. | 342 // Could not open crx file for reading. |
| 340 #if defined (OS_WIN) | 343 #if defined (OS_WIN) |
| 341 // On windows, get the error code. | 344 // On windows, get the error code. |
| 342 uint32 error_code = ::GetLastError(); | 345 uint32 error_code = ::GetLastError(); |
| 343 // TODO(skerner): Use this histogram to understand why so many | 346 // TODO(skerner): Use this histogram to understand why so many |
| 344 // windows users hit this error. crbug.com/69693 | 347 // windows users hit this error. crbug.com/69693 |
| 345 | 348 |
| 346 // Windows errors are unit32s, but all of likely errors are in | 349 // Windows errors are unit32s, but all of likely errors are in |
| 347 // [1, 1000]. See winerror.h for the meaning of specific values. | 350 // [1, 1000]. See winerror.h for the meaning of specific values. |
| 348 // Clip errors outside the expected range to a single extra value. | 351 // Clip errors outside the expected range to a single extra value. |
| 349 // If there are errors in that extra bucket, we will know to expand | 352 // If there are errors in that extra bucket, we will know to expand |
| 350 // the range. | 353 // the range. |
| 351 const uint32 kMaxErrorToSend = 1001; | 354 const uint32 kMaxErrorToSend = 1001; |
| 352 error_code = std::min(error_code, kMaxErrorToSend); | 355 error_code = std::min(error_code, kMaxErrorToSend); |
| 353 UMA_HISTOGRAM_ENUMERATION("Extensions.ErrorCodeFromCrxOpen", | 356 UMA_HISTOGRAM_ENUMERATION("Extensions.ErrorCodeFromCrxOpen", |
| 354 error_code, kMaxErrorToSend); | 357 error_code, kMaxErrorToSend); |
| 355 #endif | 358 #endif |
| 356 | 359 |
| 357 ReportFailure( | 360 ReportFailure( |
| 358 CRX_FILE_NOT_READABLE, | 361 CRX_FILE_NOT_READABLE, |
| 359 l10n_util::GetStringFUTF8( | 362 l10n_util::GetStringFUTF16( |
| 360 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 363 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 361 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); | 364 ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); |
| 362 return false; | 365 return false; |
| 363 } | 366 } |
| 364 | 367 |
| 365 // Read and verify the header. | 368 // Read and verify the header. |
| 366 ExtensionHeader header; | 369 ExtensionHeader header; |
| 367 size_t len; | 370 size_t len; |
| 368 | 371 |
| 369 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it | 372 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it |
| 370 // appears that we don't have any endian/alignment aware serialization | 373 // appears that we don't have any endian/alignment aware serialization |
| 371 // code in the code base. So for now, this assumes that we're running | 374 // code in the code base. So for now, this assumes that we're running |
| 372 // on a little endian machine with 4 byte alignment. | 375 // on a little endian machine with 4 byte alignment. |
| 373 len = fread(&header, 1, sizeof(ExtensionHeader), | 376 len = fread(&header, 1, sizeof(ExtensionHeader), |
| 374 file.get()); | 377 file.get()); |
| 375 if (len < sizeof(ExtensionHeader)) { | 378 if (len < sizeof(ExtensionHeader)) { |
| 376 // Invalid crx header | 379 // Invalid crx header |
| 377 ReportFailure( | 380 ReportFailure( |
| 378 CRX_HEADER_INVALID, | 381 CRX_HEADER_INVALID, |
| 379 l10n_util::GetStringFUTF8( | 382 l10n_util::GetStringFUTF16( |
| 380 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 383 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 381 ASCIIToUTF16("CRX_HEADER_INVALID"))); | 384 ASCIIToUTF16("CRX_HEADER_INVALID"))); |
| 382 return false; | 385 return false; |
| 383 } | 386 } |
| 384 if (strncmp(kExtensionHeaderMagic, header.magic, | 387 if (strncmp(kExtensionHeaderMagic, header.magic, |
| 385 sizeof(header.magic))) { | 388 sizeof(header.magic))) { |
| 386 // Bad magic number | 389 // Bad magic number |
| 387 ReportFailure( | 390 ReportFailure( |
| 388 CRX_MAGIC_NUMBER_INVALID, | 391 CRX_MAGIC_NUMBER_INVALID, |
| 389 l10n_util::GetStringFUTF8( | 392 l10n_util::GetStringFUTF16( |
| 390 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 393 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 391 ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID"))); | 394 ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID"))); |
| 392 return false; | 395 return false; |
| 393 } | 396 } |
| 394 if (header.version != kCurrentVersion) { | 397 if (header.version != kCurrentVersion) { |
| 395 // Bad version numer | 398 // Bad version numer |
| 396 ReportFailure(CRX_VERSION_NUMBER_INVALID, | 399 ReportFailure(CRX_VERSION_NUMBER_INVALID, |
| 397 l10n_util::GetStringFUTF8( | 400 l10n_util::GetStringFUTF16( |
| 398 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 401 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 399 ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID"))); | 402 ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID"))); |
| 400 return false; | 403 return false; |
| 401 } | 404 } |
| 402 if (header.key_size > kMaxPublicKeySize || | 405 if (header.key_size > kMaxPublicKeySize || |
| 403 header.signature_size > kMaxSignatureSize) { | 406 header.signature_size > kMaxSignatureSize) { |
| 404 // Excessively large key or signature | 407 // Excessively large key or signature |
| 405 ReportFailure( | 408 ReportFailure( |
| 406 CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE, | 409 CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE, |
| 407 l10n_util::GetStringFUTF8( | 410 l10n_util::GetStringFUTF16( |
| 408 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 411 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 409 ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE"))); | 412 ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE"))); |
| 410 return false; | 413 return false; |
| 411 } | 414 } |
| 412 if (header.key_size == 0) { | 415 if (header.key_size == 0) { |
| 413 // Key length is zero | 416 // Key length is zero |
| 414 ReportFailure( | 417 ReportFailure( |
| 415 CRX_ZERO_KEY_LENGTH, | 418 CRX_ZERO_KEY_LENGTH, |
| 416 l10n_util::GetStringFUTF8( | 419 l10n_util::GetStringFUTF16( |
| 417 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 420 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 418 ASCIIToUTF16("CRX_ZERO_KEY_LENGTH"))); | 421 ASCIIToUTF16("CRX_ZERO_KEY_LENGTH"))); |
| 419 return false; | 422 return false; |
| 420 } | 423 } |
| 421 if (header.signature_size == 0) { | 424 if (header.signature_size == 0) { |
| 422 // Signature length is zero | 425 // Signature length is zero |
| 423 ReportFailure( | 426 ReportFailure( |
| 424 CRX_ZERO_SIGNATURE_LENGTH, | 427 CRX_ZERO_SIGNATURE_LENGTH, |
| 425 l10n_util::GetStringFUTF8( | 428 l10n_util::GetStringFUTF16( |
| 426 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 429 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 427 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); | 430 ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); |
| 428 return false; | 431 return false; |
| 429 } | 432 } |
| 430 | 433 |
| 431 std::vector<uint8> key; | 434 std::vector<uint8> key; |
| 432 key.resize(header.key_size); | 435 key.resize(header.key_size); |
| 433 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); | 436 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); |
| 434 if (len < header.key_size) { | 437 if (len < header.key_size) { |
| 435 // Invalid public key | 438 // Invalid public key |
| 436 ReportFailure( | 439 ReportFailure( |
| 437 CRX_PUBLIC_KEY_INVALID, | 440 CRX_PUBLIC_KEY_INVALID, |
| 438 l10n_util::GetStringFUTF8( | 441 l10n_util::GetStringFUTF16( |
| 439 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 442 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 440 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); | 443 ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); |
| 441 return false; | 444 return false; |
| 442 } | 445 } |
| 443 | 446 |
| 444 std::vector<uint8> signature; | 447 std::vector<uint8> signature; |
| 445 signature.resize(header.signature_size); | 448 signature.resize(header.signature_size); |
| 446 len = fread(&signature.front(), sizeof(uint8), header.signature_size, | 449 len = fread(&signature.front(), sizeof(uint8), header.signature_size, |
| 447 file.get()); | 450 file.get()); |
| 448 if (len < header.signature_size) { | 451 if (len < header.signature_size) { |
| 449 // Invalid signature | 452 // Invalid signature |
| 450 ReportFailure( | 453 ReportFailure( |
| 451 CRX_SIGNATURE_INVALID, | 454 CRX_SIGNATURE_INVALID, |
| 452 l10n_util::GetStringFUTF8( | 455 l10n_util::GetStringFUTF16( |
| 453 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 456 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 454 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); | 457 ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); |
| 455 return false; | 458 return false; |
| 456 } | 459 } |
| 457 | 460 |
| 458 crypto::SignatureVerifier verifier; | 461 crypto::SignatureVerifier verifier; |
| 459 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm, | 462 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm, |
| 460 sizeof(extension_misc::kSignatureAlgorithm), | 463 sizeof(extension_misc::kSignatureAlgorithm), |
| 461 &signature.front(), | 464 &signature.front(), |
| 462 signature.size(), | 465 signature.size(), |
| 463 &key.front(), | 466 &key.front(), |
| 464 key.size())) { | 467 key.size())) { |
| 465 // Signature verification initialization failed. This is most likely | 468 // Signature verification initialization failed. This is most likely |
| 466 // caused by a public key in the wrong format (should encode algorithm). | 469 // caused by a public key in the wrong format (should encode algorithm). |
| 467 ReportFailure( | 470 ReportFailure( |
| 468 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, | 471 CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, |
| 469 l10n_util::GetStringFUTF8( | 472 l10n_util::GetStringFUTF16( |
| 470 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 473 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 471 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); | 474 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); |
| 472 return false; | 475 return false; |
| 473 } | 476 } |
| 474 | 477 |
| 475 unsigned char buf[1 << 12]; | 478 unsigned char buf[1 << 12]; |
| 476 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) | 479 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) |
| 477 verifier.VerifyUpdate(buf, len); | 480 verifier.VerifyUpdate(buf, len); |
| 478 | 481 |
| 479 if (!verifier.VerifyFinal()) { | 482 if (!verifier.VerifyFinal()) { |
| 480 // Signature verification failed | 483 // Signature verification failed |
| 481 ReportFailure( | 484 ReportFailure( |
| 482 CRX_SIGNATURE_VERIFICATION_FAILED, | 485 CRX_SIGNATURE_VERIFICATION_FAILED, |
| 483 l10n_util::GetStringFUTF8( | 486 l10n_util::GetStringFUTF16( |
| 484 IDS_EXTENSION_PACKAGE_ERROR_CODE, | 487 IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| 485 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); | 488 ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); |
| 486 return false; | 489 return false; |
| 487 } | 490 } |
| 488 | 491 |
| 489 base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), | 492 base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()), |
| 490 key.size()), &public_key_); | 493 key.size()), &public_key_); |
| 491 return true; | 494 return true; |
| 492 } | 495 } |
| 493 | 496 |
| 494 void SandboxedExtensionUnpacker::ReportFailure(FailureReason reason, | 497 void SandboxedExtensionUnpacker::ReportFailure(FailureReason reason, |
| 495 const std::string& error) { | 498 const string16& error) { |
| 496 UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", | 499 UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", |
| 497 reason, NUM_FAILURE_REASONS); | 500 reason, NUM_FAILURE_REASONS); |
| 498 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime", | 501 UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime", |
| 499 base::TimeTicks::Now() - unpack_start_time_); | 502 base::TimeTicks::Now() - unpack_start_time_); |
| 500 | 503 |
| 501 client_->OnUnpackFailure(error); | 504 client_->OnUnpackFailure(error); |
| 502 } | 505 } |
| 503 | 506 |
| 504 void SandboxedExtensionUnpacker::ReportSuccess( | 507 void SandboxedExtensionUnpacker::ReportSuccess( |
| 505 const DictionaryValue& original_manifest) { | 508 const DictionaryValue& original_manifest) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 524 scoped_ptr<DictionaryValue> final_manifest(manifest.DeepCopy()); | 527 scoped_ptr<DictionaryValue> final_manifest(manifest.DeepCopy()); |
| 525 final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); | 528 final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_); |
| 526 | 529 |
| 527 std::string manifest_json; | 530 std::string manifest_json; |
| 528 JSONStringValueSerializer serializer(&manifest_json); | 531 JSONStringValueSerializer serializer(&manifest_json); |
| 529 serializer.set_pretty_print(true); | 532 serializer.set_pretty_print(true); |
| 530 if (!serializer.Serialize(*final_manifest)) { | 533 if (!serializer.Serialize(*final_manifest)) { |
| 531 // Error serializing manifest.json. | 534 // Error serializing manifest.json. |
| 532 ReportFailure( | 535 ReportFailure( |
| 533 ERROR_SERIALIZING_MANIFEST_JSON, | 536 ERROR_SERIALIZING_MANIFEST_JSON, |
| 534 l10n_util::GetStringFUTF8( | 537 l10n_util::GetStringFUTF16( |
| 535 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 538 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 536 ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); | 539 ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); |
| 537 return NULL; | 540 return NULL; |
| 538 } | 541 } |
| 539 | 542 |
| 540 FilePath manifest_path = | 543 FilePath manifest_path = |
| 541 extension_root_.Append(Extension::kManifestFilename); | 544 extension_root_.Append(Extension::kManifestFilename); |
| 542 if (!file_util::WriteFile(manifest_path, | 545 if (!file_util::WriteFile(manifest_path, |
| 543 manifest_json.data(), manifest_json.size())) { | 546 manifest_json.data(), manifest_json.size())) { |
| 544 // Error saving manifest.json. | 547 // Error saving manifest.json. |
| 545 ReportFailure( | 548 ReportFailure( |
| 546 ERROR_SAVING_MANIFEST_JSON, | 549 ERROR_SAVING_MANIFEST_JSON, |
| 547 l10n_util::GetStringFUTF8( | 550 l10n_util::GetStringFUTF16( |
| 548 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 551 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 549 ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); | 552 ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); |
| 550 return NULL; | 553 return NULL; |
| 551 } | 554 } |
| 552 | 555 |
| 553 return final_manifest.release(); | 556 return final_manifest.release(); |
| 554 } | 557 } |
| 555 | 558 |
| 556 bool SandboxedExtensionUnpacker::RewriteImageFiles() { | 559 bool SandboxedExtensionUnpacker::RewriteImageFiles() { |
| 557 ExtensionUnpacker::DecodedImages images; | 560 ExtensionUnpacker::DecodedImages images; |
| 558 if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { | 561 if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { |
| 559 // Couldn't read image data from disk. | 562 // Couldn't read image data from disk. |
| 560 ReportFailure( | 563 ReportFailure( |
| 561 COULD_NOT_READ_IMAGE_DATA_FROM_DISK, | 564 COULD_NOT_READ_IMAGE_DATA_FROM_DISK, |
| 562 l10n_util::GetStringFUTF8( | 565 l10n_util::GetStringFUTF16( |
| 563 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 566 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 564 ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK"))); | 567 ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK"))); |
| 565 return false; | 568 return false; |
| 566 } | 569 } |
| 567 | 570 |
| 568 // Delete any images that may be used by the browser. We're going to write | 571 // Delete any images that may be used by the browser. We're going to write |
| 569 // out our own versions of the parsed images, and we want to make sure the | 572 // out our own versions of the parsed images, and we want to make sure the |
| 570 // originals are gone for good. | 573 // originals are gone for good. |
| 571 std::set<FilePath> image_paths = extension_->GetBrowserImages(); | 574 std::set<FilePath> image_paths = extension_->GetBrowserImages(); |
| 572 if (image_paths.size() != images.size()) { | 575 if (image_paths.size() != images.size()) { |
| 573 // Decoded images don't match what's in the manifest. | 576 // Decoded images don't match what's in the manifest. |
| 574 ReportFailure( | 577 ReportFailure( |
| 575 DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST, | 578 DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST, |
| 576 l10n_util::GetStringFUTF8( | 579 l10n_util::GetStringFUTF16( |
| 577 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 580 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 578 ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST"))); | 581 ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST"))); |
| 579 return false; | 582 return false; |
| 580 } | 583 } |
| 581 | 584 |
| 582 for (std::set<FilePath>::iterator it = image_paths.begin(); | 585 for (std::set<FilePath>::iterator it = image_paths.begin(); |
| 583 it != image_paths.end(); ++it) { | 586 it != image_paths.end(); ++it) { |
| 584 FilePath path = *it; | 587 FilePath path = *it; |
| 585 if (path.IsAbsolute() || path.ReferencesParent()) { | 588 if (path.IsAbsolute() || path.ReferencesParent()) { |
| 586 // Invalid path for browser image. | 589 // Invalid path for browser image. |
| 587 ReportFailure( | 590 ReportFailure( |
| 588 INVALID_PATH_FOR_BROWSER_IMAGE, | 591 INVALID_PATH_FOR_BROWSER_IMAGE, |
| 589 l10n_util::GetStringFUTF8( | 592 l10n_util::GetStringFUTF16( |
| 590 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 593 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 591 ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); | 594 ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); |
| 592 return false; | 595 return false; |
| 593 } | 596 } |
| 594 if (!file_util::Delete(extension_root_.Append(path), false)) { | 597 if (!file_util::Delete(extension_root_.Append(path), false)) { |
| 595 // Error removing old image file. | 598 // Error removing old image file. |
| 596 ReportFailure( | 599 ReportFailure( |
| 597 ERROR_REMOVING_OLD_IMAGE_FILE, | 600 ERROR_REMOVING_OLD_IMAGE_FILE, |
| 598 l10n_util::GetStringFUTF8( | 601 l10n_util::GetStringFUTF16( |
| 599 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 602 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 600 ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE"))); | 603 ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE"))); |
| 601 return false; | 604 return false; |
| 602 } | 605 } |
| 603 } | 606 } |
| 604 | 607 |
| 605 // Write our parsed images back to disk as well. | 608 // Write our parsed images back to disk as well. |
| 606 for (size_t i = 0; i < images.size(); ++i) { | 609 for (size_t i = 0; i < images.size(); ++i) { |
| 607 const SkBitmap& image = images[i].a; | 610 const SkBitmap& image = images[i].a; |
| 608 FilePath path_suffix = images[i].b; | 611 FilePath path_suffix = images[i].b; |
| 609 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { | 612 if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { |
| 610 // Invalid path for bitmap image. | 613 // Invalid path for bitmap image. |
| 611 ReportFailure( | 614 ReportFailure( |
| 612 INVALID_PATH_FOR_BITMAP_IMAGE, | 615 INVALID_PATH_FOR_BITMAP_IMAGE, |
| 613 l10n_util::GetStringFUTF8( | 616 l10n_util::GetStringFUTF16( |
| 614 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 617 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 615 ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"))); | 618 ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"))); |
| 616 return false; | 619 return false; |
| 617 } | 620 } |
| 618 FilePath path = extension_root_.Append(path_suffix); | 621 FilePath path = extension_root_.Append(path_suffix); |
| 619 | 622 |
| 620 std::vector<unsigned char> image_data; | 623 std::vector<unsigned char> image_data; |
| 621 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even | 624 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even |
| 622 // though they may originally be .jpg, etc. Figure something out. | 625 // though they may originally be .jpg, etc. Figure something out. |
| 623 // http://code.google.com/p/chromium/issues/detail?id=12459 | 626 // http://code.google.com/p/chromium/issues/detail?id=12459 |
| 624 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { | 627 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { |
| 625 // Error re-encoding theme image. | 628 // Error re-encoding theme image. |
| 626 ReportFailure( | 629 ReportFailure( |
| 627 ERROR_RE_ENCODING_THEME_IMAGE, | 630 ERROR_RE_ENCODING_THEME_IMAGE, |
| 628 l10n_util::GetStringFUTF8( | 631 l10n_util::GetStringFUTF16( |
| 629 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 632 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 630 ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE"))); | 633 ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE"))); |
| 631 return false; | 634 return false; |
| 632 } | 635 } |
| 633 | 636 |
| 634 // Note: we're overwriting existing files that the utility process wrote, | 637 // Note: we're overwriting existing files that the utility process wrote, |
| 635 // so we can be sure the directory exists. | 638 // so we can be sure the directory exists. |
| 636 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); | 639 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); |
| 637 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { | 640 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { |
| 638 // Error saving theme image. | 641 // Error saving theme image. |
| 639 ReportFailure( | 642 ReportFailure( |
| 640 ERROR_SAVING_THEME_IMAGE, | 643 ERROR_SAVING_THEME_IMAGE, |
| 641 l10n_util::GetStringFUTF8( | 644 l10n_util::GetStringFUTF16( |
| 642 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 645 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 643 ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE"))); | 646 ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE"))); |
| 644 return false; | 647 return false; |
| 645 } | 648 } |
| 646 } | 649 } |
| 647 | 650 |
| 648 return true; | 651 return true; |
| 649 } | 652 } |
| 650 | 653 |
| 651 bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { | 654 bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { |
| 652 DictionaryValue catalogs; | 655 DictionaryValue catalogs; |
| 653 if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(), | 656 if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(), |
| 654 &catalogs)) { | 657 &catalogs)) { |
| 655 // Could not read catalog data from disk. | 658 // Could not read catalog data from disk. |
| 656 ReportFailure( | 659 ReportFailure( |
| 657 COULD_NOT_READ_CATALOG_DATA_FROM_DISK, | 660 COULD_NOT_READ_CATALOG_DATA_FROM_DISK, |
| 658 l10n_util::GetStringFUTF8( | 661 l10n_util::GetStringFUTF16( |
| 659 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 662 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 660 ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK"))); | 663 ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK"))); |
| 661 return false; | 664 return false; |
| 662 } | 665 } |
| 663 | 666 |
| 664 // Write our parsed catalogs back to disk. | 667 // Write our parsed catalogs back to disk. |
| 665 for (DictionaryValue::key_iterator key_it = catalogs.begin_keys(); | 668 for (DictionaryValue::key_iterator key_it = catalogs.begin_keys(); |
| 666 key_it != catalogs.end_keys(); ++key_it) { | 669 key_it != catalogs.end_keys(); ++key_it) { |
| 667 DictionaryValue* catalog; | 670 DictionaryValue* catalog; |
| 668 if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) { | 671 if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) { |
| 669 // Invalid catalog data. | 672 // Invalid catalog data. |
| 670 ReportFailure( | 673 ReportFailure( |
| 671 INVALID_CATALOG_DATA, | 674 INVALID_CATALOG_DATA, |
| 672 l10n_util::GetStringFUTF8( | 675 l10n_util::GetStringFUTF16( |
| 673 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 676 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 674 ASCIIToUTF16("INVALID_CATALOG_DATA"))); | 677 ASCIIToUTF16("INVALID_CATALOG_DATA"))); |
| 675 return false; | 678 return false; |
| 676 } | 679 } |
| 677 | 680 |
| 678 // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())| | 681 // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())| |
| 679 // hack and remove the corresponding #include. | 682 // hack and remove the corresponding #include. |
| 680 FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it)); | 683 FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it)); |
| 681 relative_path = relative_path.Append(Extension::kMessagesFilename); | 684 relative_path = relative_path.Append(Extension::kMessagesFilename); |
| 682 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { | 685 if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { |
| 683 // Invalid path for catalog. | 686 // Invalid path for catalog. |
| 684 ReportFailure( | 687 ReportFailure( |
| 685 INVALID_PATH_FOR_CATALOG, | 688 INVALID_PATH_FOR_CATALOG, |
| 686 l10n_util::GetStringFUTF8( | 689 l10n_util::GetStringFUTF16( |
| 687 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 690 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 688 ASCIIToUTF16("INVALID_PATH_FOR_CATALOG"))); | 691 ASCIIToUTF16("INVALID_PATH_FOR_CATALOG"))); |
| 689 return false; | 692 return false; |
| 690 } | 693 } |
| 691 FilePath path = extension_root_.Append(relative_path); | 694 FilePath path = extension_root_.Append(relative_path); |
| 692 | 695 |
| 693 std::string catalog_json; | 696 std::string catalog_json; |
| 694 JSONStringValueSerializer serializer(&catalog_json); | 697 JSONStringValueSerializer serializer(&catalog_json); |
| 695 serializer.set_pretty_print(true); | 698 serializer.set_pretty_print(true); |
| 696 if (!serializer.Serialize(*catalog)) { | 699 if (!serializer.Serialize(*catalog)) { |
| 697 // Error serializing catalog. | 700 // Error serializing catalog. |
| 698 ReportFailure( | 701 ReportFailure( |
| 699 ERROR_SERIALIZING_CATALOG, | 702 ERROR_SERIALIZING_CATALOG, |
| 700 l10n_util::GetStringFUTF8( | 703 l10n_util::GetStringFUTF16( |
| 701 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 704 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 702 ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"))); | 705 ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"))); |
| 703 return false; | 706 return false; |
| 704 } | 707 } |
| 705 | 708 |
| 706 // Note: we're overwriting existing files that the utility process read, | 709 // Note: we're overwriting existing files that the utility process read, |
| 707 // so we can be sure the directory exists. | 710 // so we can be sure the directory exists. |
| 708 if (!file_util::WriteFile(path, | 711 if (!file_util::WriteFile(path, |
| 709 catalog_json.c_str(), | 712 catalog_json.c_str(), |
| 710 catalog_json.size())) { | 713 catalog_json.size())) { |
| 711 // Error saving catalog. | 714 // Error saving catalog. |
| 712 ReportFailure( | 715 ReportFailure( |
| 713 ERROR_SAVING_CATALOG, | 716 ERROR_SAVING_CATALOG, |
| 714 l10n_util::GetStringFUTF8( | 717 l10n_util::GetStringFUTF16( |
| 715 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, | 718 IDS_EXTENSION_PACKAGE_INSTALL_ERROR, |
| 716 ASCIIToUTF16("ERROR_SAVING_CATALOG"))); | 719 ASCIIToUTF16("ERROR_SAVING_CATALOG"))); |
| 717 return false; | 720 return false; |
| 718 } | 721 } |
| 719 } | 722 } |
| 720 | 723 |
| 721 return true; | 724 return true; |
| 722 } | 725 } |
| OLD | NEW |