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 |