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/crx_installer.h" | 5 #include "chrome/browser/extensions/crx_installer.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
(...skipping 23 matching lines...) Expand all Loading... | |
34 #include "content/common/notification_type.h" | 34 #include "content/common/notification_type.h" |
35 #include "grit/chromium_strings.h" | 35 #include "grit/chromium_strings.h" |
36 #include "grit/generated_resources.h" | 36 #include "grit/generated_resources.h" |
37 #include "grit/theme_resources.h" | 37 #include "grit/theme_resources.h" |
38 #include "third_party/skia/include/core/SkBitmap.h" | 38 #include "third_party/skia/include/core/SkBitmap.h" |
39 #include "ui/base/l10n/l10n_util.h" | 39 #include "ui/base/l10n/l10n_util.h" |
40 #include "ui/base/resource/resource_bundle.h" | 40 #include "ui/base/resource/resource_bundle.h" |
41 | 41 |
42 namespace { | 42 namespace { |
43 | 43 |
44 struct WhitelistedInstallData { | 44 struct Whitelist { |
45 WhitelistedInstallData() {} | 45 Whitelist() {} |
46 std::set<std::string> ids; | 46 std::set<std::string> ids; |
47 std::map<std::string, linked_ptr<DictionaryValue> > manifests; | 47 std::map<std::string, linked_ptr<CrxInstaller::WhitelistEntry> > entries; |
48 }; | 48 }; |
49 | 49 |
50 static base::LazyInstance<WhitelistedInstallData> | 50 static base::LazyInstance<Whitelist> |
51 g_whitelisted_install_data(base::LINKER_INITIALIZED); | 51 g_whitelisted_install_data(base::LINKER_INITIALIZED); |
52 | 52 |
53 } // namespace | 53 } // namespace |
54 | 54 |
55 // static | 55 // static |
56 void CrxInstaller::SetWhitelistedInstallId(const std::string& id) { | 56 void CrxInstaller::SetWhitelistedInstallId(const std::string& id) { |
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 57 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
58 g_whitelisted_install_data.Get().ids.insert(id); | 58 g_whitelisted_install_data.Get().ids.insert(id); |
59 } | 59 } |
60 | 60 |
61 // static | 61 // static |
62 void CrxInstaller::SetWhitelistedManifest(const std::string& id, | 62 void CrxInstaller::SetWhitelistEntry(const std::string& id, |
63 DictionaryValue* parsed_manifest) { | 63 CrxInstaller::WhitelistEntry* entry) { |
64 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 64 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
65 WhitelistedInstallData& data = g_whitelisted_install_data.Get(); | 65 Whitelist& data = g_whitelisted_install_data.Get(); |
66 data.manifests[id] = linked_ptr<DictionaryValue>(parsed_manifest); | 66 data.entries[id] = linked_ptr<CrxInstaller::WhitelistEntry>(entry); |
67 } | 67 } |
68 | 68 |
69 // static | 69 // static |
70 const DictionaryValue* CrxInstaller::GetWhitelistedManifest( | 70 const CrxInstaller::WhitelistEntry* CrxInstaller::GetWhitelistEntry( |
71 const std::string& id) { | 71 const std::string& id) { |
72 WhitelistedInstallData& data = g_whitelisted_install_data.Get(); | 72 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
73 if (ContainsKey(data.manifests, id)) | 73 Whitelist& data = g_whitelisted_install_data.Get(); |
74 return data.manifests[id].get(); | 74 if (ContainsKey(data.entries, id)) |
75 return data.entries[id].get(); | |
75 else | 76 else |
76 return NULL; | 77 return NULL; |
77 } | 78 } |
78 | 79 |
79 // static | 80 // static |
80 DictionaryValue* CrxInstaller::RemoveWhitelistedManifest( | 81 CrxInstaller::WhitelistEntry* CrxInstaller::RemoveWhitelistEntry( |
81 const std::string& id) { | 82 const std::string& id) { |
82 WhitelistedInstallData& data = g_whitelisted_install_data.Get(); | 83 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
83 if (ContainsKey(data.manifests, id)) { | 84 Whitelist& data = g_whitelisted_install_data.Get(); |
84 DictionaryValue* manifest = data.manifests[id].release(); | 85 if (ContainsKey(data.entries, id)) { |
85 data.manifests.erase(id); | 86 CrxInstaller::WhitelistEntry* entry = data.entries[id].release(); |
86 return manifest; | 87 data.entries.erase(id); |
88 return entry; | |
87 } | 89 } |
88 return NULL; | 90 return NULL; |
89 } | 91 } |
90 | 92 |
91 // static | 93 // static |
92 bool CrxInstaller::IsIdWhitelisted(const std::string& id) { | 94 bool CrxInstaller::IsIdWhitelisted(const std::string& id) { |
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 95 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
94 std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; | 96 std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; |
95 return ContainsKey(ids, id); | 97 return ContainsKey(ids, id); |
96 } | 98 } |
97 | 99 |
98 // static | 100 // static |
99 bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) { | 101 bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) { |
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 102 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
101 std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; | 103 std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; |
102 if (ContainsKey(ids, id)) { | 104 if (ContainsKey(ids, id)) { |
103 ids.erase(id); | 105 ids.erase(id); |
104 return true; | 106 return true; |
105 } | 107 } |
106 return false; | 108 return false; |
107 } | 109 } |
108 | 110 |
109 CrxInstaller::CrxInstaller(base::WeakPtr<ExtensionService> frontend_weak, | 111 CrxInstaller::CrxInstaller(base::WeakPtr<ExtensionService> frontend_weak, |
110 ExtensionInstallUI* client) | 112 ExtensionInstallUI* client) |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 | 180 |
179 void CrxInstaller::ConvertUserScriptOnFileThread() { | 181 void CrxInstaller::ConvertUserScriptOnFileThread() { |
180 std::string error; | 182 std::string error; |
181 scoped_refptr<Extension> extension = | 183 scoped_refptr<Extension> extension = |
182 ConvertUserScriptToExtension(source_file_, original_url_, &error); | 184 ConvertUserScriptToExtension(source_file_, original_url_, &error); |
183 if (!extension) { | 185 if (!extension) { |
184 ReportFailureFromFileThread(error); | 186 ReportFailureFromFileThread(error); |
185 return; | 187 return; |
186 } | 188 } |
187 | 189 |
188 OnUnpackSuccess(extension->path(), extension->path(), extension); | 190 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension); |
189 } | 191 } |
190 | 192 |
191 void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) { | 193 void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) { |
192 if (!BrowserThread::PostTask( | 194 if (!BrowserThread::PostTask( |
193 BrowserThread::FILE, FROM_HERE, | 195 BrowserThread::FILE, FROM_HERE, |
194 NewRunnableMethod(this, &CrxInstaller::ConvertWebAppOnFileThread, | 196 NewRunnableMethod(this, &CrxInstaller::ConvertWebAppOnFileThread, |
195 web_app))) | 197 web_app))) |
196 NOTREACHED(); | 198 NOTREACHED(); |
197 } | 199 } |
198 | 200 |
199 void CrxInstaller::ConvertWebAppOnFileThread( | 201 void CrxInstaller::ConvertWebAppOnFileThread( |
200 const WebApplicationInfo& web_app) { | 202 const WebApplicationInfo& web_app) { |
201 std::string error; | 203 std::string error; |
202 scoped_refptr<Extension> extension( | 204 scoped_refptr<Extension> extension( |
203 ConvertWebAppToExtension(web_app, base::Time::Now())); | 205 ConvertWebAppToExtension(web_app, base::Time::Now())); |
204 if (!extension) { | 206 if (!extension) { |
205 // Validation should have stopped any potential errors before getting here. | 207 // Validation should have stopped any potential errors before getting here. |
206 NOTREACHED() << "Could not convert web app to extension."; | 208 NOTREACHED() << "Could not convert web app to extension."; |
207 return; | 209 return; |
208 } | 210 } |
209 | 211 |
210 // TODO(aa): conversion data gets lost here :( | 212 // TODO(aa): conversion data gets lost here :( |
211 | 213 |
212 OnUnpackSuccess(extension->path(), extension->path(), extension); | 214 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension); |
213 } | 215 } |
214 | 216 |
215 bool CrxInstaller::AllowInstall(const Extension* extension, | 217 bool CrxInstaller::AllowInstall(const Extension* extension, |
216 std::string* error) { | 218 std::string* error) { |
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
218 DCHECK(error); | 220 DCHECK(error); |
219 | 221 |
220 // Make sure the expected id matches. | 222 // Make sure the expected id matches. |
221 if (!expected_id_.empty() && expected_id_ != extension->id()) { | 223 if (!expected_id_.empty() && expected_id_ != extension->id()) { |
222 *error = base::StringPrintf( | 224 *error = base::StringPrintf( |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
304 | 306 |
305 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallCause", | 307 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallCause", |
306 install_cause(), | 308 install_cause(), |
307 extension_misc::NUM_INSTALL_CAUSES); | 309 extension_misc::NUM_INSTALL_CAUSES); |
308 | 310 |
309 ReportFailureFromFileThread(error_message); | 311 ReportFailureFromFileThread(error_message); |
310 } | 312 } |
311 | 313 |
312 void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, | 314 void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, |
313 const FilePath& extension_dir, | 315 const FilePath& extension_dir, |
316 const DictionaryValue* original_manifest, | |
314 const Extension* extension) { | 317 const Extension* extension) { |
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
316 | 319 |
317 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", | 320 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", |
318 install_source(), Extension::NUM_LOCATIONS); | 321 install_source(), Extension::NUM_LOCATIONS); |
319 | 322 |
320 | 323 |
321 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", | 324 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", |
322 install_cause(), | 325 install_cause(), |
323 extension_misc::NUM_INSTALL_CAUSES); | 326 extension_misc::NUM_INSTALL_CAUSES); |
324 | 327 |
325 // Note: We take ownership of |extension| and |temp_dir|. | 328 // Note: We take ownership of |extension| and |temp_dir|. |
326 extension_ = extension; | 329 extension_ = extension; |
327 temp_dir_ = temp_dir; | 330 temp_dir_ = temp_dir; |
328 | 331 |
332 original_manifest_.reset(original_manifest->DeepCopy()); | |
333 | |
329 // We don't have to delete the unpack dir explicity since it is a child of | 334 // We don't have to delete the unpack dir explicity since it is a child of |
330 // the temp dir. | 335 // the temp dir. |
331 unpacked_extension_root_ = extension_dir; | 336 unpacked_extension_root_ = extension_dir; |
332 | 337 |
333 std::string error; | 338 std::string error; |
334 if (!AllowInstall(extension, &error)) { | 339 if (!AllowInstall(extension, &error)) { |
335 ReportFailureFromFileThread(error); | 340 ReportFailureFromFileThread(error); |
336 return; | 341 return; |
337 } | 342 } |
338 | 343 |
339 if (client_) { | 344 if (client_) { |
340 Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE, | 345 Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE, |
341 &install_icon_); | 346 &install_icon_); |
342 } | 347 } |
343 | 348 |
344 if (!BrowserThread::PostTask( | 349 if (!BrowserThread::PostTask( |
345 BrowserThread::UI, FROM_HERE, | 350 BrowserThread::UI, FROM_HERE, |
346 NewRunnableMethod(this, &CrxInstaller::ConfirmInstall))) | 351 NewRunnableMethod(this, &CrxInstaller::ConfirmInstall))) |
347 NOTREACHED(); | 352 NOTREACHED(); |
348 } | 353 } |
349 | 354 |
355 #if 0 | |
Matt Perry
2011/05/25 01:46:06
Remove dead code, unless you mean to use it. In th
asargent_no_longer_on_chrome
2011/05/25 04:42:00
Oops, I had meant to remove this whole block. Done
| |
350 // Helper method to let us compare a whitelisted manifest with the actual | 356 // Helper method to let us compare a whitelisted manifest with the actual |
351 // downloaded extension's manifest, but ignoring the kPublicKey since the | 357 // downloaded extension's manifest, but ignoring certain keys. |
352 // whitelisted manifest doesn't have that value. | 358 static bool WhitelistMatches( |
353 static bool EqualsIgnoringPublicKey( | |
354 const DictionaryValue& extension_manifest, | 359 const DictionaryValue& extension_manifest, |
355 const DictionaryValue& whitelisted_manifest) { | 360 const DictionaryValue& whitelisted_manifest) { |
356 scoped_ptr<DictionaryValue> manifest_copy(extension_manifest.DeepCopy()); | 361 scoped_ptr<DictionaryValue> manifest_copy(extension_manifest.DeepCopy()); |
357 manifest_copy->Remove(extension_manifest_keys::kPublicKey, NULL); | 362 manifest_copy->Remove(extension_manifest_keys::kPublicKey, NULL); |
358 return manifest_copy->Equals(&whitelisted_manifest); | 363 manifest_copy->Remove(extension_manifest_keys::kCurrentLocale, NULL); |
364 | |
365 for (DictionaryValue::key_iterator i = extension_manifest.begin_keys(); | |
366 i != extension_manifest.end_keys(); | |
367 ++i) { | |
368 const std::string& key = *i; | |
369 if (key == extension_manifest_keys::kPublicKey || | |
370 key == extension_manifest_keys::kCurrentLocale) | |
371 continue; | |
372 | |
373 Value* extension_value = NULL; | |
374 Value* whitelist_value = NULL; | |
375 | |
376 if (!extension_manifest.Get(key, &extension_value) || | |
377 !whitelisted_manifest.Get(key, &whitelist_value)) | |
378 return false; | |
379 | |
380 if (!extension_value->Equals(whitelist_value)) | |
381 return false; | |
382 } | |
383 return true; | |
359 } | 384 } |
385 #endif | |
360 | 386 |
361 void CrxInstaller::ConfirmInstall() { | 387 void CrxInstaller::ConfirmInstall() { |
362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
363 if (!frontend_weak_.get()) | 389 if (!frontend_weak_.get()) |
364 return; | 390 return; |
365 | 391 |
366 if (frontend_weak_->extension_prefs() | 392 if (frontend_weak_->extension_prefs() |
367 ->IsExtensionBlacklisted(extension_->id())) { | 393 ->IsExtensionBlacklisted(extension_->id())) { |
368 VLOG(1) << "This extension: " << extension_->id() | 394 VLOG(1) << "This extension: " << extension_->id() |
369 << " is blacklisted. Install failed."; | 395 << " is blacklisted. Install failed."; |
(...skipping 21 matching lines...) Expand all Loading... | |
391 return; | 417 return; |
392 } | 418 } |
393 | 419 |
394 current_version_ = | 420 current_version_ = |
395 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); | 421 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); |
396 | 422 |
397 // First see if it's whitelisted by id (the old mechanism). | 423 // First see if it's whitelisted by id (the old mechanism). |
398 bool whitelisted = ClearWhitelistedInstallId(extension_->id()) && | 424 bool whitelisted = ClearWhitelistedInstallId(extension_->id()) && |
399 extension_->plugins().empty() && is_gallery_install_; | 425 extension_->plugins().empty() && is_gallery_install_; |
400 | 426 |
401 // Now check if it's whitelisted by manifest. | 427 // Now check if there's a WhitelistEntry. |
402 scoped_ptr<DictionaryValue> whitelisted_manifest( | 428 scoped_ptr<CrxInstaller::WhitelistEntry> entry( |
403 RemoveWhitelistedManifest(extension_->id())); | 429 RemoveWhitelistEntry(extension_->id())); |
404 if (is_gallery_install_ && whitelisted_manifest.get()) { | 430 if (is_gallery_install_ && entry.get() && original_manifest_.get()) { |
405 if (!EqualsIgnoringPublicKey(*extension_->manifest_value(), | 431 if (!(original_manifest_->Equals(entry->parsed_manifest.get()))) { |
Matt Perry
2011/05/25 01:46:06
isn't the Extension::manifest_value supposed to be
asargent_no_longer_on_chrome
2011/05/25 04:42:00
The Extension::manifest_value has already had a co
Matt Perry
2011/05/25 19:03:24
Should we also check to ensure that the localized
| |
406 *whitelisted_manifest)) { | |
407 ReportFailureFromUIThread( | 432 ReportFailureFromUIThread( |
408 l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID)); | 433 l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID)); |
409 return; | 434 return; |
410 } | 435 } |
411 whitelisted = true; | 436 whitelisted = true; |
412 } | 437 } |
413 | 438 |
414 if (client_ && | 439 if (client_ && |
415 (!allow_silent_install_ || !whitelisted)) { | 440 (!allow_silent_install_ || !whitelisted)) { |
416 AddRef(); // Balanced in Proceed() and Abort(). | 441 AddRef(); // Balanced in Proceed() and Abort(). |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
547 client_->OnInstallSuccess(extension_.get(), install_icon_.get()); | 572 client_->OnInstallSuccess(extension_.get(), install_icon_.get()); |
548 | 573 |
549 // Tell the frontend about the installation and hand off ownership of | 574 // Tell the frontend about the installation and hand off ownership of |
550 // extension_ to it. | 575 // extension_ to it. |
551 frontend_weak_->OnExtensionInstalled(extension_); | 576 frontend_weak_->OnExtensionInstalled(extension_); |
552 extension_ = NULL; | 577 extension_ = NULL; |
553 | 578 |
554 // We're done. We don't post any more tasks to ourselves so we are deleted | 579 // We're done. We don't post any more tasks to ourselves so we are deleted |
555 // soon. | 580 // soon. |
556 } | 581 } |
OLD | NEW |