| 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 if (original_manifest) |
| 333 original_manifest_.reset(original_manifest->DeepCopy()); |
| 334 |
| 329 // We don't have to delete the unpack dir explicity since it is a child of | 335 // We don't have to delete the unpack dir explicity since it is a child of |
| 330 // the temp dir. | 336 // the temp dir. |
| 331 unpacked_extension_root_ = extension_dir; | 337 unpacked_extension_root_ = extension_dir; |
| 332 | 338 |
| 333 std::string error; | 339 std::string error; |
| 334 if (!AllowInstall(extension, &error)) { | 340 if (!AllowInstall(extension, &error)) { |
| 335 ReportFailureFromFileThread(error); | 341 ReportFailureFromFileThread(error); |
| 336 return; | 342 return; |
| 337 } | 343 } |
| 338 | 344 |
| 339 if (client_) { | 345 if (client_) { |
| 340 Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE, | 346 Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE, |
| 341 &install_icon_); | 347 &install_icon_); |
| 342 } | 348 } |
| 343 | 349 |
| 344 if (!BrowserThread::PostTask( | 350 if (!BrowserThread::PostTask( |
| 345 BrowserThread::UI, FROM_HERE, | 351 BrowserThread::UI, FROM_HERE, |
| 346 NewRunnableMethod(this, &CrxInstaller::ConfirmInstall))) | 352 NewRunnableMethod(this, &CrxInstaller::ConfirmInstall))) |
| 347 NOTREACHED(); | 353 NOTREACHED(); |
| 348 } | 354 } |
| 349 | 355 |
| 350 // Helper method to let us compare a whitelisted manifest with the actual | |
| 351 // downloaded extension's manifest, but ignoring the kPublicKey since the | |
| 352 // whitelisted manifest doesn't have that value. | |
| 353 static bool EqualsIgnoringPublicKey( | |
| 354 const DictionaryValue& extension_manifest, | |
| 355 const DictionaryValue& whitelisted_manifest) { | |
| 356 scoped_ptr<DictionaryValue> manifest_copy(extension_manifest.DeepCopy()); | |
| 357 manifest_copy->Remove(extension_manifest_keys::kPublicKey, NULL); | |
| 358 return manifest_copy->Equals(&whitelisted_manifest); | |
| 359 } | |
| 360 | |
| 361 void CrxInstaller::ConfirmInstall() { | 356 void CrxInstaller::ConfirmInstall() { |
| 362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 363 if (!frontend_weak_.get()) | 358 if (!frontend_weak_.get()) |
| 364 return; | 359 return; |
| 365 | 360 |
| 366 if (frontend_weak_->extension_prefs() | 361 if (frontend_weak_->extension_prefs() |
| 367 ->IsExtensionBlacklisted(extension_->id())) { | 362 ->IsExtensionBlacklisted(extension_->id())) { |
| 368 VLOG(1) << "This extension: " << extension_->id() | 363 VLOG(1) << "This extension: " << extension_->id() |
| 369 << " is blacklisted. Install failed."; | 364 << " is blacklisted. Install failed."; |
| 370 ReportFailureFromUIThread( | 365 ReportFailureFromUIThread( |
| (...skipping 20 matching lines...) Expand all Loading... |
| 391 return; | 386 return; |
| 392 } | 387 } |
| 393 | 388 |
| 394 current_version_ = | 389 current_version_ = |
| 395 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); | 390 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); |
| 396 | 391 |
| 397 // First see if it's whitelisted by id (the old mechanism). | 392 // First see if it's whitelisted by id (the old mechanism). |
| 398 bool whitelisted = ClearWhitelistedInstallId(extension_->id()) && | 393 bool whitelisted = ClearWhitelistedInstallId(extension_->id()) && |
| 399 extension_->plugins().empty() && is_gallery_install_; | 394 extension_->plugins().empty() && is_gallery_install_; |
| 400 | 395 |
| 401 // Now check if it's whitelisted by manifest. | 396 // Now check if there's a WhitelistEntry. |
| 402 scoped_ptr<DictionaryValue> whitelisted_manifest( | 397 scoped_ptr<CrxInstaller::WhitelistEntry> entry( |
| 403 RemoveWhitelistedManifest(extension_->id())); | 398 RemoveWhitelistEntry(extension_->id())); |
| 404 if (is_gallery_install_ && whitelisted_manifest.get()) { | 399 if (is_gallery_install_ && entry.get() && original_manifest_.get()) { |
| 405 if (!EqualsIgnoringPublicKey(*extension_->manifest_value(), | 400 if (!(original_manifest_->Equals(entry->parsed_manifest.get()))) { |
| 406 *whitelisted_manifest)) { | |
| 407 ReportFailureFromUIThread( | 401 ReportFailureFromUIThread( |
| 408 l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID)); | 402 l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID)); |
| 409 return; | 403 return; |
| 410 } | 404 } |
| 411 whitelisted = true; | 405 whitelisted = true; |
| 412 } | 406 } |
| 413 | 407 |
| 414 if (client_ && | 408 if (client_ && |
| 415 (!allow_silent_install_ || !whitelisted)) { | 409 (!allow_silent_install_ || !whitelisted)) { |
| 416 AddRef(); // Balanced in Proceed() and Abort(). | 410 AddRef(); // Balanced in Proceed() and Abort(). |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 563 // Some users (such as the download shelf) need to know when a | 557 // Some users (such as the download shelf) need to know when a |
| 564 // CRXInstaller is done. Listening for the EXTENSION_* events | 558 // CRXInstaller is done. Listening for the EXTENSION_* events |
| 565 // is problematic because they don't know anything about the | 559 // is problematic because they don't know anything about the |
| 566 // extension before it is unpacked, so they can not filter based | 560 // extension before it is unpacked, so they can not filter based |
| 567 // on the extension. | 561 // on the extension. |
| 568 NotificationService::current()->Notify( | 562 NotificationService::current()->Notify( |
| 569 NotificationType::CRX_INSTALLER_DONE, | 563 NotificationType::CRX_INSTALLER_DONE, |
| 570 Source<CrxInstaller>(this), | 564 Source<CrxInstaller>(this), |
| 571 NotificationService::NoDetails()); | 565 NotificationService::NoDetails()); |
| 572 } | 566 } |
| OLD | NEW |