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 |