Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Side by Side Diff: chrome/browser/extensions/extensions_service.cc

Issue 115595: Have the browser process rewrite manifest.json and theme images that the... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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/extensions_service.h" 5 #include "chrome/browser/extensions/extensions_service.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/gfx/png_encoder.h"
8 #include "base/scoped_handle.h" 9 #include "base/scoped_handle.h"
9 #include "base/scoped_temp_dir.h" 10 #include "base/scoped_temp_dir.h"
10 #include "base/string_util.h" 11 #include "base/string_util.h"
11 #include "base/third_party/nss/blapi.h" 12 #include "base/third_party/nss/blapi.h"
12 #include "base/third_party/nss/sha256.h" 13 #include "base/third_party/nss/sha256.h"
13 #include "base/thread.h" 14 #include "base/thread.h"
14 #include "base/values.h" 15 #include "base/values.h"
15 #include "net/base/file_stream.h" 16 #include "net/base/file_stream.h"
16 #include "chrome/browser/browser.h" 17 #include "chrome/browser/browser.h"
17 #include "chrome/browser/browser_list.h" 18 #include "chrome/browser/browser_list.h"
18 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chrome_thread.h" 20 #include "chrome/browser/chrome_thread.h"
20 #include "chrome/browser/extensions/extension.h" 21 #include "chrome/browser/extensions/extension.h"
21 #include "chrome/browser/extensions/extension_browser_event_router.h" 22 #include "chrome/browser/extensions/extension_browser_event_router.h"
22 #include "chrome/browser/extensions/extension_error_reporter.h" 23 #include "chrome/browser/extensions/extension_error_reporter.h"
23 #include "chrome/browser/extensions/extension_process_manager.h" 24 #include "chrome/browser/extensions/extension_process_manager.h"
24 #include "chrome/browser/profile.h" 25 #include "chrome/browser/profile.h"
25 #include "chrome/browser/utility_process_host.h" 26 #include "chrome/browser/utility_process_host.h"
26 #include "chrome/common/extensions/extension_unpacker.h" 27 #include "chrome/common/extensions/extension_unpacker.h"
27 #include "chrome/common/json_value_serializer.h" 28 #include "chrome/common/json_value_serializer.h"
28 #include "chrome/common/notification_service.h" 29 #include "chrome/common/notification_service.h"
29 #include "chrome/common/pref_service.h" 30 #include "chrome/common/pref_service.h"
30 #include "chrome/common/unzip.h" 31 #include "chrome/common/unzip.h"
31 #include "chrome/common/url_constants.h" 32 #include "chrome/common/url_constants.h"
33 #include "third_party/skia/include/core/SkBitmap.h"
32 34
33 #if defined(OS_WIN) 35 #if defined(OS_WIN)
34 #include "base/registry.h" 36 #include "base/registry.h"
35 #endif 37 #endif
36 38
37 // ExtensionsService 39 // ExtensionsService
38 40
39 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; 41 const char* ExtensionsService::kInstallDirectoryName = "Extensions";
40 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; 42 const char* ExtensionsService::kCurrentVersionFileName = "Current Version";
41 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL"; 43 const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL";
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 124
123 if (backend_->resource_dispatcher_host_) { 125 if (backend_->resource_dispatcher_host_) {
124 ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE, 126 ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE,
125 NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread, 127 NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread,
126 backend_->resource_dispatcher_host_, 128 backend_->resource_dispatcher_host_,
127 MessageLoop::current())); 129 MessageLoop::current()));
128 } else { 130 } else {
129 // Cheesy... but if we don't have a ResourceDispatcherHost, assume we're 131 // Cheesy... but if we don't have a ResourceDispatcherHost, assume we're
130 // in a unit test and run the unpacker directly in-process. 132 // in a unit test and run the unpacker directly in-process.
131 ExtensionUnpacker unpacker(temp_extension_path_); 133 ExtensionUnpacker unpacker(temp_extension_path_);
132 bool success = unpacker.Run(); 134 if (unpacker.Run()) {
133 OnUnpackExtensionReply(success, unpacker.error_message()); 135 OnUnpackExtensionSucceeded(*unpacker.parsed_manifest(),
136 unpacker.decoded_images());
137 } else {
138 OnUnpackExtensionFailed(unpacker.error_message());
139 }
134 } 140 }
135 } 141 }
136 142
137 private: 143 private:
138 // UtilityProcessHost::Client 144 // UtilityProcessHost::Client
139 virtual void OnProcessCrashed() { 145 virtual void OnProcessCrashed() {
140 OnUnpackExtensionReply(false, "Chrome crashed while trying to install"); 146 OnUnpackExtensionFailed("Chrome crashed while trying to install");
141 } 147 }
142 148
143 virtual void OnUnpackExtensionReply(bool success, 149 virtual void OnUnpackExtensionSucceeded(
144 const std::string& error_message) { 150 const DictionaryValue& manifest,
145 if (success) { 151 const std::vector< Tuple2<SkBitmap, FilePath> >& images) {
146 // The extension was unpacked to the temp dir inside our unpacking dir. 152 // The extension was unpacked to the temp dir inside our unpacking dir.
147 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII( 153 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII(
148 ExtensionsServiceBackend::kTempExtensionName); 154 ExtensionsServiceBackend::kTempExtensionName);
149 backend_->OnExtensionUnpacked(extension_path_, extension_dir, 155 backend_->OnExtensionUnpacked(extension_path_, extension_dir,
150 expected_id_, from_external_); 156 expected_id_, from_external_,
151 } else { 157 manifest, images);
152 backend_->ReportExtensionInstallError(extension_path_, error_message);
153 }
154 Cleanup(); 158 Cleanup();
155 Release(); // balanced in Run() 159 }
160
161 virtual void OnUnpackExtensionFailed(const std::string& error_message) {
162 backend_->ReportExtensionInstallError(extension_path_, error_message);
163 Cleanup();
156 } 164 }
157 165
158 // Cleans up our temp directory. 166 // Cleans up our temp directory.
159 void Cleanup() { 167 void Cleanup() {
160 file_util::Delete(temp_extension_path_.DirName(), true); 168 file_util::Delete(temp_extension_path_.DirName(), true);
169 Release(); // balanced in Run()
161 } 170 }
162 171
163 // Starts the utility process that unpacks our extension. 172 // Starts the utility process that unpacks our extension.
164 void StartProcessOnIOThread(ResourceDispatcherHost* rdh, 173 void StartProcessOnIOThread(ResourceDispatcherHost* rdh,
165 MessageLoop* file_loop) { 174 MessageLoop* file_loop) {
166 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop); 175 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop);
167 host->StartExtensionUnpacker(temp_extension_path_); 176 host->StartExtensionUnpacker(temp_extension_path_);
168 } 177 }
169 178
170 scoped_refptr<ExtensionsServiceBackend> backend_; 179 scoped_refptr<ExtensionsServiceBackend> backend_;
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 bool from_external) { 814 bool from_external) {
806 UnpackerClient* client = 815 UnpackerClient* client =
807 new UnpackerClient(this, extension_path, expected_id, from_external); 816 new UnpackerClient(this, extension_path, expected_id, from_external);
808 client->Start(); 817 client->Start();
809 } 818 }
810 819
811 void ExtensionsServiceBackend::OnExtensionUnpacked( 820 void ExtensionsServiceBackend::OnExtensionUnpacked(
812 const FilePath& extension_path, 821 const FilePath& extension_path,
813 const FilePath& temp_extension_dir, 822 const FilePath& temp_extension_dir,
814 const std::string expected_id, 823 const std::string expected_id,
815 bool from_external) { 824 bool from_external,
816 // TODO(mpcomplete): the utility process should pass up a parsed manifest that 825 const DictionaryValue& manifest,
817 // we rewrite in the browser. 826 const std::vector< Tuple2<SkBitmap, FilePath> >& images) {
818 // Bug http://code.google.com/p/chromium/issues/detail?id=11680
819 scoped_ptr<DictionaryValue> manifest(ReadManifest(extension_path));
820 if (!manifest.get()) {
821 // ReadManifest has already reported the extension error.
822 return;
823 }
824
825 Extension extension; 827 Extension extension;
826 std::string error; 828 std::string error;
827 if (!extension.InitFromValue(*manifest, 829 if (!extension.InitFromValue(manifest,
828 true, // require ID 830 true, // require ID
829 &error)) { 831 &error)) {
830 ReportExtensionInstallError(extension_path, "Invalid extension manifest."); 832 ReportExtensionInstallError(extension_path, "Invalid extension manifest.");
831 return; 833 return;
832 } 834 }
833 835
834 // If an expected id was provided, make sure it matches. 836 // If an expected id was provided, make sure it matches.
835 if (!expected_id.empty() && expected_id != extension.id()) { 837 if (!expected_id.empty() && expected_id != extension.id()) {
836 ReportExtensionInstallError(extension_path, 838 ReportExtensionInstallError(extension_path,
837 "ID in new extension manifest does not match expected ID."); 839 "ID in new extension manifest does not match expected ID.");
838 return; 840 return;
839 } 841 }
840 842
841 // <profile>/Extensions/<id> 843 // <profile>/Extensions/<id>
842 FilePath dest_dir = install_directory_.AppendASCII(extension.id()); 844 FilePath dest_dir = install_directory_.AppendASCII(extension.id());
843 std::string version = extension.VersionString(); 845 std::string version = extension.VersionString();
844 std::string current_version; 846 std::string current_version;
845 bool was_update = false; 847 bool was_update = false;
846 if (ReadCurrentVersion(dest_dir, &current_version)) { 848 if (ReadCurrentVersion(dest_dir, &current_version)) {
847 if (!CheckCurrentVersion(version, current_version, dest_dir)) 849 if (!CheckCurrentVersion(version, current_version, dest_dir))
848 return; 850 return;
849 was_update = true; 851 was_update = true;
850 } 852 }
851 853
854 // Write our parsed manifest back to disk, to ensure it doesn't contain an
855 // exploitable bug that can be used to compromise the browser.
856 std::string manifest_json;
857 JSONStringValueSerializer serializer(&manifest_json);
858 serializer.set_pretty_print(true);
859 if (!serializer.Serialize(manifest)) {
860 ReportExtensionInstallError(extension_path,
861 "Error serializing manifest.json.");
862 return;
863 }
864
865 FilePath manifest_path =
866 temp_extension_dir.AppendASCII(Extension::kManifestFilename);
867 if (!file_util::WriteFile(manifest_path,
868 manifest_json.data(), manifest_json.size())) {
869 ReportExtensionInstallError(extension_path, "Error saving manifest.json.");
870 return;
871 }
872
873 // Write our parsed images back to disk as well.
874 for (size_t i = 0; i < images.size(); ++i) {
875 const SkBitmap& image = images[i].a;
876 FilePath path = temp_extension_dir.Append(images[i].b);
877
878 std::vector<unsigned char> image_data;
879 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even
880 // though they may originally be .jpg, etc. Figure something out.
881 // http://code.google.com/p/chromium/issues/detail?id=12459
882 if (!PNGEncoder::EncodeBGRASkBitmap(image, false, &image_data)) {
883 ReportExtensionInstallError(extension_path,
884 "Error re-encoding theme image.");
885 return;
886 }
887
888 // Note: we're overwriting existing files that the utility process wrote,
889 // so we can be sure the directory exists.
890 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]);
891 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) {
892 ReportExtensionInstallError(extension_path, "Error saving theme image.");
893 return;
894 }
895 }
896
852 // <profile>/Extensions/<dir_name>/<version> 897 // <profile>/Extensions/<dir_name>/<version>
853 FilePath version_dir = dest_dir.AppendASCII(version); 898 FilePath version_dir = dest_dir.AppendASCII(version);
899
900 // If anything fails after this, we want to delete the extension dir.
901 ScopedTempDir scoped_version_dir;
902 scoped_version_dir.Set(version_dir);
903
854 if (!InstallDirSafely(temp_extension_dir, version_dir)) 904 if (!InstallDirSafely(temp_extension_dir, version_dir))
855 return; 905 return;
856 906
857 if (!SetCurrentVersion(dest_dir, version)) { 907 if (!SetCurrentVersion(dest_dir, version))
858 if (!file_util::Delete(version_dir, true))
859 LOG(WARNING) << "Can't remove " << dest_dir.value();
860 return; 908 return;
861 }
862 909
863 // To mark that this extension was installed from an external source, create a 910 // To mark that this extension was installed from an external source, create a
864 // zero-length file. At load time, this is used to indicate that the 911 // zero-length file. At load time, this is used to indicate that the
865 // extension should be uninstalled. 912 // extension should be uninstalled.
866 // TODO(erikkay): move this into per-extension config storage when it appears. 913 // TODO(erikkay): move this into per-extension config storage when it appears.
867 if (from_external) { 914 if (from_external) {
868 FilePath marker = version_dir.AppendASCII(kExternalInstallFile); 915 FilePath marker = version_dir.AppendASCII(kExternalInstallFile);
869 file_util::WriteFile(marker, NULL, 0); 916 file_util::WriteFile(marker, NULL, 0);
870 } 917 }
871 918
872 // Load the extension immediately and then report installation success. We 919 // Load the extension immediately and then report installation success. We
873 // don't load extensions for external installs because external installation 920 // don't load extensions for external installs because external installation
874 // occurs before the normal startup so we just let startup pick them up. We 921 // occurs before the normal startup so we just let startup pick them up. We
875 // don't notify installation because there is no UI or external install so 922 // don't notify installation because there is no UI for external install so
876 // there is nobody to notify. 923 // there is nobody to notify.
877 if (!from_external) { 924 if (!from_external) {
878 Extension* extension = LoadExtension(version_dir, true); // require id 925 Extension* extension = LoadExtension(version_dir, true); // require id
879 CHECK(extension); 926 CHECK(extension);
880 927
881 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( 928 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
882 frontend_, &ExtensionsService::OnExtensionInstalled, extension, 929 frontend_, &ExtensionsService::OnExtensionInstalled, extension,
883 was_update)); 930 was_update));
884 931
885 // Only one extension, but ReportExtensionsLoaded can handle multiple, 932 // Only one extension, but ReportExtensionsLoaded can handle multiple,
886 // so we need to construct a list. 933 // so we need to construct a list.
887 scoped_ptr<ExtensionList> extensions(new ExtensionList); 934 scoped_ptr<ExtensionList> extensions(new ExtensionList);
888 extensions->push_back(extension); 935 extensions->push_back(extension);
889 LOG(INFO) << "Done."; 936 LOG(INFO) << "Done.";
890 // Hand off ownership of the loaded extensions to the frontend. 937 // Hand off ownership of the loaded extensions to the frontend.
891 ReportExtensionsLoaded(extensions.release()); 938 ReportExtensionsLoaded(extensions.release());
892 } 939 }
940
941 scoped_version_dir.Take();
893 } 942 }
894 943
895 void ExtensionsServiceBackend::ReportExtensionInstallError( 944 void ExtensionsServiceBackend::ReportExtensionInstallError(
896 const FilePath& extension_path, const std::string &error) { 945 const FilePath& extension_path, const std::string &error) {
897 946
898 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux. 947 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux.
899 std::string path_str = WideToASCII(extension_path.ToWStringHack()); 948 std::string path_str = WideToASCII(extension_path.ToWStringHack());
900 std::string message = 949 std::string message =
901 StringPrintf("Could not install extension from '%s'. %s", 950 StringPrintf("Could not install extension from '%s'. %s",
902 path_str.c_str(), error.c_str()); 951 path_str.c_str(), error.c_str());
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
1030 1079
1031 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id, 1080 bool ExtensionsServiceBackend::ShouldInstall(const std::string& id,
1032 const std::string& version) { 1081 const std::string& version) {
1033 FilePath dir(install_directory_.AppendASCII(id.c_str())); 1082 FilePath dir(install_directory_.AppendASCII(id.c_str()));
1034 std::string current_version; 1083 std::string current_version;
1035 if (ReadCurrentVersion(dir, &current_version)) { 1084 if (ReadCurrentVersion(dir, &current_version)) {
1036 return CheckCurrentVersion(version, current_version, dir); 1085 return CheckCurrentVersion(version, current_version, dir);
1037 } 1086 }
1038 return true; 1087 return true;
1039 } 1088 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extensions_service.h ('k') | chrome/browser/extensions/extensions_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698